@stacksjs/ts-cloud 0.16.66 → 0.16.68
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-8bgfn8ek.js → chunk-17ewx21n.js} +11 -11
- package/dist/bin/chunk-19dhvnjh.js +1 -0
- package/dist/bin/{chunk-ya1413jw.js → chunk-1cb0r1j3.js} +2 -2
- package/dist/bin/chunk-1tk64amh.js +1 -0
- package/dist/bin/{chunk-tcn6qcc4.js → chunk-2247xk4n.js} +1 -1
- package/dist/bin/chunk-37xeqae4.js +1 -0
- package/dist/bin/{chunk-zesb85ra.js → chunk-43a60zkj.js} +1 -1
- package/dist/bin/chunk-4vz5erjz.js +1 -0
- package/dist/bin/{chunk-2avtspqd.js → chunk-55j0x82p.js} +5 -5
- package/dist/bin/{chunk-zs0q8sh5.js → chunk-5fde4d44.js} +1 -1
- package/dist/bin/{chunk-tw6z2mvh.js → chunk-5gf0je0v.js} +14 -14
- package/dist/bin/{chunk-0ejp168p.js → chunk-5t1ky9re.js} +1 -1
- package/dist/bin/chunk-6cyr6gcg.js +1 -0
- package/dist/bin/chunk-6rwewb7j.js +1 -0
- package/dist/bin/{chunk-d38cyam8.js → chunk-6tqzgm9z.js} +5 -5
- package/dist/bin/chunk-7d83f6sn.js +1 -0
- package/dist/bin/chunk-7v68hpgc.js +2 -0
- package/dist/bin/{chunk-nn8k84cd.js → chunk-7y56qyrj.js} +1 -1
- package/dist/bin/{chunk-e51cd46z.js → chunk-8escxm7h.js} +1 -1
- package/dist/bin/{chunk-6r04kx46.js → chunk-abk97qeq.js} +2 -2
- package/dist/bin/{chunk-qpvydcfm.js → chunk-b0r8a5h5.js} +5 -5
- package/dist/bin/chunk-bkvxzenb.js +1 -0
- package/dist/bin/{chunk-v6jm8dsa.js → chunk-d28q9ath.js} +1 -1
- package/dist/bin/chunk-dmm1p4bs.js +1 -0
- package/dist/bin/chunk-dycx66c7.js +1 -0
- package/dist/bin/{chunk-aekwpste.js → chunk-e4c7ba0g.js} +1 -1
- package/dist/bin/chunk-fjx816tt.js +1 -0
- package/dist/bin/{chunk-nbqja2ja.js → chunk-fx9zesgx.js} +113 -113
- package/dist/bin/{chunk-9pj5r0x0.js → chunk-gga18c4g.js} +1 -1
- package/dist/bin/chunk-gmy8p7nr.js +1 -0
- package/dist/bin/chunk-h5ccvped.js +1 -0
- package/dist/bin/chunk-h9h9dn0r.js +1 -0
- package/dist/bin/chunk-ht6s2cwm.js +1 -0
- package/dist/bin/{chunk-vbq4ten8.js → chunk-jrxb5sg4.js} +3 -3
- package/dist/bin/{chunk-cf2eyje1.js → chunk-krt80e8w.js} +7 -7
- package/dist/bin/{chunk-sbjzewvk.js → chunk-m60wwxz1.js} +6 -6
- package/dist/bin/{chunk-w4axqmyc.js → chunk-m92m9tx3.js} +84 -84
- package/dist/bin/{chunk-d0q93ecd.js → chunk-mjbd4pbz.js} +5 -5
- package/dist/bin/chunk-ncr1dwdt.js +1 -0
- package/dist/bin/{chunk-tpttr74v.js → chunk-nxsx69p4.js} +4 -4
- package/dist/bin/chunk-nzhpva7z.js +1 -0
- package/dist/bin/chunk-p40tvp17.js +1 -0
- package/dist/bin/{chunk-n667tnf3.js → chunk-pgbtdsj2.js} +3 -3
- package/dist/bin/{chunk-5ad4b744.js → chunk-pr96tp0s.js} +2 -2
- package/dist/bin/chunk-qe8zh9kn.js +1 -0
- package/dist/bin/{chunk-v5x06h8w.js → chunk-qjxd8f5m.js} +5 -5
- package/dist/bin/{chunk-favx96qj.js → chunk-qka0e661.js} +5 -5
- package/dist/bin/{chunk-pe18g092.js → chunk-rgnmxfvp.js} +3 -3
- package/dist/bin/chunk-sn1zde06.js +1 -0
- package/dist/bin/{chunk-71b4t3d8.js → chunk-sv7n9ape.js} +2 -2
- package/dist/bin/chunk-t6zpvaqr.js +1 -0
- package/dist/bin/{chunk-90ds3vw7.js → chunk-tdv5rwjv.js} +1 -1
- package/dist/bin/chunk-v4ncs6q2.js +1 -0
- package/dist/bin/{chunk-v3j9wgmn.js → chunk-v5js5pz6.js} +186 -186
- package/dist/bin/chunk-vrn0akcn.js +1 -0
- package/dist/bin/{chunk-mver6psb.js → chunk-w2eezm9z.js} +2 -2
- package/dist/bin/{chunk-6da5c33e.js → chunk-wjn2bpdb.js} +2 -2
- package/dist/bin/chunk-x00efaxm.js +1 -0
- package/dist/bin/{chunk-38qy0dj2.js → chunk-x40sd2m9.js} +3 -3
- package/dist/bin/chunk-zred4827.js +1 -0
- package/dist/bin/{chunk-tg3vzzc4.js → chunk-zs1cpqhv.js} +2 -2
- package/dist/bin/{chunk-kmxkwznm.js → chunk-zz9nj5kn.js} +5 -5
- package/dist/bin/cli.js +101 -101
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-y9589qef.js → chunk-040rbk7k.js} +35 -35
- package/dist/{chunk-f739f6d2.js → chunk-192rthtb.js} +70 -70
- package/dist/{chunk-9w5ncn9s.js → chunk-1wc2zfct.js} +3 -3
- package/dist/{chunk-axcxfz8p.js → chunk-1yj07hbw.js} +2 -2
- package/dist/{chunk-0kemzwpg.js → chunk-41fwhvp7.js} +1 -1
- package/dist/chunk-426k7fgf.js +1 -0
- package/dist/chunk-4b0ynr9y.js +1 -0
- package/dist/{chunk-a92gvctb.js → chunk-a07kew2q.js} +6 -6
- package/dist/chunk-emkp3dsp.js +1 -0
- package/dist/{chunk-pymc2aad.js → chunk-h360gwrf.js} +2 -2
- package/dist/{chunk-7mpbjr6c.js → chunk-h5yx54ks.js} +3 -3
- package/dist/{chunk-q4408fwg.js → chunk-hvttzk9q.js} +2 -2
- package/dist/{chunk-q8vvwmka.js → chunk-je8tky8z.js} +1 -1
- package/dist/{chunk-03eny26f.js → chunk-kbr9nc8y.js} +2 -2
- package/dist/{chunk-3ca6cb1s.js → chunk-p21vbrgk.js} +1 -1
- package/dist/chunk-pcagajw1.js +1 -0
- package/dist/{chunk-83fy36fn.js → chunk-qb25wesa.js} +2 -2
- package/dist/{chunk-hk1frmnn.js → chunk-qrpy0h2n.js} +1 -1
- package/dist/{chunk-xd67tr7p.js → chunk-s4wz0csj.js} +1 -1
- package/dist/{chunk-157bgr0x.js → chunk-spr6akra.js} +90 -90
- package/dist/chunk-sybwn2y6.js +1 -0
- package/dist/{chunk-r49ynkag.js → chunk-t8fbwcdk.js} +1 -1
- package/dist/{chunk-qgtydqpj.js → chunk-tb8azghz.js} +23 -23
- package/dist/{chunk-pah2r8a0.js → chunk-tq7nsdnd.js} +4 -4
- package/dist/{chunk-0860mm00.js → chunk-v0s8vpa3.js} +1 -1
- package/dist/{chunk-tngsyawj.js → chunk-xyem7g21.js} +1 -1
- package/dist/{chunk-zgfzc46r.js → chunk-yh9tmx00.js} +3 -3
- package/dist/{chunk-1t3rjvf9.js → chunk-z585dfjz.js} +12 -12
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/releases.d.ts +12 -0
- package/dist/index.js +8 -8
- package/dist/mail/index.js +2 -2
- package/dist/object-storage/index.d.ts +6 -4
- package/dist/object-storage/migrate.d.ts +3 -1
- 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 +5 -5
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +6 -6
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +6 -6
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +5 -5
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +5 -5
- 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 +5 -5
- 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 +5 -5
- package/dist/ui/server/team.html +5 -5
- package/dist/ui/server/terminal.html +1 -1
- package/dist/ui/serverless/alarms.html +5 -5
- package/dist/ui/serverless/assets.html +1 -1
- 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 +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +5 -5
- package/package.json +3 -3
- package/dist/bin/chunk-0v5tsfx5.js +0 -1
- package/dist/bin/chunk-3954zb9r.js +0 -1
- package/dist/bin/chunk-3x52axr2.js +0 -1
- package/dist/bin/chunk-67mww6gq.js +0 -1
- package/dist/bin/chunk-7khzyn7k.js +0 -1
- package/dist/bin/chunk-97494wnx.js +0 -1
- package/dist/bin/chunk-agmznzms.js +0 -1
- package/dist/bin/chunk-ambf5hpg.js +0 -1
- package/dist/bin/chunk-b39h9as6.js +0 -1
- package/dist/bin/chunk-dfgzav9j.js +0 -1
- package/dist/bin/chunk-g0w0jec3.js +0 -1
- package/dist/bin/chunk-g514nb80.js +0 -1
- package/dist/bin/chunk-hknz7fsr.js +0 -1
- package/dist/bin/chunk-j9yq3b4d.js +0 -2
- package/dist/bin/chunk-k8qrjnyg.js +0 -1
- package/dist/bin/chunk-kqstefmv.js +0 -1
- package/dist/bin/chunk-mk2h37pm.js +0 -1
- package/dist/bin/chunk-nrtjmzzn.js +0 -1
- package/dist/bin/chunk-q3rch5hc.js +0 -1
- package/dist/bin/chunk-qqb6h33k.js +0 -1
- package/dist/bin/chunk-r1p3k2tn.js +0 -1
- package/dist/bin/chunk-t8xq3v3j.js +0 -1
- package/dist/bin/chunk-xb48vxmk.js +0 -1
- package/dist/bin/chunk-yehb738r.js +0 -1
- package/dist/bin/chunk-ythfx8pv.js +0 -1
- package/dist/bin/chunk-zynfzzjk.js +0 -1
- package/dist/chunk-0c48hvb8.js +0 -1
- package/dist/chunk-8crqfe8x.js +0 -1
- package/dist/chunk-949tycxj.js +0 -1
- package/dist/chunk-s3pe89wj.js +0 -1
- package/dist/chunk-wxjd9gyb.js +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import{k,ra}from"./chunk-m2a60evh.js";import{hn,nt}from"./chunk-83fy36fn.js";var km={};hn(km,{default:()=>Rr,handler:()=>At});var Nm={};hn(Nm,{default:()=>Pr,handler:()=>Ct});var Cf={};hn(Cf,{EmailAnalyticsModule:()=>it,EmailRules:()=>Ut,EmailScheduling:()=>Wt,EmailSearch:()=>Gt,EmailTemplates:()=>ke,EmailThreading:()=>_t,SharedMailboxes:()=>Vt});var Ef={};hn(Ef,{default:()=>ki,handler:()=>xi});var vf={};hn(vf,{CallAnalytics:()=>jt,CallRecording:()=>Ht,Callbacks:()=>mt,IVRBuilder:()=>Be});var Tf={};hn(Tf,{AbTesting:()=>Ee,LinkTracking:()=>Jt,MmsSupport:()=>zt,SmsAnalytics:()=>qt,SmsCampaigns:()=>Kt,SmsChatbot:()=>Qt});var LI={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}},$I={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 bt,join as at,relative as sr}from"node:path";var rl=".ts-cloud",ym="TS_CLOUD_STATE_DIR",St=null;function nl(n){St=n?.trim()||null}function il(){return Boolean(process.env[ym]?.trim()||St)}function cn(){return process.env[ym]?.trim()||St||rl}function Q(...n){return at(cn(),...n)}function l(n,...i){let s=cn();return bt(s)?at(s,...i):at(n,s,...i)}function sl(n,i=process.cwd()){let s=(c,u)=>{let d=sr(c,u);return d===""||!d.startsWith("..")&&!bt(d)},o=bt(n)?n:at(i,n);return s(l(i),o)}function Sm(n){let i=n.infrastructure?.compute!=null,s=Object.values(n.environments??{}).some((o)=>o?.app!=null);return{server:i,serverless:s}}function K(n){if(n.mode==="server"||n.mode==="serverless")return n.mode;let{serverless:i}=Sm(n);return i?"serverless":"server"}function ol(n){let{server:i,serverless:s}=Sm(n);if(i&&s)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(n.mode==="server"&&s&&!i)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(n.mode==="serverless"&&i&&!s)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function g(n){return n.infrastructure?.appDatabase??n.infrastructure?.compute?.database}function or(n){return typeof n==="object"&&n!==null?n:{}}function ty(n){return n===!0||typeof n==="object"&&n!==null}function cr(n,i){let s=i?n.environments?.[i]:void 0;if(s?.domain)return s.domain;let o=Object.values(n.sites??{}),c=n.sites?.main?.domain??o.find((u)=>u.domain)?.domain;if(c)return c;return`${n.project?.slug??"app"}.local`}function yr(n){let i=n.indexOf(".");return i>0?n.slice(i+1):void 0}function C(n,i={}){let s=n.infrastructure?.compute?.managedServices?.mail,o=or(s),c=i.environmentType??(i.environment?n.environments?.[i.environment]?.type:void 0),u=o.mode??(c==="production"?"server":"catcher"),d=u==="server",p=cr(n,i.environment),y=o.hostname??(d?`mail.${p}`:"localhost"),h=o.ports??{},b=d?{smtp:h.smtp??25,submission:h.submission??587,submissions:h.submissions??465,imap:h.imap??143,imaps:h.imaps??993,webmail:h.webmail??8080,managesieve:h.managesieve}:{smtp:h.smtp??1025,submission:h.submission,submissions:h.submissions,imap:h.imap,imaps:h.imaps,webmail:h.webmail??8025,managesieve:h.managesieve},v=o.tls??{},A=v.enabled??d,T=!!(v.certPath&&v.keyPath),R=(o.accounts??[]).map((me)=>({address:me.address,password:me.password,passwordPolicy:me.passwordPolicy??"initial"})),P=typeof o.dkim==="object"&&o.dkim!==null?o.dkim:{},I=o.dkim===!1?!1:o.dkim===!0||d,M=typeof o.webmail==="object"&&o.webmail!==null?o.webmail:{},L=o.webmail===!1?!1:M.enabled??!0,N=y.includes(".")&&!y.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(y),O=M.domain===!1?void 0:M.domain??(d&&N?y:void 0),B=M.tls??(O?!1:A),F=[...new Set(M.aliases??[])].filter((me)=>me!==O),U=o.spam??{},j=o.delivery??(d?"direct":"none"),H=o.expose??d,z=yr(y),ae=[...new Set([y,...z?[z]:[],...o.domains??[]])],Te=M.attachments?.maxFileBytes??20971520,oe=M.attachments?.maxTotalBytes??20971520,pe=M.attachments?.maxCount??20,se=M.undoSendSeconds??10;for(let[me,Ie,Le]of[["maxFileBytes",Te,104857600],["maxTotalBytes",oe,104857600],["maxCount",pe,100],["undoSendSeconds",se,30]])if(!Number.isInteger(Ie)||Ie<0||Ie>Le)throw Error(`Mail webmail ${me} must be an integer from 0 to ${Le}`);return{enabled:ty(s),mode:u,version:o.version,hostname:y,domains:ae,ports:b,tls:{enabled:A,acme:A&&!T&&(v.acme??!0),certPath:v.certPath,keyPath:v.keyPath,requireForAuth:v.requireForAuth??(A&&d),acmeEmail:v.acmeEmail??R[0]?.address},dkim:{enabled:I,selector:P.selector??"default",rotate:P.rotate??!1,rotateIntervalDays:P.rotateIntervalDays??90},webmail:{enabled:L,port:M.port??b.webmail,domain:O,aliases:F,tls:B,secureCookies:M.secureCookies??(!!O||B),attachmentMaxFileBytes:Te,attachmentMaxTotalBytes:oe,attachmentMaxCount:pe,undoSendSeconds:se},delivery:j,sesRegion:o.sesRegion??"us-east-1",accounts:R,storagePath:o.storagePath??"/var/lib/mail",maxMessageSize:o.maxMessageSize??26214400,spam:{enabled:U.enabled??d,enforce:U.enforce??!1,junkScore:U.junkScore??5,rejectScore:U.rejectScore??12,dnsbl:U.dnsbl??d,greylist:U.greylist??!1},webhookUrl:o.webhookUrl,expose:H,bindAddress:H?"0.0.0.0":"127.0.0.1"}}function Xe(n){if(!n.enabled||!n.expose)return[];let i=[n.ports.smtp,n.ports.submission,n.ports.submissions,n.ports.imap,n.ports.imaps,n.ports.managesieve].filter((s)=>typeof s==="number");if(n.webmail.enabled&&!n.webmail.domain)i.push(n.webmail.port);return[...new Set(i)].sort((s,o)=>s-o)}function Ji(n){if(!n.enabled)return{};let i=n.ports.submission??n.ports.smtp,s={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(i)};if(n.mode==="server"){s.MAIL_ENCRYPTION=n.tls.enabled?"tls":"null";let o=n.accounts[0];if(o)s.MAIL_USERNAME=o.address,s.MAIL_PASSWORD=o.password}else s.MAIL_ENCRYPTION="null",s.MAIL_USERNAME="null",s.MAIL_PASSWORD="null";return s}function dn(n){if(!n.enabled||!n.webmail.enabled||!n.webmail.domain)return{};let i=[n.webmail.domain,...n.webmail.aliases];if(!Number.isInteger(n.webmail.port)||n.webmail.port<1||n.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(i.map((s,o)=>{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(s))throw Error(`Invalid mail webmail hostname: ${s}`);return[`__mail_webmail_${o}`,{domain:s,proxyTo:`localhost:${n.webmail.port}`}]}))}function w(n,i={}){let s=n.infrastructure?.compute?.proxy,o=C(n,i);if(!o.enabled||!o.webmail.enabled||!o.webmail.domain)return s;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:o.tls.acmeEmail??`webmaster@${o.webmail.domain}`,...s}}function be(n){if(n.cloud?.provider)return n.cloud.provider;if(n.ssh?.hosts?.length)return"ssh";if(n.hetzner?.apiToken)return"hetzner";return"aws"}class al{template;constructor(n){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:n,Resources:{}}}addResource(n,i){return this.template.Resources[n]=i,this}addResources(n){return Object.assign(this.template.Resources,n),this}addParameter(n,i){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[n]=i,this}addOutput(n,i){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[n]=i,this}addMetadata(n,i){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[n]=i,this}hasResource(n){return n in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(n=!0){return JSON.stringify(this.template,null,n?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(n,i=0){let s=" ".repeat(i),o="";for(let[c,u]of Object.entries(n)){if(u===null||u===void 0)continue;if(typeof u==="object"&&!Array.isArray(u))o+=`${s}${c}:
|
|
1
|
+
import{k,ra}from"./chunk-m2a60evh.js";import{hn,it}from"./chunk-qb25wesa.js";var km={};hn(km,{default:()=>Rr,handler:()=>At});var Nm={};hn(Nm,{default:()=>Pr,handler:()=>Ct});var Cf={};hn(Cf,{EmailAnalyticsModule:()=>Xe,EmailRules:()=>Ut,EmailScheduling:()=>Wt,EmailSearch:()=>Gt,EmailTemplates:()=>ke,EmailThreading:()=>_t,SharedMailboxes:()=>Vt});var Ef={};hn(Ef,{default:()=>ki,handler:()=>xi});var vf={};hn(vf,{CallAnalytics:()=>jt,CallRecording:()=>Ht,Callbacks:()=>mt,IVRBuilder:()=>Be});var Tf={};hn(Tf,{AbTesting:()=>Ee,LinkTracking:()=>Jt,MmsSupport:()=>zt,SmsAnalytics:()=>qt,SmsCampaigns:()=>Kt,SmsChatbot:()=>Qt});var LI={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}},$I={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 bt,join as st,relative as ar}from"node:path";var rl=".ts-cloud",ym="TS_CLOUD_STATE_DIR",St=null;function nl(n){St=n?.trim()||null}function il(){return Boolean(process.env[ym]?.trim()||St)}function cn(){return process.env[ym]?.trim()||St||rl}function Q(...n){return st(cn(),...n)}function l(n,...i){let s=cn();return bt(s)?st(s,...i):st(n,s,...i)}function sl(n,i=process.cwd()){let s=(c,u)=>{let d=ar(c,u);return d===""||!d.startsWith("..")&&!bt(d)},o=bt(n)?n:st(i,n);return s(l(i),o)}function Sm(n){let i=n.infrastructure?.compute!=null,s=Object.values(n.environments??{}).some((o)=>o?.app!=null);return{server:i,serverless:s}}function K(n){if(n.mode==="server"||n.mode==="serverless")return n.mode;let{serverless:i}=Sm(n);return i?"serverless":"server"}function ol(n){let{server:i,serverless:s}=Sm(n);if(i&&s)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(n.mode==="server"&&s&&!i)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(n.mode==="serverless"&&i&&!s)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function g(n){return n.infrastructure?.appDatabase??n.infrastructure?.compute?.database}function or(n){return typeof n==="object"&&n!==null?n:{}}function ty(n){return n===!0||typeof n==="object"&&n!==null}function cr(n,i){let s=i?n.environments?.[i]:void 0;if(s?.domain)return s.domain;let o=Object.values(n.sites??{}),c=n.sites?.main?.domain??o.find((u)=>u.domain)?.domain;if(c)return c;return`${n.project?.slug??"app"}.local`}function dr(n){let i=n.indexOf(".");return i>0?n.slice(i+1):void 0}function C(n,i={}){let s=n.infrastructure?.compute?.managedServices?.mail,o=or(s),c=i.environmentType??(i.environment?n.environments?.[i.environment]?.type:void 0),u=o.mode??(c==="production"?"server":"catcher"),d=u==="server",p=cr(n,i.environment),y=o.hostname??(d?`mail.${p}`:"localhost"),h=o.ports??{},b=d?{smtp:h.smtp??25,submission:h.submission??587,submissions:h.submissions??465,imap:h.imap??143,imaps:h.imaps??993,webmail:h.webmail??8080,managesieve:h.managesieve}:{smtp:h.smtp??1025,submission:h.submission,submissions:h.submissions,imap:h.imap,imaps:h.imaps,webmail:h.webmail??8025,managesieve:h.managesieve},v=o.tls??{},A=v.enabled??d,T=!!(v.certPath&&v.keyPath),R=(o.accounts??[]).map((me)=>({address:me.address,password:me.password,passwordPolicy:me.passwordPolicy??"initial"})),P=typeof o.dkim==="object"&&o.dkim!==null?o.dkim:{},I=o.dkim===!1?!1:o.dkim===!0||d,M=typeof o.webmail==="object"&&o.webmail!==null?o.webmail:{},L=o.webmail===!1?!1:M.enabled??!0,N=y.includes(".")&&!y.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(y),O=M.domain===!1?void 0:M.domain??(d&&N?y:void 0),B=M.tls??(O?!1:A),F=[...new Set(M.aliases??[])].filter((me)=>me!==O),U=o.spam??{},j=o.delivery??(d?"direct":"none"),H=o.expose??d,z=dr(y),se=[...new Set([y,...z?[z]:[],...o.domains??[]])],Te=M.attachments?.maxFileBytes??20971520,oe=M.attachments?.maxTotalBytes??20971520,pe=M.attachments?.maxCount??20,ae=M.undoSendSeconds??10;for(let[me,Ie,Le]of[["maxFileBytes",Te,104857600],["maxTotalBytes",oe,104857600],["maxCount",pe,100],["undoSendSeconds",ae,30]])if(!Number.isInteger(Ie)||Ie<0||Ie>Le)throw Error(`Mail webmail ${me} must be an integer from 0 to ${Le}`);return{enabled:ty(s),mode:u,version:o.version,hostname:y,domains:se,ports:b,tls:{enabled:A,acme:A&&!T&&(v.acme??!0),certPath:v.certPath,keyPath:v.keyPath,requireForAuth:v.requireForAuth??(A&&d),acmeEmail:v.acmeEmail??R[0]?.address},dkim:{enabled:I,selector:P.selector??"default",rotate:P.rotate??!1,rotateIntervalDays:P.rotateIntervalDays??90},webmail:{enabled:L,port:M.port??b.webmail,domain:O,aliases:F,tls:B,secureCookies:M.secureCookies??(!!O||B),attachmentMaxFileBytes:Te,attachmentMaxTotalBytes:oe,attachmentMaxCount:pe,undoSendSeconds:ae},delivery:j,sesRegion:o.sesRegion??"us-east-1",accounts:R,storagePath:o.storagePath??"/var/lib/mail",maxMessageSize:o.maxMessageSize??26214400,spam:{enabled:U.enabled??d,enforce:U.enforce??!1,junkScore:U.junkScore??5,rejectScore:U.rejectScore??12,dnsbl:U.dnsbl??d,dnsblReject:U.dnsblReject??!1,greylist:U.greylist??!1},webhookUrl:o.webhookUrl,expose:H,bindAddress:H?"0.0.0.0":"127.0.0.1"}}function Ye(n){if(!n.enabled||!n.expose)return[];let i=[n.ports.smtp,n.ports.submission,n.ports.submissions,n.ports.imap,n.ports.imaps,n.ports.managesieve].filter((s)=>typeof s==="number");if(n.webmail.enabled&&!n.webmail.domain)i.push(n.webmail.port);return[...new Set(i)].sort((s,o)=>s-o)}function Ji(n){if(!n.enabled)return{};let i=n.ports.submission??n.ports.smtp,s={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(i)};if(n.mode==="server"){s.MAIL_ENCRYPTION=n.tls.enabled?"tls":"null";let o=n.accounts[0];if(o)s.MAIL_USERNAME=o.address,s.MAIL_PASSWORD=o.password}else s.MAIL_ENCRYPTION="null",s.MAIL_USERNAME="null",s.MAIL_PASSWORD="null";return s}function dn(n){if(!n.enabled||!n.webmail.enabled||!n.webmail.domain)return{};let i=[n.webmail.domain,...n.webmail.aliases];if(!Number.isInteger(n.webmail.port)||n.webmail.port<1||n.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(i.map((s,o)=>{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(s))throw Error(`Invalid mail webmail hostname: ${s}`);return[`__mail_webmail_${o}`,{domain:s,proxyTo:`localhost:${n.webmail.port}`}]}))}function w(n,i={}){let s=n.infrastructure?.compute?.proxy,o=C(n,i);if(!o.enabled||!o.webmail.enabled||!o.webmail.domain)return s;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:o.tls.acmeEmail??`webmaster@${o.webmail.domain}`,...s}}function be(n){if(n.cloud?.provider)return n.cloud.provider;if(n.ssh?.hosts?.length)return"ssh";if(n.hetzner?.apiToken)return"hetzner";return"aws"}class al{template;constructor(n){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:n,Resources:{}}}addResource(n,i){return this.template.Resources[n]=i,this}addResources(n){return Object.assign(this.template.Resources,n),this}addParameter(n,i){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[n]=i,this}addOutput(n,i){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[n]=i,this}addMetadata(n,i){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[n]=i,this}hasResource(n){return n in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(n=!0){return JSON.stringify(this.template,null,n?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(n,i=0){let s=" ".repeat(i),o="";for(let[c,u]of Object.entries(n)){if(u===null||u===void 0)continue;if(typeof u==="object"&&!Array.isArray(u))o+=`${s}${c}:
|
|
2
2
|
${this.convertToYAML(u,i+1)}`;else if(Array.isArray(u)){o+=`${s}${c}:
|
|
3
3
|
`;for(let d of u)if(typeof d==="object")o+=`${s} -
|
|
4
4
|
${this.convertToYAML(d,i+2)}`;else o+=`${s} - ${d}
|
|
5
5
|
`}else o+=`${s}${c}: ${u}
|
|
6
|
-
`}return o}}var x={Ref:(n)=>({Ref:n}),GetAtt:(n,i)=>({"Fn::GetAtt":[n,i]}),Sub:(n,i)=>{if(i)return{"Fn::Sub":[n,i]};return{"Fn::Sub":n}},Join:(n,i)=>({"Fn::Join":[n,i]}),Select:(n,i)=>({"Fn::Select":[n,i]}),Split:(n,i)=>({"Fn::Split":[n,i]}),GetAZs:(n="")=>({"Fn::GetAZs":n}),ImportValue:(n)=>({"Fn::ImportValue":n}),If:(n,i,s)=>({"Fn::If":[n,i,s]}),Equals:(n,i)=>({"Fn::Equals":[n,i]}),And:(...n)=>({"Fn::And":n}),Or:(...n)=>({"Fn::Or":n}),Not:(n)=>({"Fn::Not":[n]}),Base64:(n)=>({"Fn::Base64":n})},ry={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 r(n){let{slug:i,environment:s,resourceType:o,timestamp:c,suffix:u}=n,d=[i,s,o];if(c)d.push(c);if(u)d.push(u);return d.join("-")}function t(n){return n.split("-").map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")}function MI(){return Date.now().toString()}function FI(n){return n.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function m(n,i){return n.project.stackName??`${n.project.slug}-${i}`}function UI(n,i,s,o){return s.stackName??`${n.project.slug}-${o}-${i}-site`}function QI(n,i){return`${n.project.slug}-${i}`}function HI(n,i,s,o){if(o)return o;if(s==="main")return`${n}-${i}-site`;return`${n}-${i}-${s}`}function GI(n,i,s,o){return o??`${n}-${i}-${s}`}function VI(n,i){return`${n}-${i}-deploy`}function
|
|
6
|
+
`}return o}}var x={Ref:(n)=>({Ref:n}),GetAtt:(n,i)=>({"Fn::GetAtt":[n,i]}),Sub:(n,i)=>{if(i)return{"Fn::Sub":[n,i]};return{"Fn::Sub":n}},Join:(n,i)=>({"Fn::Join":[n,i]}),Select:(n,i)=>({"Fn::Select":[n,i]}),Split:(n,i)=>({"Fn::Split":[n,i]}),GetAZs:(n="")=>({"Fn::GetAZs":n}),ImportValue:(n)=>({"Fn::ImportValue":n}),If:(n,i,s)=>({"Fn::If":[n,i,s]}),Equals:(n,i)=>({"Fn::Equals":[n,i]}),And:(...n)=>({"Fn::And":n}),Or:(...n)=>({"Fn::Or":n}),Not:(n)=>({"Fn::Not":[n]}),Base64:(n)=>({"Fn::Base64":n})},ry={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 r(n){let{slug:i,environment:s,resourceType:o,timestamp:c,suffix:u}=n,d=[i,s,o];if(c)d.push(c);if(u)d.push(u);return d.join("-")}function t(n){return n.split("-").map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")}function MI(){return Date.now().toString()}function FI(n){return n.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function m(n,i){return n.project.stackName??`${n.project.slug}-${i}`}function UI(n,i,s,o){return s.stackName??`${n.project.slug}-${o}-${i}-site`}function QI(n,i){return`${n.project.slug}-${i}`}function HI(n,i,s,o){if(o)return o;if(s==="main")return`${n}-${i}-site`;return`${n}-${i}-${s}`}function GI(n,i,s,o){return o??`${n}-${i}-${s}`}function VI(n,i){return`${n}-${i}-deploy`}function lr(n,i){return`${n.project.slug}-${i}-app`}function cl(n,i){return`${n}-${i}-deployments`}function Xi(n,i){return`${n}-${i}-assets`}class ny{nodes=new Map;addResource(n,i){let s=this.extractDependencies(i);this.nodes.set(n,{logicalId:n,resource:i,dependencies:s})}extractDependencies(n){let i=new Set;if(n.DependsOn)if(Array.isArray(n.DependsOn))n.DependsOn.forEach((s)=>i.add(s));else i.add(n.DependsOn);return this.findReferences(n.Properties||{},i),i}findReferences(n,i){if(!n||typeof n!=="object")return;if("Ref"in n&&typeof n.Ref==="string"){if(!n.Ref.startsWith("AWS::"))i.add(n.Ref)}if("Fn::GetAtt"in n&&Array.isArray(n["Fn::GetAtt"]))i.add(n["Fn::GetAtt"][0]);for(let s of Object.values(n))if(typeof s==="object")this.findReferences(s,i)}topologicalSort(){let n=[],i=new Set,s=new Set,o=(c)=>{if(i.has(c))return;if(s.has(c))throw Error(`Circular dependency detected: ${c}`);s.add(c);let u=this.nodes.get(c);if(u)for(let d of u.dependencies)o(d);s.delete(c),i.add(c),n.push(c)};for(let c of this.nodes.keys())o(c);return n}validate(){for(let[n,i]of this.nodes.entries())for(let s of i.dependencies)if(!this.nodes.has(s))throw Error(`Resource "${n}" depends on "${s}" which does not exist`)}getDependents(n){let i=[];for(let[s,o]of this.nodes.entries())if(o.dependencies.has(n))i.push(s);return i}}function qI(n,i){let s=[],o=[],c=[],u=[],d=[],p=n.Resources||{},y=i.Resources||{},h=new Set([...Object.keys(p),...Object.keys(y)]);for(let v of h){let A=p[v],T=y[v];if(!A&&T)s.push({logicalId:v,action:"add",resourceType:T.Type});else if(A&&!T)o.push({logicalId:v,action:"remove",resourceType:A.Type});else if(A&&T)if(A.Type!==T.Type)u.push({logicalId:v,action:"replace",resourceType:T.Type,reason:`Type changed from ${A.Type} to ${T.Type}`});else{let R=tn(A.Properties||{},T.Properties||{});if(R.length>0)if(yr(A.Type,R))u.push({logicalId:v,action:"replace",resourceType:T.Type,changes:R,reason:"Property changes require replacement"});else c.push({logicalId:v,action:"update",resourceType:T.Type,changes:R});else d.push(v)}}let b=br([...o,...u,...c]);return{added:s,removed:o,updated:c,replaced:u,unchanged:d,summary:{totalChanges:s.length+o.length+c.length+u.length,requiresReplacement:u.length>0,dangerousChanges:b}}}function tn(n,i,s=""){let o=[],c=new Set([...Object.keys(n),...Object.keys(i)]);for(let u of c){let d=s?`${s}.${u}`:u,p=n[u],y=i[u];if(p===void 0&&y!==void 0)o.push({path:d,oldValue:void 0,newValue:y});else if(p!==void 0&&y===void 0)o.push({path:d,oldValue:p,newValue:void 0});else if(typeof p!==typeof y)o.push({path:d,oldValue:p,newValue:y});else if(typeof p==="object"&&p!==null)if(Array.isArray(p)&&Array.isArray(y)){if(JSON.stringify(p)!==JSON.stringify(y))o.push({path:d,oldValue:p,newValue:y})}else if(!Array.isArray(p)&&!Array.isArray(y)){let h=tn(p,y,d);o.push(...h)}else o.push({path:d,oldValue:p,newValue:y});else if(p!==y)o.push({path:d,oldValue:p,newValue:y})}return o}function yr(n,i){let o={"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"])}[n];if(!o)return!1;for(let c of i){let u=c.path.split(".")[0];if(o.has(u))return!0}return!1}function br(n){let i=[];for(let s of n){if(s.action==="remove"&&(s.resourceType==="AWS::RDS::DBInstance"||s.resourceType==="AWS::DynamoDB::Table"||s.resourceType==="AWS::ElastiCache::CacheCluster"))i.push(`Removing ${s.resourceType} ${s.logicalId} - data loss risk!`);if(s.action==="replace"&&(s.resourceType==="AWS::RDS::DBInstance"||s.resourceType==="AWS::DynamoDB::Table"))i.push(`Replacing ${s.resourceType} ${s.logicalId} - data loss risk!`);if((s.action==="remove"||s.action==="replace")&&s.resourceType==="AWS::S3::Bucket")i.push(`${s.action==="remove"?"Removing":"Replacing"} S3 bucket ${s.logicalId} - data loss risk!`);if(s.action==="replace"&&s.resourceType==="AWS::EC2::Instance")i.push(`Replacing EC2 instance ${s.logicalId} - downtime expected`);if(s.action==="update"&&s.resourceType==="AWS::EC2::SecurityGroup")i.push(`Updating security group ${s.logicalId} - may affect connectivity`);if((s.action==="update"||s.action==="replace")&&(s.resourceType==="AWS::IAM::Role"||s.resourceType==="AWS::IAM::Policy"))i.push(`Modifying IAM ${s.resourceType.split("::")[2]} ${s.logicalId} - may affect permissions`)}return i}function jI(n){let i=[];if(i.push(`=== Stack Update Analysis ===
|
|
7
7
|
`),n.summary.totalChanges===0)return i.push(`No changes detected.
|
|
8
8
|
`),i.join(`
|
|
9
9
|
`);if(i.push(`Total changes: ${n.summary.totalChanges}`),i.push(`Requires replacement: ${n.summary.requiresReplacement?"Yes":"No"}
|
|
10
10
|
`),n.summary.dangerousChanges.length>0){i.push("⚠️ DANGEROUS CHANGES DETECTED:");for(let s of n.summary.dangerousChanges)i.push(` • ${s}`);i.push("")}if(n.added.length>0){i.push(`✅ Resources to Add (${n.added.length}):`);for(let s of n.added)i.push(` + ${s.logicalId} (${s.resourceType})`);i.push("")}if(n.removed.length>0){i.push(`❌ Resources to Remove (${n.removed.length}):`);for(let s of n.removed)i.push(` - ${s.logicalId} (${s.resourceType})`);i.push("")}if(n.replaced.length>0){i.push(`\uD83D\uDD04 Resources to Replace (${n.replaced.length}):`);for(let s of n.replaced){if(i.push(` ~ ${s.logicalId} (${s.resourceType})`),s.reason)i.push(` Reason: ${s.reason}`);if(s.changes){for(let o of s.changes.slice(0,3))i.push(` • ${o.path}: ${JSON.stringify(o.oldValue)} → ${JSON.stringify(o.newValue)}`);if(s.changes.length>3)i.push(` ... and ${s.changes.length-3} more changes`)}}i.push("")}if(n.updated.length>0){i.push(`\uD83D\uDCDD Resources to Update (${n.updated.length}):`);for(let s of n.updated)if(i.push(` ~ ${s.logicalId} (${s.resourceType})`),s.changes){for(let o of s.changes.slice(0,3))i.push(` • ${o.path}: ${JSON.stringify(o.oldValue)} → ${JSON.stringify(o.newValue)}`);if(s.changes.length>3)i.push(` ... and ${s.changes.length-3} more changes`)}i.push("")}if(n.unchanged.length>0)i.push(`⚪ Unchanged Resources (${n.unchanged.length})`);return i.join(`
|
|
11
|
-
`)}import{existsSync as He,readdirSync as Ar}from"node:fs";import{join as Pe}from"node:path";class xe{static createBucket(n){let{name:i,bucketName:s,slug:o,environment:c,public:u=!1,versioning:d=!1,website:p=!1,encryption:y=!0,intelligentTiering:h=!1,cors:b,lifecycleRules:v}=n,A=s??r({slug:o,environment:c,resourceType:"s3",suffix:i}),T=t(A),R={Type:"AWS::S3::Bucket",Properties:{BucketName:A}};if(y)R.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(d)R.Properties.VersioningConfiguration={Status:"Enabled"};if(p)R.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!u)R.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(b&&b.length>0)R.Properties.CorsConfiguration={CorsRules:b.map((I)=>({AllowedOrigins:I.allowedOrigins,AllowedMethods:I.allowedMethods,AllowedHeaders:I.allowedHeaders,MaxAge:I.maxAge}))};if(v&&v.length>0)R.Properties.LifecycleConfiguration={Rules:v.map((I)=>({Id:I.id,Status:I.enabled?"Enabled":"Disabled",ExpirationInDays:I.expirationDays,Transitions:I.transitions?.map((M)=>({TransitionInDays:M.days,StorageClass:M.storageClass}))}))};if(h&&v){let I={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!R.Properties.LifecycleConfiguration)R.Properties.LifecycleConfiguration={Rules:[]};R.Properties.LifecycleConfiguration.Rules.push({Id:I.id,Status:"Enabled",Transitions:I.transitions?.map((M)=>({TransitionInDays:M.days,StorageClass:M.storageClass}))})}let P;if(u)P={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(T),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[x.Join("",[x.GetAtt(T,"Arn"),"/*"])]}]}}};return{bucket:R,bucketPolicy:P,logicalId:T}}static enableVersioning(n){if(!n.Properties)n.Properties={};return n.Properties.VersioningConfiguration={Status:"Enabled"},n}static enableWebsiteHosting(n,i="index.html",s="error.html"){if(!n.Properties)n.Properties={};return n.Properties.WebsiteConfiguration={IndexDocument:i,ErrorDocument:s},n}static setLifecycleRules(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecycleConfiguration={Rules:i.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((o)=>({TransitionInDays:o.days,StorageClass:o.storageClass}))}))},n}static enableIntelligentTiering(n){if(!n.Properties)n.Properties={};if(!n.Properties.LifecycleConfiguration)n.Properties.LifecycleConfiguration={Rules:[]};return n.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),n}static addLambdaNotification(n,i){if(!n.Properties)n.Properties={};if(!n.Properties.NotificationConfiguration)n.Properties.NotificationConfiguration={};if(!n.Properties.NotificationConfiguration.LambdaConfigurations)n.Properties.NotificationConfiguration.LambdaConfigurations=[];let s={Event:i.events[0],Function:i.functionArn};if(i.filter)s.Filter={S3Key:{Rules:[...i.filter.prefix?[{Name:"prefix",Value:i.filter.prefix}]:[],...i.filter.suffix?[{Name:"suffix",Value:i.filter.suffix}]:[]]}};for(let o of i.events){let c={...s,Event:o};n.Properties.NotificationConfiguration.LambdaConfigurations.push(c)}return n}static Notifications={onObjectCreated:(n)=>({functionArn:n,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(n)=>({functionArn:n,events:["s3:ObjectRemoved:*"]}),onImageUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i,suffix:".jpg"}}),onFileType:(n,i,s)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:s,suffix:i}}),onFolderUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i.endsWith("/")?i:`${i}/`}})};static createBackupPlan(n){let{name:i,slug:s,environment:o,bucketLogicalIds:c,retentionDays:u,schedule:d="cron(0 5 * * ? *)",vaultName:p,enableContinuousBackup:y=!1,moveToColdStorageAfterDays:h}=n,b=p||r({slug:s,environment:o,resourceType:"backup-vault",suffix:i}),v=t(b),A={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:b}},T=r({slug:s,environment:o,resourceType:"backup-role",suffix:i}),R=t(T),P={Type:"AWS::IAM::Role",Properties:{RoleName:T,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},I=r({slug:s,environment:o,resourceType:"backup-plan",suffix:i}),M=t(I),L={DeleteAfterDays:u};if(h&&h<u)L.MoveToColdStorageAfterDays=h;let N={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:I,BackupPlanRule:[{RuleName:`${i}-daily-backup`,TargetBackupVault:x.Ref(v),ScheduleExpression:d,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:L,EnableContinuousBackup:y}]}}},O=r({slug:s,environment:o,resourceType:"backup-selection",suffix:i}),B=t(O),F=c.map((j)=>x.GetAtt(j,"Arn")),U={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:x.Ref(M),BackupSelection:{SelectionName:O,IamRoleArn:x.GetAtt(R,"Arn"),Resources:F}}};return{vault:A,plan:N,selection:U,role:P,vaultLogicalId:v,planLogicalId:M,selectionLogicalId:B,roleLogicalId:R}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:u="https"}=n,d=r({slug:i,environment:s,resourceType:"s3",suffix:"www-redirect"}),p=t(d),y={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:u}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},h={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(p),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[x.Join("",[x.GetAtt(p,"Arn"),"/*"])]}]}}};return{bucket:y,bucketPolicy:h,logicalId:p}}static createDocsBucket(n){let{slug:i,environment:s,domain:o}=n,c=o||r({slug:i,environment:s,resourceType:"s3",suffix:"docs"}),u=t(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:u}}static createEmailBucket(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"s3",suffix:"email"}),c=t(o),u={Type:"AWS::S3::Bucket",Properties:{BucketName:o,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},d={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(c),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:x.Join("",[x.GetAtt(c,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":x.Ref("AWS::AccountId")}}}]}}};return{bucket:u,bucketPolicy:d,logicalId:c}}static docsExist(n={}){let{projectRoot:i=process.cwd(),docsPaths:s=["docs","documentation","doc"]}=n;for(let o of s){let c=Pe(i,o);if(He(c)){let u=["dist","build",".bunpress/dist","_site","out","public"];for(let d of u){let p=Pe(c,d);if(He(p))try{if(Ar(p).length>0)return{exists:!0,path:c,hasDistFolder:!0,distPath:p}}catch{}}return{exists:!0,path:c,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(n){let i=xe.docsExist({projectRoot:n.projectRoot,docsPaths:n.docsPaths});if(!i.exists)return{bucket:null,logicalId:null,docsInfo:i};let s=xe.createDocsBucket({slug:n.slug,environment:n.environment,domain:n.domain});return{bucket:s.bucket,bucketPolicy:s.bucketPolicy,logicalId:s.logicalId,docsInfo:i}}static createPrivateBucket(n){let{slug:i,environment:s,enableVersioning:o=!0,retentionDays:c,encryptionKeyArn:u}=n,d=r({slug:i,environment:s,resourceType:"s3",suffix:"private"}),p=t(d);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:d,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:u?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:u}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:o?{Status:"Enabled"}:void 0,LifecycleConfiguration:c?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:c}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:p}}static checkSourcePaths(n={}){let{projectRoot:i=process.cwd(),paths:s={}}=n,o=s.web||"views/web/dist",c=s.docs||"docs/dist",u=s.private||"private";return{web:{exists:He(Pe(i,o)),path:Pe(i,o)},docs:{exists:He(Pe(i,c)),path:Pe(i,c)},private:{exists:He(Pe(i,u)),path:Pe(i,u)}}}static createDeploymentBuckets(n){let{slug:i,environment:s,domain:o,projectRoot:c,paths:u}=n,d=xe.checkSourcePaths({projectRoot:c,paths:u}),p={},y={web:!1,docs:!1,private:!1},h=xe.createBucket({name:"web",slug:i,environment:s,public:!1,versioning:!1,encryption:!0});if(p[h.logicalId]=h.bucket,y.web=!0,d.docs.exists){let b=xe.createDocsBucket({slug:i,environment:s,domain:o?`docs.${o}`:void 0});if(p[b.logicalId]=b.bucket,b.bucketPolicy)p[`${b.logicalId}Policy`]=b.bucketPolicy;y.docs=!0}if(d.private.exists){let b=xe.createPrivateBucket({slug:i,environment:s,enableVersioning:!0});p[b.logicalId]=b.bucket,y.private=!0}return{resources:p,created:y,sourcePaths:d}}}class Ye{static createRepository(n){let{name:i,slug:s,environment:o,scanOnPush:c=!0,imageMutability:u="MUTABLE",encryption:d="AES256",kmsKey:p,lifecyclePolicy:y,tags:h}=n,b=r({slug:s,environment:o,resourceType:"ecr",suffix:i}),v=t(b),A={Type:"AWS::ECR::Repository",Properties:{RepositoryName:b,ImageTagMutability:u,ImageScanningConfiguration:{ScanOnPush:c},EncryptionConfiguration:{EncryptionType:d,...p&&d==="KMS"?{KmsKey:p}:{}}}};if(y)A.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Ye.generateLifecyclePolicy(y))};if(h)A.Properties.Tags=Object.entries(h).map(([T,R])=>({Key:T,Value:R}));return{repository:A,logicalId:v}}static generateLifecyclePolicy(n){let i=[];if(n.untaggedImageExpireDays!==void 0)i.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:n.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(n.maxImageCount!==void 0)i.push({rulePriority:i.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:n.maxImageCount},action:{type:"expire"}});if(n.maxImageAgeDays!==void 0)i.push({rulePriority:i.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:n.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:i}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(n){if(!n.Properties)n.Properties={};return n.Properties.ImageTagMutability="IMMUTABLE",n}static enableScanOnPush(n){if(!n.Properties)n.Properties={};return n.Properties.ImageScanningConfiguration={ScanOnPush:!0},n}static setLifecyclePolicy(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Ye.generateLifecyclePolicy(i))},n}static addCrossAccountAccess(n,i){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:i.map((s)=>`arn:aws:iam::${s}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},n}static addLambdaAccess(n){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},n}static generateBunDockerfile(n){let{baseImage:i="oven/bun:1-debian",serverPath:s,port:o=3000,additionalDirs:c=[],healthCheckEndpoint:u="/health",nodeCompatible:d=!1,envVars:p={},buildCommands:y=[],runCommand:h}=n,b=["app","config",...c],v=h||`bun run ${s}`,A=`# Multi-stage build for Bun application
|
|
11
|
+
`)}import{existsSync as He,readdirSync as Sr}from"node:fs";import{join as Pe}from"node:path";class xe{static createBucket(n){let{name:i,bucketName:s,slug:o,environment:c,public:u=!1,versioning:d=!1,website:p=!1,encryption:y=!0,intelligentTiering:h=!1,cors:b,lifecycleRules:v}=n,A=s??r({slug:o,environment:c,resourceType:"s3",suffix:i}),T=t(A),R={Type:"AWS::S3::Bucket",Properties:{BucketName:A}};if(y)R.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(d)R.Properties.VersioningConfiguration={Status:"Enabled"};if(p)R.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!u)R.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(b&&b.length>0)R.Properties.CorsConfiguration={CorsRules:b.map((I)=>({AllowedOrigins:I.allowedOrigins,AllowedMethods:I.allowedMethods,AllowedHeaders:I.allowedHeaders,MaxAge:I.maxAge}))};if(v&&v.length>0)R.Properties.LifecycleConfiguration={Rules:v.map((I)=>({Id:I.id,Status:I.enabled?"Enabled":"Disabled",ExpirationInDays:I.expirationDays,Transitions:I.transitions?.map((M)=>({TransitionInDays:M.days,StorageClass:M.storageClass}))}))};if(h&&v){let I={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!R.Properties.LifecycleConfiguration)R.Properties.LifecycleConfiguration={Rules:[]};R.Properties.LifecycleConfiguration.Rules.push({Id:I.id,Status:"Enabled",Transitions:I.transitions?.map((M)=>({TransitionInDays:M.days,StorageClass:M.storageClass}))})}let P;if(u)P={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(T),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[x.Join("",[x.GetAtt(T,"Arn"),"/*"])]}]}}};return{bucket:R,bucketPolicy:P,logicalId:T}}static enableVersioning(n){if(!n.Properties)n.Properties={};return n.Properties.VersioningConfiguration={Status:"Enabled"},n}static enableWebsiteHosting(n,i="index.html",s="error.html"){if(!n.Properties)n.Properties={};return n.Properties.WebsiteConfiguration={IndexDocument:i,ErrorDocument:s},n}static setLifecycleRules(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecycleConfiguration={Rules:i.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((o)=>({TransitionInDays:o.days,StorageClass:o.storageClass}))}))},n}static enableIntelligentTiering(n){if(!n.Properties)n.Properties={};if(!n.Properties.LifecycleConfiguration)n.Properties.LifecycleConfiguration={Rules:[]};return n.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),n}static addLambdaNotification(n,i){if(!n.Properties)n.Properties={};if(!n.Properties.NotificationConfiguration)n.Properties.NotificationConfiguration={};if(!n.Properties.NotificationConfiguration.LambdaConfigurations)n.Properties.NotificationConfiguration.LambdaConfigurations=[];let s={Event:i.events[0],Function:i.functionArn};if(i.filter)s.Filter={S3Key:{Rules:[...i.filter.prefix?[{Name:"prefix",Value:i.filter.prefix}]:[],...i.filter.suffix?[{Name:"suffix",Value:i.filter.suffix}]:[]]}};for(let o of i.events){let c={...s,Event:o};n.Properties.NotificationConfiguration.LambdaConfigurations.push(c)}return n}static Notifications={onObjectCreated:(n)=>({functionArn:n,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(n)=>({functionArn:n,events:["s3:ObjectRemoved:*"]}),onImageUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i,suffix:".jpg"}}),onFileType:(n,i,s)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:s,suffix:i}}),onFolderUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i.endsWith("/")?i:`${i}/`}})};static createBackupPlan(n){let{name:i,slug:s,environment:o,bucketLogicalIds:c,retentionDays:u,schedule:d="cron(0 5 * * ? *)",vaultName:p,enableContinuousBackup:y=!1,moveToColdStorageAfterDays:h}=n,b=p||r({slug:s,environment:o,resourceType:"backup-vault",suffix:i}),v=t(b),A={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:b}},T=r({slug:s,environment:o,resourceType:"backup-role",suffix:i}),R=t(T),P={Type:"AWS::IAM::Role",Properties:{RoleName:T,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},I=r({slug:s,environment:o,resourceType:"backup-plan",suffix:i}),M=t(I),L={DeleteAfterDays:u};if(h&&h<u)L.MoveToColdStorageAfterDays=h;let N={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:I,BackupPlanRule:[{RuleName:`${i}-daily-backup`,TargetBackupVault:x.Ref(v),ScheduleExpression:d,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:L,EnableContinuousBackup:y}]}}},O=r({slug:s,environment:o,resourceType:"backup-selection",suffix:i}),B=t(O),F=c.map((j)=>x.GetAtt(j,"Arn")),U={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:x.Ref(M),BackupSelection:{SelectionName:O,IamRoleArn:x.GetAtt(R,"Arn"),Resources:F}}};return{vault:A,plan:N,selection:U,role:P,vaultLogicalId:v,planLogicalId:M,selectionLogicalId:B,roleLogicalId:R}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:u="https"}=n,d=r({slug:i,environment:s,resourceType:"s3",suffix:"www-redirect"}),p=t(d),y={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:u}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},h={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(p),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[x.Join("",[x.GetAtt(p,"Arn"),"/*"])]}]}}};return{bucket:y,bucketPolicy:h,logicalId:p}}static createDocsBucket(n){let{slug:i,environment:s,domain:o}=n,c=o||r({slug:i,environment:s,resourceType:"s3",suffix:"docs"}),u=t(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:u}}static createEmailBucket(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"s3",suffix:"email"}),c=t(o),u={Type:"AWS::S3::Bucket",Properties:{BucketName:o,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},d={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(c),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:x.Join("",[x.GetAtt(c,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":x.Ref("AWS::AccountId")}}}]}}};return{bucket:u,bucketPolicy:d,logicalId:c}}static docsExist(n={}){let{projectRoot:i=process.cwd(),docsPaths:s=["docs","documentation","doc"]}=n;for(let o of s){let c=Pe(i,o);if(He(c)){let u=["dist","build",".bunpress/dist","_site","out","public"];for(let d of u){let p=Pe(c,d);if(He(p))try{if(Sr(p).length>0)return{exists:!0,path:c,hasDistFolder:!0,distPath:p}}catch{}}return{exists:!0,path:c,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(n){let i=xe.docsExist({projectRoot:n.projectRoot,docsPaths:n.docsPaths});if(!i.exists)return{bucket:null,logicalId:null,docsInfo:i};let s=xe.createDocsBucket({slug:n.slug,environment:n.environment,domain:n.domain});return{bucket:s.bucket,bucketPolicy:s.bucketPolicy,logicalId:s.logicalId,docsInfo:i}}static createPrivateBucket(n){let{slug:i,environment:s,enableVersioning:o=!0,retentionDays:c,encryptionKeyArn:u}=n,d=r({slug:i,environment:s,resourceType:"s3",suffix:"private"}),p=t(d);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:d,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:u?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:u}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:o?{Status:"Enabled"}:void 0,LifecycleConfiguration:c?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:c}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:p}}static checkSourcePaths(n={}){let{projectRoot:i=process.cwd(),paths:s={}}=n,o=s.web||"views/web/dist",c=s.docs||"docs/dist",u=s.private||"private";return{web:{exists:He(Pe(i,o)),path:Pe(i,o)},docs:{exists:He(Pe(i,c)),path:Pe(i,c)},private:{exists:He(Pe(i,u)),path:Pe(i,u)}}}static createDeploymentBuckets(n){let{slug:i,environment:s,domain:o,projectRoot:c,paths:u}=n,d=xe.checkSourcePaths({projectRoot:c,paths:u}),p={},y={web:!1,docs:!1,private:!1},h=xe.createBucket({name:"web",slug:i,environment:s,public:!1,versioning:!1,encryption:!0});if(p[h.logicalId]=h.bucket,y.web=!0,d.docs.exists){let b=xe.createDocsBucket({slug:i,environment:s,domain:o?`docs.${o}`:void 0});if(p[b.logicalId]=b.bucket,b.bucketPolicy)p[`${b.logicalId}Policy`]=b.bucketPolicy;y.docs=!0}if(d.private.exists){let b=xe.createPrivateBucket({slug:i,environment:s,enableVersioning:!0});p[b.logicalId]=b.bucket,y.private=!0}return{resources:p,created:y,sourcePaths:d}}}class Ze{static createRepository(n){let{name:i,slug:s,environment:o,scanOnPush:c=!0,imageMutability:u="MUTABLE",encryption:d="AES256",kmsKey:p,lifecyclePolicy:y,tags:h}=n,b=r({slug:s,environment:o,resourceType:"ecr",suffix:i}),v=t(b),A={Type:"AWS::ECR::Repository",Properties:{RepositoryName:b,ImageTagMutability:u,ImageScanningConfiguration:{ScanOnPush:c},EncryptionConfiguration:{EncryptionType:d,...p&&d==="KMS"?{KmsKey:p}:{}}}};if(y)A.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Ze.generateLifecyclePolicy(y))};if(h)A.Properties.Tags=Object.entries(h).map(([T,R])=>({Key:T,Value:R}));return{repository:A,logicalId:v}}static generateLifecyclePolicy(n){let i=[];if(n.untaggedImageExpireDays!==void 0)i.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:n.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(n.maxImageCount!==void 0)i.push({rulePriority:i.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:n.maxImageCount},action:{type:"expire"}});if(n.maxImageAgeDays!==void 0)i.push({rulePriority:i.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:n.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:i}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(n){if(!n.Properties)n.Properties={};return n.Properties.ImageTagMutability="IMMUTABLE",n}static enableScanOnPush(n){if(!n.Properties)n.Properties={};return n.Properties.ImageScanningConfiguration={ScanOnPush:!0},n}static setLifecyclePolicy(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Ze.generateLifecyclePolicy(i))},n}static addCrossAccountAccess(n,i){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:i.map((s)=>`arn:aws:iam::${s}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},n}static addLambdaAccess(n){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},n}static generateBunDockerfile(n){let{baseImage:i="oven/bun:1-debian",serverPath:s,port:o=3000,additionalDirs:c=[],healthCheckEndpoint:u="/health",nodeCompatible:d=!1,envVars:p={},buildCommands:y=[],runCommand:h}=n,b=["app","config",...c],v=h||`bun run ${s}`,A=`# Multi-stage build for Bun application
|
|
12
12
|
# Generated by ts-cloud
|
|
13
13
|
|
|
14
14
|
# Builder stage
|
|
@@ -62,7 +62,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
|
|
|
62
62
|
|
|
63
63
|
# Start application
|
|
64
64
|
CMD ["bun", "run", "${s}"]
|
|
65
|
-
`,A}static generateDockerBuildCommands(n){let{repositoryUri:i,tag:s="latest",dockerfilePath:o="Dockerfile",context:c=".",additionalTags:u=[],buildArgs:d={},platform:p="linux/amd64",noCache:y=!1}=n,h=`${i}:${s}`,b=[s,...u],v=`docker build -f ${o} -t ${h}`;if(p)v+=` --platform ${p}`;if(y)v+=" --no-cache";for(let[R,P]of Object.entries(d))v+=` --build-arg ${R}=${P}`;v+=` ${c}`;let A=b.slice(1).map((R)=>`docker tag ${h} ${i}:${R}`),T=b.map((R)=>`docker push ${i}:${R}`);return{build:v,tag:A,push:T,all:[v,...A,...T]}}static generateEcrLoginCommand(n,i){return`aws ecr get-login-password --region ${n} | docker login --username AWS --password-stdin ${i}.dkr.ecr.${n}.amazonaws.com`}static buildRepositoryUri(n){return`${n.accountId}.dkr.ecr.${n.region}.amazonaws.com/${n.repositoryName}`}static generateImageTags(n){let i=["latest"];if(n.version){i.push(n.version);let s=n.version.split(".");if(s.length>=2)i.push(`${s[0]}.${s[1]}`);if(s.length>=1)i.push(s[0])}if(n.gitSha)i.push(n.gitSha.substring(0,7)),i.push(n.gitSha);if(n.gitBranch){let s=n.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");i.push(s)}if(n.environment)i.push(n.environment);if(n.timestamp){let s=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);i.push(s)}return[...new Set(i)]}static DeploymentWorkflow={generateDeployScript:(n)=>{let i=
|
|
65
|
+
`,A}static generateDockerBuildCommands(n){let{repositoryUri:i,tag:s="latest",dockerfilePath:o="Dockerfile",context:c=".",additionalTags:u=[],buildArgs:d={},platform:p="linux/amd64",noCache:y=!1}=n,h=`${i}:${s}`,b=[s,...u],v=`docker build -f ${o} -t ${h}`;if(p)v+=` --platform ${p}`;if(y)v+=" --no-cache";for(let[R,P]of Object.entries(d))v+=` --build-arg ${R}=${P}`;v+=` ${c}`;let A=b.slice(1).map((R)=>`docker tag ${h} ${i}:${R}`),T=b.map((R)=>`docker push ${i}:${R}`);return{build:v,tag:A,push:T,all:[v,...A,...T]}}static generateEcrLoginCommand(n,i){return`aws ecr get-login-password --region ${n} | docker login --username AWS --password-stdin ${i}.dkr.ecr.${n}.amazonaws.com`}static buildRepositoryUri(n){return`${n.accountId}.dkr.ecr.${n.region}.amazonaws.com/${n.repositoryName}`}static generateImageTags(n){let i=["latest"];if(n.version){i.push(n.version);let s=n.version.split(".");if(s.length>=2)i.push(`${s[0]}.${s[1]}`);if(s.length>=1)i.push(s[0])}if(n.gitSha)i.push(n.gitSha.substring(0,7)),i.push(n.gitSha);if(n.gitBranch){let s=n.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");i.push(s)}if(n.environment)i.push(n.environment);if(n.timestamp){let s=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);i.push(s)}return[...new Set(i)]}static DeploymentWorkflow={generateDeployScript:(n)=>{let i=Ze.buildRepositoryUri({accountId:n.accountId,region:n.region,repositoryName:n.repositoryName}),s=n.tags||["latest"],o=s[0];return`#!/bin/bash
|
|
66
66
|
set -e
|
|
67
67
|
|
|
68
68
|
# Configuration
|
|
@@ -73,7 +73,7 @@ IMAGE_URI="${i}"
|
|
|
73
73
|
DOCKERFILE="${n.dockerfilePath||"Dockerfile"}"
|
|
74
74
|
|
|
75
75
|
echo "=== ECR Login ==="
|
|
76
|
-
${
|
|
76
|
+
${Ze.generateEcrLoginCommand(n.region,n.accountId)}
|
|
77
77
|
|
|
78
78
|
echo "=== Building Image ==="
|
|
79
79
|
docker build -f $DOCKERFILE -t $IMAGE_URI:${o} --platform linux/amd64 .
|
|
@@ -91,7 +91,7 @@ echo "Image: $IMAGE_URI:${o}"
|
|
|
91
91
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
|
92
92
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest`},...n.ecsCluster&&n.ecsService?[{name:"Deploy to ECS",run:`aws ecs update-service --cluster ${n.ecsCluster} --service ${n.ecsService} --force-new-deployment`}]:[]]}}};return`# Generated by ts-cloud
|
|
93
93
|
${JSON.stringify(i,null,2).replace(/"/g,"").replace(/,\n/g,`
|
|
94
|
-
`)}`}};static DockerfileTemplates={bunServer:(n,i=3000)=>Ye.generateBunDockerfile({serverPath:n,port:i}),bunWithBuild:(n,i,s=3000)=>Ye.generateBunDockerfile({serverPath:n,port:s,buildCommands:[i]}),bunFullStack:(n,i=3000)=>Ye.generateBunDockerfile({serverPath:n,port:i,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(n,i=3000)=>Ye.generateBunDockerfile({serverPath:n,port:i,healthCheckEndpoint:"/api/health"})}}var dl=[400,403,404,416,429,500,502,503,504],Im=[500,502,503,504],bm=["GET","HEAD","OPTIONS"],zI="-failover-group",Cm=["default","media-quality-based"],Em={min:1,max:3},vm={min:1,max:10};function Qo(n){if(n===void 0)return[...Im];if(n.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${dl.join(", ")}). Omit it to use the default ${Im.join(", ")}.`);let i=n.filter((s)=>!dl.includes(s));if(i.length>0)throw Error(`CloudFront origin failover: ${i.join(", ")} ${i.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${dl.join(", ")}.`);return[...new Set(n)].sort((s,o)=>s-o)}function ll(n){let{primaryOriginId:i,secondaryOriginId:s}=n;if(!i||!s)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(i===s)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${i}")`);let o=Qo(n.statusCodes);return nn(n.selectionCriteria),{Id:n.groupId??`${i}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:o.length,Items:o}},Members:{Quantity:2,Items:[{OriginId:i},{OriginId:s}]},...n.selectionCriteria?{SelectionCriteria:n.selectionCriteria}:{}}}function nn(n,i="the origin group"){if(n===void 0)return;if(!Cm.includes(n))throw Error(`CloudFront origin failover: ${i} has selection criteria ${JSON.stringify(n)}. Allowed: ${Cm.join(", ")}.`)}function st(n,i,s){if(typeof n!=="number"||!Number.isInteger(n)||n<i.min||n>i.max)throw Error(`CloudFront origin: ${s} must be a whole number from ${i.min} to ${i.max}, got ${JSON.stringify(n)}.`)}function ce(n,i="the origin"){let s={};if(n?.connectionAttempts!==void 0)st(n.connectionAttempts,Em,`${i} connectionAttempts`),s.ConnectionAttempts=n.connectionAttempts;if(n?.connectionTimeout!==void 0)st(n.connectionTimeout,vm,`${i} connectionTimeout (seconds)`),s.ConnectionTimeout=n.connectionTimeout;return s}function ln(n){return{Quantity:1,Items:[ll(n)]}}function Dt(n,i="the cache behavior"){let o=(Array.isArray(n)?n:n?.Items??[]).filter((c)=>!bm.includes(c.toUpperCase()));if(o.length>0)throw Error(`CloudFront origin failover: ${i} allows ${o.join(", ")}, but a cache behavior that targets an origin group may only allow ${bm.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Ho(n){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(n)&&!/s3-website/i.test(n)}function je(n){if(!n)return[];if(Array.isArray(n))return n;return n.Items??[]}function Ae(n){return typeof n==="string"?n:void 0}var Cr=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function Pt(n,i="the distribution"){let s=je(n.Origins),o=new Set(s.map((b)=>Ae(b.Id)).filter((b)=>!!b)),c=new Map(s.map((b)=>[Ae(b.Id)??"",b.DomainName])),u=s.some((b)=>Ae(b.Id)===void 0);for(let b of s){let v=Ae(b.Id)??"(unnamed origin)";if(b.ConnectionAttempts!==void 0)st(b.ConnectionAttempts,Em,`${i} origin "${v}" ConnectionAttempts`);if(b.ConnectionTimeout!==void 0)st(b.ConnectionTimeout,vm,`${i} origin "${v}" ConnectionTimeout (seconds)`)}let d=n.OriginGroups,p=je(d);if(d&&!Array.isArray(d)&&d.Quantity!==void 0&&d.Quantity!==p.length)throw Error(`CloudFront origin failover: ${i} OriginGroups.Quantity is ${d.Quantity} but it lists ${p.length} group(s).`);let y=new Set;for(let b of p){let v=Ae(b.Id);if(b.Id===void 0||b.Id==="")throw Error(`CloudFront origin failover: ${i} has an origin group without an Id.`);let A=`${i} origin group "${v??"(intrinsic id)"}"`;if(v){if(y.has(v))throw Error(`CloudFront origin failover: ${i} declares origin group "${v}" twice.`);if(o.has(v))throw Error(`CloudFront origin failover: ${A} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);y.add(v)}let T=b.Members,R=je(T);if(R.length!==2||T?.Quantity!==void 0&&T.Quantity!==R.length)throw Error(`CloudFront origin failover: ${A} must have exactly 2 members (a primary and a secondary), it has ${R.length}${T?.Quantity!==void 0&&T.Quantity!==R.length?` with Quantity ${T.Quantity}`:""}.`);let P=R.map((L)=>Ae(L.OriginId));for(let L of P)if(L&&!o.has(L)&&!u)throw Error(`CloudFront origin failover: ${A} lists member "${L}", which is not an origin of this distribution. Origins: ${[...o].join(", ")||"(none)"}.`);if(P[0]&&P[0]===P[1])throw Error(`CloudFront origin failover: ${A} lists "${P[0]}" as both primary and secondary.`);let I=b.FailoverCriteria?.StatusCodes,M=je(I);if(Qo(M),I?.Quantity!==void 0&&I.Quantity!==M.length)throw Error(`CloudFront origin failover: ${A} FailoverCriteria.StatusCodes.Quantity is ${I.Quantity} but it lists ${M.length} code(s).`);if(nn(b.SelectionCriteria,A),b.SelectionCriteria==="media-quality-based")for(let L of P){let N=L?Ae(c.get(L)):void 0;if(N&&!Cr.test(N))throw Error(`CloudFront origin failover: ${A} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${L}" is ${N}. Use 'default'.`)}}let h=[];if(n.DefaultCacheBehavior)h.push({behavior:n.DefaultCacheBehavior,name:"the default cache behavior"});for(let b of je(n.CacheBehaviors))h.push({behavior:b,name:`the cache behavior for ${JSON.stringify(b.PathPattern)}`});for(let{behavior:b,name:v}of h){let A=Ae(b.TargetOriginId);if(!A)continue;if(y.has(A))Dt(b.AllowedMethods??["GET","HEAD"],`${v} of ${i} (origin group "${A}")`);else if(!o.has(A)&&!u&&p.every((T)=>Ae(T.Id)!==void 0))throw Error(`CloudFront: ${v} of ${i} targets "${A}", which is neither an origin nor an origin group of this distribution.`)}}class Ce{static createDistribution(n){let{slug:i,environment:s,origin:o,customDomain:c,certificateArn:u,errorPages:d,cachePolicy:p,edgeFunctions:y,http3:h=!1,comment:b,failoverOrigin:v}=n,A=r({slug:i,environment:s,resourceType:"cdn"}),T=t(A),R={Id:"DefaultOrigin",DomainName:o.domainName,OriginPath:o.originPath||"",...ce(o,"the CDN origin")},P;if(o.type==="s3"){let M=`${T}OAC`;P={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${A}-oac`,Description:`Origin Access Control for ${A}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},R.OriginAccessControlId=x.Ref(M)}else if(o.type==="alb"||o.type==="custom")R.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let I={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:b||`CDN for ${A}`,DefaultRootObject:"index.html",Origins:[R],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:h?"http2and3":"http2"}}};if(c&&u)I.Properties.DistributionConfig.Aliases=[c],I.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:u,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(d&&d.length>0)I.Properties.DistributionConfig.CustomErrorResponses=d.map((M)=>({ErrorCode:M.errorCode,ResponseCode:M.responseCode,ResponsePagePath:M.responsePagePath}));if(y&&y.length>0)I.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=y.map((M)=>({EventType:M.event,LambdaFunctionARN:M.functionArn}));if(v)Ce.addOriginFailover(I,v);return{distribution:I,originAccessControl:P,logicalId:T}}static addOriginFailover(n,i){let s=n.Properties.DistributionConfig,o=s.DefaultCacheBehavior,c=o.TargetOriginId,u=i.id??"FailoverOrigin";if(s.OriginGroups&&s.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Dt(o.AllowedMethods??["GET","HEAD"],"the default cache behavior"),s.Origins.some((b)=>b.Id===u))throw Error(`CloudFront origin failover: an origin with id "${u}" already exists`);let d=ll({primaryOriginId:c,secondaryOriginId:u,statusCodes:i.statusCodes,selectionCriteria:i.selectionCriteria}),p=i.type??(Ho(i.domainName)?"s3":"custom"),y={Id:u,DomainName:i.domainName,OriginPath:i.originPath||"",...ce(i,"the failover origin")},h=ce(i.primary,"the primary origin");if(Object.keys(h).length>0){let b=s.Origins.find((v)=>v.Id===c);if(b)Object.assign(b,h)}if(p==="s3"){let b=s.Origins.find((v)=>v.Id===c);if(y.S3OriginConfig={OriginAccessIdentity:""},b?.OriginAccessControlId)y.OriginAccessControlId=b.OriginAccessControlId}else y.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return s.Origins.push(y),s.OriginGroups={Quantity:1,Items:[d]},o.TargetOriginId=d.Id,Pt(s),n}static setCustomDomain(n,i,s){return n.Properties.DistributionConfig.Aliases=[i],n.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},n}static setErrorPages(n,i){return n.Properties.DistributionConfig.CustomErrorResponses=i.map((s)=>({ErrorCode:s.errorCode,ResponseCode:s.responseCode,ResponsePagePath:s.responsePagePath})),n}static enableHttp3(n){return n.Properties.DistributionConfig.HttpVersion="http2and3",n}static addEdgeFunction(n,i,s){if(!n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:i,LambdaFunctionARN:s}),n}static setCachePolicy(n,i){return n.Properties.DistributionConfig.Comment=`${n.Properties.DistributionConfig.Comment||""} (TTL: ${i.default||86400}s)`,n}static createSpaDistribution(n){return Ce.createDistribution({...n,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"edge-docs"}),c=t(o),u=t(`${o}-role`),d=t(`${o}-version`),p={Type:"AWS::IAM::Role",Properties:{RoleName:`${o}-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"]}},y=`
|
|
94
|
+
`)}`}};static DockerfileTemplates={bunServer:(n,i=3000)=>Ze.generateBunDockerfile({serverPath:n,port:i}),bunWithBuild:(n,i,s=3000)=>Ze.generateBunDockerfile({serverPath:n,port:s,buildCommands:[i]}),bunFullStack:(n,i=3000)=>Ze.generateBunDockerfile({serverPath:n,port:i,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(n,i=3000)=>Ze.generateBunDockerfile({serverPath:n,port:i,healthCheckEndpoint:"/api/health"})}}var dl=[400,403,404,416,429,500,502,503,504],Im=[500,502,503,504],bm=["GET","HEAD","OPTIONS"],zI="-failover-group",Cm=["default","media-quality-based"],Em={min:1,max:3},vm={min:1,max:10};function Qo(n){if(n===void 0)return[...Im];if(n.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${dl.join(", ")}). Omit it to use the default ${Im.join(", ")}.`);let i=n.filter((s)=>!dl.includes(s));if(i.length>0)throw Error(`CloudFront origin failover: ${i.join(", ")} ${i.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${dl.join(", ")}.`);return[...new Set(n)].sort((s,o)=>s-o)}function ll(n){let{primaryOriginId:i,secondaryOriginId:s}=n;if(!i||!s)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(i===s)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${i}")`);let o=Qo(n.statusCodes);return nn(n.selectionCriteria),{Id:n.groupId??`${i}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:o.length,Items:o}},Members:{Quantity:2,Items:[{OriginId:i},{OriginId:s}]},...n.selectionCriteria?{SelectionCriteria:n.selectionCriteria}:{}}}function nn(n,i="the origin group"){if(n===void 0)return;if(!Cm.includes(n))throw Error(`CloudFront origin failover: ${i} has selection criteria ${JSON.stringify(n)}. Allowed: ${Cm.join(", ")}.`)}function at(n,i,s){if(typeof n!=="number"||!Number.isInteger(n)||n<i.min||n>i.max)throw Error(`CloudFront origin: ${s} must be a whole number from ${i.min} to ${i.max}, got ${JSON.stringify(n)}.`)}function ce(n,i="the origin"){let s={};if(n?.connectionAttempts!==void 0)at(n.connectionAttempts,Em,`${i} connectionAttempts`),s.ConnectionAttempts=n.connectionAttempts;if(n?.connectionTimeout!==void 0)at(n.connectionTimeout,vm,`${i} connectionTimeout (seconds)`),s.ConnectionTimeout=n.connectionTimeout;return s}function ln(n){return{Quantity:1,Items:[ll(n)]}}function Pt(n,i="the cache behavior"){let o=(Array.isArray(n)?n:n?.Items??[]).filter((c)=>!bm.includes(c.toUpperCase()));if(o.length>0)throw Error(`CloudFront origin failover: ${i} allows ${o.join(", ")}, but a cache behavior that targets an origin group may only allow ${bm.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Ho(n){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(n)&&!/s3-website/i.test(n)}function je(n){if(!n)return[];if(Array.isArray(n))return n;return n.Items??[]}function Ae(n){return typeof n==="string"?n:void 0}var Cr=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function kt(n,i="the distribution"){let s=je(n.Origins),o=new Set(s.map((b)=>Ae(b.Id)).filter((b)=>!!b)),c=new Map(s.map((b)=>[Ae(b.Id)??"",b.DomainName])),u=s.some((b)=>Ae(b.Id)===void 0);for(let b of s){let v=Ae(b.Id)??"(unnamed origin)";if(b.ConnectionAttempts!==void 0)at(b.ConnectionAttempts,Em,`${i} origin "${v}" ConnectionAttempts`);if(b.ConnectionTimeout!==void 0)at(b.ConnectionTimeout,vm,`${i} origin "${v}" ConnectionTimeout (seconds)`)}let d=n.OriginGroups,p=je(d);if(d&&!Array.isArray(d)&&d.Quantity!==void 0&&d.Quantity!==p.length)throw Error(`CloudFront origin failover: ${i} OriginGroups.Quantity is ${d.Quantity} but it lists ${p.length} group(s).`);let y=new Set;for(let b of p){let v=Ae(b.Id);if(b.Id===void 0||b.Id==="")throw Error(`CloudFront origin failover: ${i} has an origin group without an Id.`);let A=`${i} origin group "${v??"(intrinsic id)"}"`;if(v){if(y.has(v))throw Error(`CloudFront origin failover: ${i} declares origin group "${v}" twice.`);if(o.has(v))throw Error(`CloudFront origin failover: ${A} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);y.add(v)}let T=b.Members,R=je(T);if(R.length!==2||T?.Quantity!==void 0&&T.Quantity!==R.length)throw Error(`CloudFront origin failover: ${A} must have exactly 2 members (a primary and a secondary), it has ${R.length}${T?.Quantity!==void 0&&T.Quantity!==R.length?` with Quantity ${T.Quantity}`:""}.`);let P=R.map((L)=>Ae(L.OriginId));for(let L of P)if(L&&!o.has(L)&&!u)throw Error(`CloudFront origin failover: ${A} lists member "${L}", which is not an origin of this distribution. Origins: ${[...o].join(", ")||"(none)"}.`);if(P[0]&&P[0]===P[1])throw Error(`CloudFront origin failover: ${A} lists "${P[0]}" as both primary and secondary.`);let I=b.FailoverCriteria?.StatusCodes,M=je(I);if(Qo(M),I?.Quantity!==void 0&&I.Quantity!==M.length)throw Error(`CloudFront origin failover: ${A} FailoverCriteria.StatusCodes.Quantity is ${I.Quantity} but it lists ${M.length} code(s).`);if(nn(b.SelectionCriteria,A),b.SelectionCriteria==="media-quality-based")for(let L of P){let N=L?Ae(c.get(L)):void 0;if(N&&!Cr.test(N))throw Error(`CloudFront origin failover: ${A} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${L}" is ${N}. Use 'default'.`)}}let h=[];if(n.DefaultCacheBehavior)h.push({behavior:n.DefaultCacheBehavior,name:"the default cache behavior"});for(let b of je(n.CacheBehaviors))h.push({behavior:b,name:`the cache behavior for ${JSON.stringify(b.PathPattern)}`});for(let{behavior:b,name:v}of h){let A=Ae(b.TargetOriginId);if(!A)continue;if(y.has(A))Pt(b.AllowedMethods??["GET","HEAD"],`${v} of ${i} (origin group "${A}")`);else if(!o.has(A)&&!u&&p.every((T)=>Ae(T.Id)!==void 0))throw Error(`CloudFront: ${v} of ${i} targets "${A}", which is neither an origin nor an origin group of this distribution.`)}}class Ce{static createDistribution(n){let{slug:i,environment:s,origin:o,customDomain:c,certificateArn:u,errorPages:d,cachePolicy:p,edgeFunctions:y,http3:h=!1,comment:b,failoverOrigin:v}=n,A=r({slug:i,environment:s,resourceType:"cdn"}),T=t(A),R={Id:"DefaultOrigin",DomainName:o.domainName,OriginPath:o.originPath||"",...ce(o,"the CDN origin")},P;if(o.type==="s3"){let M=`${T}OAC`;P={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${A}-oac`,Description:`Origin Access Control for ${A}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},R.OriginAccessControlId=x.Ref(M)}else if(o.type==="alb"||o.type==="custom")R.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let I={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:b||`CDN for ${A}`,DefaultRootObject:"index.html",Origins:[R],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:h?"http2and3":"http2"}}};if(c&&u)I.Properties.DistributionConfig.Aliases=[c],I.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:u,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(d&&d.length>0)I.Properties.DistributionConfig.CustomErrorResponses=d.map((M)=>({ErrorCode:M.errorCode,ResponseCode:M.responseCode,ResponsePagePath:M.responsePagePath}));if(y&&y.length>0)I.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=y.map((M)=>({EventType:M.event,LambdaFunctionARN:M.functionArn}));if(v)Ce.addOriginFailover(I,v);return{distribution:I,originAccessControl:P,logicalId:T}}static addOriginFailover(n,i){let s=n.Properties.DistributionConfig,o=s.DefaultCacheBehavior,c=o.TargetOriginId,u=i.id??"FailoverOrigin";if(s.OriginGroups&&s.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Pt(o.AllowedMethods??["GET","HEAD"],"the default cache behavior"),s.Origins.some((b)=>b.Id===u))throw Error(`CloudFront origin failover: an origin with id "${u}" already exists`);let d=ll({primaryOriginId:c,secondaryOriginId:u,statusCodes:i.statusCodes,selectionCriteria:i.selectionCriteria}),p=i.type??(Ho(i.domainName)?"s3":"custom"),y={Id:u,DomainName:i.domainName,OriginPath:i.originPath||"",...ce(i,"the failover origin")},h=ce(i.primary,"the primary origin");if(Object.keys(h).length>0){let b=s.Origins.find((v)=>v.Id===c);if(b)Object.assign(b,h)}if(p==="s3"){let b=s.Origins.find((v)=>v.Id===c);if(y.S3OriginConfig={OriginAccessIdentity:""},b?.OriginAccessControlId)y.OriginAccessControlId=b.OriginAccessControlId}else y.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return s.Origins.push(y),s.OriginGroups={Quantity:1,Items:[d]},o.TargetOriginId=d.Id,kt(s),n}static setCustomDomain(n,i,s){return n.Properties.DistributionConfig.Aliases=[i],n.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},n}static setErrorPages(n,i){return n.Properties.DistributionConfig.CustomErrorResponses=i.map((s)=>({ErrorCode:s.errorCode,ResponseCode:s.responseCode,ResponsePagePath:s.responsePagePath})),n}static enableHttp3(n){return n.Properties.DistributionConfig.HttpVersion="http2and3",n}static addEdgeFunction(n,i,s){if(!n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:i,LambdaFunctionARN:s}),n}static setCachePolicy(n,i){return n.Properties.DistributionConfig.Comment=`${n.Properties.DistributionConfig.Comment||""} (TTL: ${i.default||86400}s)`,n}static createSpaDistribution(n){return Ce.createDistribution({...n,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"edge-docs"}),c=t(o),u=t(`${o}-role`),d=t(`${o}-version`),p={Type:"AWS::IAM::Role",Properties:{RoleName:`${o}-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"]}},y=`
|
|
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:(n)=>{let{min:i=0,max:s=86400,default:o=86400}=n;return{MinTTL:i,MaxTTL:s,DefaultTTL:o}},cookies:(n,i)=>{let s={Forward:n==="allowList"?"whitelist":n};if(n==="allowList"&&i)s.WhitelistedNames=i;return s},allowedMethods:(n)=>{let i={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.GET_HEAD},cachedMethods:(n)=>{let i={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.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:(n)=>{let{ttl:i={min:0,max:86400,default:86400},cookies:s="none",allowedCookies:o,allowedMethods:c="GET_HEAD",cachedMethods:u="GET_HEAD",compress:d=!0,forwardQueryString:p=!0,forwardHeaders:y=[]}=n;return{MinTTL:i.min,MaxTTL:i.max,DefaultTTL:i.default,Compress:d,AllowedMethods:Ce.Config.allowedMethods(c),CachedMethods:Ce.Config.cachedMethods(u),ForwardedValues:{QueryString:p,Headers:y,Cookies:Ce.Config.cookies(s,o)}}}};static applyConfig(n,i){let s=n.Properties.DistributionConfig.DefaultCacheBehavior;if(i.ttl)s.MinTTL=i.ttl.min,s.MaxTTL=i.ttl.max,s.DefaultTTL=i.ttl.default;if(i.compress!==void 0)s.Compress=i.compress;if(i.allowedMethods)s.AllowedMethods=Ce.Config.allowedMethods(i.allowedMethods);if(i.cachedMethods)s.CachedMethods=Ce.Config.cachedMethods(i.cachedMethods);if(i.cookies){if(!s.ForwardedValues)s.ForwardedValues={QueryString:!0};s.ForwardedValues.Cookies=Ce.Config.cookies(i.cookies,i.allowedCookies)}return n}}var iy=[403,404,500,502,503,504],ul="TsCloud::StorageFailover",Go="AllowCloudFrontFailoverRead",vr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Tr=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function Tm(n){let{failover:i,primaryBucket:s,primaryRegion:o}=n,c=n.where??"storage failover";if(!i||typeof i!=="object")throw Error(`${c}.failover must be an object such as { region: 'us-west-2' }.`);if(!i.region||!vr.test(i.region))throw Error(`${c}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(i.region)}.`);if(i.region===o)throw Error(`${c}.failover.region is ${i.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let u=i.bucket??`${s}-${i.region}`;if(!Tr.test(u)||u.includes("..")){let d=i.bucket===void 0&&u.length>63?` The default name (<primary bucket>-<region>) is ${u.length} characters; S3 allows 63. Set ${c}.failover.bucket.`:"";throw Error(`${c}.failover: "${u}" is not a valid S3 bucket name.${d}`)}if(u===s)throw Error(`${c}.failover.bucket must differ from the primary bucket "${s}".`);return{replicaBucket:u,replicaRegion:i.region,replicate:i.replicate!==!1,statusCodes:Qo(i.statusCodes??iy),primaryConnection:ce(i,`${c}.failover`)}}function wm(n,i){return`${n}.s3.${i}.amazonaws.com`}function Rm(n){let i=`arn:aws:s3:::${n.primaryBucket}`,s=`arn:aws:s3:::${n.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...n.roleName?{RoleName:n.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:i},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${i}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${s}/*`}]}}]}}}function Dm(n){return{Role:n.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${n.replicaBucket}`}}]}}function gl(n){return{Sid:Go,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${n.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":n.distributionArn}}}}function KI(n){let s=(typeof n==="string"?JSON.parse(n):n)?.Metadata?.[ul];return Array.isArray(s)?s:[]}class W{static createHostedZone(n){let{domain:i,slug:s,environment:o,comment:c}=n,u=r({slug:s,environment:o,resourceType:"hostedzone"}),d=t(`${u}-${i.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:i,HostedZoneConfig:{Comment:c||`Hosted zone for ${i}`}}},logicalId:d}}static createRecord(n){let{hostedZoneId:i,hostedZoneName:s,name:o,type:c,ttl:u,values:d,aliasTarget:p}=n,y=t(`record-${o.replace(/\./g,"")}-${c}`),h={Type:"AWS::Route53::RecordSet",Properties:{Name:o,Type:c}};if(i)h.Properties.HostedZoneId=i;else if(s)h.Properties.HostedZoneName=s;if(p)h.Properties.AliasTarget={DNSName:p.dnsName,HostedZoneId:p.hostedZoneId,EvaluateTargetHealth:p.evaluateTargetHealth??!1};else h.Properties.TTL=u||300,h.Properties.ResourceRecords=d||[];return{record:h,logicalId:y}}static createCloudFrontAlias(n,i,s){return W.createRecord({hostedZoneId:s,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(n,i,s,o){return W.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,evaluateTargetHealth:!0}})}static createCname(n,i,s,o=300){return W.createRecord({hostedZoneId:s,name:n,type:"CNAME",ttl:o,values:[i]})}static createWwwRedirect(n,i){return W.createRecord({hostedZoneId:i,name:`www.${n}`,type:"CNAME",ttl:300,values:[n]})}static createMxRecords(n,i,s,o=300){return W.createRecord({hostedZoneId:s,name:n,type:"MX",ttl:o,values:i.map((c)=>`${c.priority} ${c.server}`)})}static createTxtRecord(n,i,s,o=300){return W.createRecord({hostedZoneId:s,name:n,type:"TXT",ttl:o,values:[`"${i}"`]})}static createSpfRecord(n,i,s){return W.createTxtRecord(n,i,s)}static createDmarcRecord(n,i,s,o){let c=`v=DMARC1; p=${i}; rua=mailto:${s}`;return W.createTxtRecord(`_dmarc.${n}`,c,o)}static createS3WebsiteAlias(n,i,s,o){return W.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,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(n,i){return`${n}.s3-website-${i}.amazonaws.com`}static createStoreRecord(n,i,s){return W.createCname(`store.${n}`,i,s)}static createApiRecord(n,i,s){return W.createCname(`api.${n}`,i,s)}static createDocsRecord(n,i,s){return W.createCname(`docs.${n}`,i,s)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class E{static createCertificate(n){let{domain:i,subdomains:s=[],slug:o,environment:c,validationMethod:u="DNS",hostedZoneId:d}=n,p=r({slug:o,environment:c,resourceType:"acm"}),y=t(`${p}-${i.replace(/\./g,"")}`),h=[i];for(let v of s)if(v==="*")h.push(`*.${i}`);else h.push(`${v}.${i}`);let b={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i,SubjectAlternativeNames:h,ValidationMethod:u}};if(u==="DNS"&&d)b.Properties.DomainValidationOptions=h.map((v)=>({DomainName:v,HostedZoneId:d}));return{certificate:b,logicalId:y}}static createKmsKey(n){let{description:i,slug:s,environment:o,enableRotation:c=!0,multiRegion:u=!1}=n,d=r({slug:s,environment:o,resourceType:"kms"}),p=t(d),y={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:x.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:"*"}]},h={Type:"AWS::KMS::Key",Properties:{Description:i,Enabled:!0,EnableKeyRotation:c,KeyPolicy:y,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:u}},b=t(`${d}-alias`),v={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${s}-${o}`,TargetKeyId:x.Ref(p)}};return{key:h,alias:v,logicalId:p,aliasId:b}}static createFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",defaultAction:c="allow"}=n,u=r({slug:i,environment:s,resourceType:"waf"}),d=t(u);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:u,Scope:o,DefaultAction:c==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${i} ${s}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${u}-metric`}}},logicalId:d}}static setRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockCountries(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{GeoMatchStatement:{CountryCodes:i.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockIpAddresses(n,i,s,o){let c=r({slug:s,environment:o,resourceType:"ipset"}),u=t(`${c}-${i.name}`),d={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${c}-${i.name}`,Scope:n.Properties.Scope,IPAddressVersion:i.ipVersion||"IPV4",Addresses:i.ipAddresses,Description:`Blocked IPs for ${i.name}`}};if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{IPSetReferenceStatement:{Arn:x.GetAtt(u,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),{webAcl:n,ipSet:d,ipSetLogicalId:u}}static addManagedRules(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={ManagedRuleGroupStatement:{VendorName:i.vendorName,Name:i.ruleName}};if(i.excludedRules&&i.excludedRules.length>0)s.ManagedRuleGroupStatement.ExcludedRules=i.excludedRules.map((o)=>({Name:o}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}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(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s=i.paths.map((o)=>({SearchString:o,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:s.map((o)=>({ByteMatchStatement:o}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static setHeaderRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:i.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(i.headerValue)s.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:i.headerValue,FieldToMatch:{SingleHeader:{Name:i.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static protectLoginEndpoint(n,i){let{loginPaths:s,priority:o,requestsPerMinute:c=10}=i;return E.setPathRateLimit(n,{name:"LoginRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static protectApiEndpoints(n,i){let{apiPaths:s,priority:o,requestsPerMinute:c=100}=i;return E.setPathRateLimit(n,{name:"ApiRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static createProtectedFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",enableBotControl:c=!1,enableRateLimiting:u=!0,rateLimitPerMinute:d=2000}=n,{webAcl:p,logicalId:y}=E.createFirewall({slug:i,environment:s,scope:o,defaultAction:"allow"}),h=0;if(p=E.addManagedRules(p,{name:"AWSIPReputationList",priority:h++,...E.ManagedRuleGroups.AmazonIpReputation}),p=E.addManagedRules(p,{name:"AWSAnonymousIPList",priority:h++,...E.ManagedRuleGroups.AnonymousIpList}),p=E.addManagedRules(p,{name:"AWSCoreRuleSet",priority:h++,...E.ManagedRuleGroups.CoreRuleSet}),p=E.addManagedRules(p,{name:"AWSKnownBadInputs",priority:h++,...E.ManagedRuleGroups.KnownBadInputs}),p=E.addManagedRules(p,{name:"AWSSQLi",priority:h++,...E.ManagedRuleGroups.SqlDatabase}),c)p=E.addManagedRules(p,{name:"AWSBotControl",priority:h++,...E.ManagedRuleGroups.BotControl});if(u)p=E.setRateLimit(p,{name:"GlobalRateLimit",priority:h++,requestsPerWindow:d*5});return{webAcl:p,logicalId:y}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function sy(n){let i=n.split(".")[0]??"";return i==="a1"||/^[a-z]+\d+g[a-z]*$/.test(i)}function oy(n="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${sy(n)?"arm64":"x86_64"}`}function Pm(n="t3.micro"){return`{{resolve:ssm:${oy(n)}}}`}class a{static createServer(n){let{slug:i,environment:s,instanceType:o="t3.micro",imageId:c=Pm(o),keyName:u,securityGroupIds:d,subnetId:p,userData:y,volumeSize:h=20,volumeType:b="gp3",encrypted:v=!0}=n,A=r({slug:i,environment:s,resourceType:"ec2"}),T=t(A),R={Type:"AWS::EC2::Instance",Properties:{ImageId:c,InstanceType:o,Tags:[{Key:"Name",Value:A},{Key:"Environment",Value:s}]}};if(u)R.Properties.KeyName=u;if(d)R.Properties.SecurityGroupIds=d;if(p)R.Properties.SubnetId=p;if(y)R.Properties.UserData=x.Base64(y);return R.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:h,VolumeType:b,Encrypted:v,DeleteOnTermination:!0}}],{instance:R,logicalId:T}}static createSecurityGroup(n){let{slug:i,environment:s,vpcId:o,description:c,ingress:u=[],egress:d=[]}=n,p=r({slug:i,environment:s,resourceType:"sg"}),y=t(p),h={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:c||`Security group for ${i} ${s}`,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(o)h.Properties.VpcId=o;if(u.length>0)h.Properties.SecurityGroupIngress=u.map((b)=>({IpProtocol:b.protocol,FromPort:b.fromPort,ToPort:b.toPort,CidrIp:b.cidr,SourceSecurityGroupId:b.sourceSecurityGroupId}));if(d.length>0)h.Properties.SecurityGroupEgress=d.map((b)=>({IpProtocol:b.protocol,FromPort:b.fromPort,ToPort:b.toPort,CidrIp:b.cidr,DestinationSecurityGroupId:b.sourceSecurityGroupId}));return{securityGroup:h,logicalId:y}}static createWebServerSecurityGroup(n,i,s){return a.createSecurityGroup({slug:n,environment:i,vpcId:s,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(n){let{slug:i,environment:s,scheme:o="internet-facing",subnets:c,securityGroups:u,type:d="application"}=n,p=r({slug:i,environment:s,resourceType:"alb"}),y=t(p),h={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:p,Scheme:o,Type:d,Subnets:c,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(u)h.Properties.SecurityGroups=u;return{loadBalancer:h,logicalId:y}}static createTargetGroup(n){let{slug:i,environment:s,port:o,protocol:c="HTTP",vpcId:u,targetType:d="ip",healthCheckPath:p="/",healthCheckInterval:y=30,healthCheckTimeout:h=5,healthyThreshold:b=2,unhealthyThreshold:v=3}=n,A=r({slug:i,environment:s,resourceType:"tg"}),T=t(A);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:A,Port:o,Protocol:c,VpcId:u,TargetType:d,HealthCheckEnabled:!0,HealthCheckProtocol:c,HealthCheckPath:p,HealthCheckIntervalSeconds:y,HealthCheckTimeoutSeconds:h,HealthyThresholdCount:b,UnhealthyThresholdCount:v,Tags:[{Key:"Name",Value:A},{Key:"Environment",Value:s}]}},logicalId:T}}static createListener(n,i){let{port:s,protocol:o="HTTP",certificateArn:c,defaultTargetGroupArn:u}=i,d=t(`listener-${n}-${s}`),p={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:x.Ref(n),Port:s,Protocol:o,DefaultActions:[{Type:"forward",TargetGroupArn:u}]}};if(o==="HTTPS"&&c)p.Properties.Certificates=[{CertificateArn:c}],p.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:p,logicalId:d}}static createEcsCluster(n,i){let s=r({slug:n,environment:i,resourceType:"ecs-cluster"}),o=t(s);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:s,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createFargateService(n){let{slug:i,environment:s,image:o,cpu:c="256",memory:u="512",desiredCount:d=1,containerPort:p=8080,environmentVariables:y={},secrets:h=[],healthCheck:b,logGroup:v,subnets:A,securityGroups:T,targetGroupArn:R}=n,{cluster:P,logicalId:I}=a.createEcsCluster(i,s),M=r({slug:i,environment:s,resourceType:"fargate"}),L=t(`${M}-execution-role`),N={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"]}},O=t(`${M}-task-role`),B={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},F=t(`${M}-task`),U={Type:"AWS::ECS::TaskDefinition",Properties:{Family:M,TaskRoleArn:x.GetAtt(O,"Arn"),ExecutionRoleArn:x.GetAtt(L,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:c,Memory:u,ContainerDefinitions:[{Name:i,Image:o,Essential:!0,PortMappings:[{ContainerPort:p,Protocol:"tcp"}],Environment:Object.entries(y).map(([z,ae])=>({Name:z,Value:ae})),Secrets:h.map((z)=>({Name:z.name,ValueFrom:z.valueFrom}))}],Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:s}]}};if(b)U.Properties.ContainerDefinitions[0].HealthCheck={Command:b.command,Interval:b.interval||30,Timeout:b.timeout||5,Retries:b.retries||3,StartPeriod:60};if(v)U.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":v,"awslogs-region":x.Ref("AWS::Region"),"awslogs-stream-prefix":i}};let j=t(`${M}-service`),H={Type:"AWS::ECS::Service",Properties:{ServiceName:M,Cluster:x.Ref(I),TaskDefinition:x.Ref(F),DesiredCount:d,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:A,SecurityGroups:T,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:s}]}};if(R)H.Properties.LoadBalancers=[{TargetGroupArn:R,ContainerName:i,ContainerPort:p}];return{cluster:P,taskDefinition:U,service:H,taskRole:B,executionRole:N,clusterLogicalId:I,taskDefinitionLogicalId:F,serviceLogicalId:j,taskRoleLogicalId:O,executionRoleLogicalId:L}}static createLambdaFunction(n){let{slug:i,environment:s,runtime:o,handler:c,code:u,timeout:d=30,memorySize:p=128,environmentVariables:y={},vpcConfig:h}=n,b=r({slug:i,environment:s,resourceType:"lambda"}),v=t(b),A=t(`${b}-role`),T={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(h)T.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let R={Type:"AWS::Lambda::Function",Properties:{FunctionName:b,Runtime:o,Role:x.GetAtt(A,"Arn"),Handler:c,Code:{...u.s3Bucket&&{S3Bucket:u.s3Bucket},...u.s3Key&&{S3Key:u.s3Key},...u.zipFile&&{ZipFile:u.zipFile}},Timeout:d,MemorySize:p,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s}]}};if(Object.keys(y).length>0)R.Properties.Environment={Variables:y};if(h)R.Properties.VpcConfig={SecurityGroupIds:h.securityGroupIds,SubnetIds:h.subnetIds};return{lambdaFunction:R,role:T,logicalId:v,roleLogicalId:A}}static generateNodeServerUserData(n={}){let{nodeVersion:i="20",appRepo:s,environment:o={}}=n,c=Object.entries(o).map(([u,d])=>`echo "export ${u}='${d}'" >> /etc/environment`).join(`
|
|
200
|
+
`.trim()};static Config={ttl:(n)=>{let{min:i=0,max:s=86400,default:o=86400}=n;return{MinTTL:i,MaxTTL:s,DefaultTTL:o}},cookies:(n,i)=>{let s={Forward:n==="allowList"?"whitelist":n};if(n==="allowList"&&i)s.WhitelistedNames=i;return s},allowedMethods:(n)=>{let i={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.GET_HEAD},cachedMethods:(n)=>{let i={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.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:(n)=>{let{ttl:i={min:0,max:86400,default:86400},cookies:s="none",allowedCookies:o,allowedMethods:c="GET_HEAD",cachedMethods:u="GET_HEAD",compress:d=!0,forwardQueryString:p=!0,forwardHeaders:y=[]}=n;return{MinTTL:i.min,MaxTTL:i.max,DefaultTTL:i.default,Compress:d,AllowedMethods:Ce.Config.allowedMethods(c),CachedMethods:Ce.Config.cachedMethods(u),ForwardedValues:{QueryString:p,Headers:y,Cookies:Ce.Config.cookies(s,o)}}}};static applyConfig(n,i){let s=n.Properties.DistributionConfig.DefaultCacheBehavior;if(i.ttl)s.MinTTL=i.ttl.min,s.MaxTTL=i.ttl.max,s.DefaultTTL=i.ttl.default;if(i.compress!==void 0)s.Compress=i.compress;if(i.allowedMethods)s.AllowedMethods=Ce.Config.allowedMethods(i.allowedMethods);if(i.cachedMethods)s.CachedMethods=Ce.Config.cachedMethods(i.cachedMethods);if(i.cookies){if(!s.ForwardedValues)s.ForwardedValues={QueryString:!0};s.ForwardedValues.Cookies=Ce.Config.cookies(i.cookies,i.allowedCookies)}return n}}var iy=[403,404,500,502,503,504],ul="TsCloud::StorageFailover",Go="AllowCloudFrontFailoverRead",vr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Tr=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function Tm(n){let{failover:i,primaryBucket:s,primaryRegion:o}=n,c=n.where??"storage failover";if(!i||typeof i!=="object")throw Error(`${c}.failover must be an object such as { region: 'us-west-2' }.`);if(!i.region||!vr.test(i.region))throw Error(`${c}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(i.region)}.`);if(i.region===o)throw Error(`${c}.failover.region is ${i.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let u=i.bucket??`${s}-${i.region}`;if(!Tr.test(u)||u.includes("..")){let d=i.bucket===void 0&&u.length>63?` The default name (<primary bucket>-<region>) is ${u.length} characters; S3 allows 63. Set ${c}.failover.bucket.`:"";throw Error(`${c}.failover: "${u}" is not a valid S3 bucket name.${d}`)}if(u===s)throw Error(`${c}.failover.bucket must differ from the primary bucket "${s}".`);return{replicaBucket:u,replicaRegion:i.region,replicate:i.replicate!==!1,statusCodes:Qo(i.statusCodes??iy),primaryConnection:ce(i,`${c}.failover`)}}function wm(n,i){return`${n}.s3.${i}.amazonaws.com`}function Rm(n){let i=`arn:aws:s3:::${n.primaryBucket}`,s=`arn:aws:s3:::${n.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...n.roleName?{RoleName:n.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:i},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${i}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${s}/*`}]}}]}}}function Dm(n){return{Role:n.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${n.replicaBucket}`}}]}}function gl(n){return{Sid:Go,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${n.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":n.distributionArn}}}}function KI(n){let s=(typeof n==="string"?JSON.parse(n):n)?.Metadata?.[ul];return Array.isArray(s)?s:[]}class W{static createHostedZone(n){let{domain:i,slug:s,environment:o,comment:c}=n,u=r({slug:s,environment:o,resourceType:"hostedzone"}),d=t(`${u}-${i.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:i,HostedZoneConfig:{Comment:c||`Hosted zone for ${i}`}}},logicalId:d}}static createRecord(n){let{hostedZoneId:i,hostedZoneName:s,name:o,type:c,ttl:u,values:d,aliasTarget:p}=n,y=t(`record-${o.replace(/\./g,"")}-${c}`),h={Type:"AWS::Route53::RecordSet",Properties:{Name:o,Type:c}};if(i)h.Properties.HostedZoneId=i;else if(s)h.Properties.HostedZoneName=s;if(p)h.Properties.AliasTarget={DNSName:p.dnsName,HostedZoneId:p.hostedZoneId,EvaluateTargetHealth:p.evaluateTargetHealth??!1};else h.Properties.TTL=u||300,h.Properties.ResourceRecords=d||[];return{record:h,logicalId:y}}static createCloudFrontAlias(n,i,s){return W.createRecord({hostedZoneId:s,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(n,i,s,o){return W.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,evaluateTargetHealth:!0}})}static createCname(n,i,s,o=300){return W.createRecord({hostedZoneId:s,name:n,type:"CNAME",ttl:o,values:[i]})}static createWwwRedirect(n,i){return W.createRecord({hostedZoneId:i,name:`www.${n}`,type:"CNAME",ttl:300,values:[n]})}static createMxRecords(n,i,s,o=300){return W.createRecord({hostedZoneId:s,name:n,type:"MX",ttl:o,values:i.map((c)=>`${c.priority} ${c.server}`)})}static createTxtRecord(n,i,s,o=300){return W.createRecord({hostedZoneId:s,name:n,type:"TXT",ttl:o,values:[`"${i}"`]})}static createSpfRecord(n,i,s){return W.createTxtRecord(n,i,s)}static createDmarcRecord(n,i,s,o){let c=`v=DMARC1; p=${i}; rua=mailto:${s}`;return W.createTxtRecord(`_dmarc.${n}`,c,o)}static createS3WebsiteAlias(n,i,s,o){return W.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,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(n,i){return`${n}.s3-website-${i}.amazonaws.com`}static createStoreRecord(n,i,s){return W.createCname(`store.${n}`,i,s)}static createApiRecord(n,i,s){return W.createCname(`api.${n}`,i,s)}static createDocsRecord(n,i,s){return W.createCname(`docs.${n}`,i,s)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class E{static createCertificate(n){let{domain:i,subdomains:s=[],slug:o,environment:c,validationMethod:u="DNS",hostedZoneId:d}=n,p=r({slug:o,environment:c,resourceType:"acm"}),y=t(`${p}-${i.replace(/\./g,"")}`),h=[i];for(let v of s)if(v==="*")h.push(`*.${i}`);else h.push(`${v}.${i}`);let b={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i,SubjectAlternativeNames:h,ValidationMethod:u}};if(u==="DNS"&&d)b.Properties.DomainValidationOptions=h.map((v)=>({DomainName:v,HostedZoneId:d}));return{certificate:b,logicalId:y}}static createKmsKey(n){let{description:i,slug:s,environment:o,enableRotation:c=!0,multiRegion:u=!1}=n,d=r({slug:s,environment:o,resourceType:"kms"}),p=t(d),y={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:x.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:"*"}]},h={Type:"AWS::KMS::Key",Properties:{Description:i,Enabled:!0,EnableKeyRotation:c,KeyPolicy:y,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:u}},b=t(`${d}-alias`),v={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${s}-${o}`,TargetKeyId:x.Ref(p)}};return{key:h,alias:v,logicalId:p,aliasId:b}}static createFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",defaultAction:c="allow"}=n,u=r({slug:i,environment:s,resourceType:"waf"}),d=t(u);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:u,Scope:o,DefaultAction:c==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${i} ${s}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${u}-metric`}}},logicalId:d}}static setRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockCountries(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{GeoMatchStatement:{CountryCodes:i.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockIpAddresses(n,i,s,o){let c=r({slug:s,environment:o,resourceType:"ipset"}),u=t(`${c}-${i.name}`),d={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${c}-${i.name}`,Scope:n.Properties.Scope,IPAddressVersion:i.ipVersion||"IPV4",Addresses:i.ipAddresses,Description:`Blocked IPs for ${i.name}`}};if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{IPSetReferenceStatement:{Arn:x.GetAtt(u,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),{webAcl:n,ipSet:d,ipSetLogicalId:u}}static addManagedRules(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={ManagedRuleGroupStatement:{VendorName:i.vendorName,Name:i.ruleName}};if(i.excludedRules&&i.excludedRules.length>0)s.ManagedRuleGroupStatement.ExcludedRules=i.excludedRules.map((o)=>({Name:o}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}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(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s=i.paths.map((o)=>({SearchString:o,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:s.map((o)=>({ByteMatchStatement:o}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static setHeaderRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:i.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(i.headerValue)s.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:i.headerValue,FieldToMatch:{SingleHeader:{Name:i.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static protectLoginEndpoint(n,i){let{loginPaths:s,priority:o,requestsPerMinute:c=10}=i;return E.setPathRateLimit(n,{name:"LoginRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static protectApiEndpoints(n,i){let{apiPaths:s,priority:o,requestsPerMinute:c=100}=i;return E.setPathRateLimit(n,{name:"ApiRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static createProtectedFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",enableBotControl:c=!1,enableRateLimiting:u=!0,rateLimitPerMinute:d=2000}=n,{webAcl:p,logicalId:y}=E.createFirewall({slug:i,environment:s,scope:o,defaultAction:"allow"}),h=0;if(p=E.addManagedRules(p,{name:"AWSIPReputationList",priority:h++,...E.ManagedRuleGroups.AmazonIpReputation}),p=E.addManagedRules(p,{name:"AWSAnonymousIPList",priority:h++,...E.ManagedRuleGroups.AnonymousIpList}),p=E.addManagedRules(p,{name:"AWSCoreRuleSet",priority:h++,...E.ManagedRuleGroups.CoreRuleSet}),p=E.addManagedRules(p,{name:"AWSKnownBadInputs",priority:h++,...E.ManagedRuleGroups.KnownBadInputs}),p=E.addManagedRules(p,{name:"AWSSQLi",priority:h++,...E.ManagedRuleGroups.SqlDatabase}),c)p=E.addManagedRules(p,{name:"AWSBotControl",priority:h++,...E.ManagedRuleGroups.BotControl});if(u)p=E.setRateLimit(p,{name:"GlobalRateLimit",priority:h++,requestsPerWindow:d*5});return{webAcl:p,logicalId:y}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function sy(n){let i=n.split(".")[0]??"";return i==="a1"||/^[a-z]+\d+g[a-z]*$/.test(i)}function oy(n="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${sy(n)?"arm64":"x86_64"}`}function Pm(n="t3.micro"){return`{{resolve:ssm:${oy(n)}}}`}class a{static createServer(n){let{slug:i,environment:s,instanceType:o="t3.micro",imageId:c=Pm(o),keyName:u,securityGroupIds:d,subnetId:p,userData:y,volumeSize:h=20,volumeType:b="gp3",encrypted:v=!0}=n,A=r({slug:i,environment:s,resourceType:"ec2"}),T=t(A),R={Type:"AWS::EC2::Instance",Properties:{ImageId:c,InstanceType:o,Tags:[{Key:"Name",Value:A},{Key:"Environment",Value:s}]}};if(u)R.Properties.KeyName=u;if(d)R.Properties.SecurityGroupIds=d;if(p)R.Properties.SubnetId=p;if(y)R.Properties.UserData=x.Base64(y);return R.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:h,VolumeType:b,Encrypted:v,DeleteOnTermination:!0}}],{instance:R,logicalId:T}}static createSecurityGroup(n){let{slug:i,environment:s,vpcId:o,description:c,ingress:u=[],egress:d=[]}=n,p=r({slug:i,environment:s,resourceType:"sg"}),y=t(p),h={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:c||`Security group for ${i} ${s}`,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(o)h.Properties.VpcId=o;if(u.length>0)h.Properties.SecurityGroupIngress=u.map((b)=>({IpProtocol:b.protocol,FromPort:b.fromPort,ToPort:b.toPort,CidrIp:b.cidr,SourceSecurityGroupId:b.sourceSecurityGroupId}));if(d.length>0)h.Properties.SecurityGroupEgress=d.map((b)=>({IpProtocol:b.protocol,FromPort:b.fromPort,ToPort:b.toPort,CidrIp:b.cidr,DestinationSecurityGroupId:b.sourceSecurityGroupId}));return{securityGroup:h,logicalId:y}}static createWebServerSecurityGroup(n,i,s){return a.createSecurityGroup({slug:n,environment:i,vpcId:s,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(n){let{slug:i,environment:s,scheme:o="internet-facing",subnets:c,securityGroups:u,type:d="application"}=n,p=r({slug:i,environment:s,resourceType:"alb"}),y=t(p),h={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:p,Scheme:o,Type:d,Subnets:c,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(u)h.Properties.SecurityGroups=u;return{loadBalancer:h,logicalId:y}}static createTargetGroup(n){let{slug:i,environment:s,port:o,protocol:c="HTTP",vpcId:u,targetType:d="ip",healthCheckPath:p="/",healthCheckInterval:y=30,healthCheckTimeout:h=5,healthyThreshold:b=2,unhealthyThreshold:v=3}=n,A=r({slug:i,environment:s,resourceType:"tg"}),T=t(A);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:A,Port:o,Protocol:c,VpcId:u,TargetType:d,HealthCheckEnabled:!0,HealthCheckProtocol:c,HealthCheckPath:p,HealthCheckIntervalSeconds:y,HealthCheckTimeoutSeconds:h,HealthyThresholdCount:b,UnhealthyThresholdCount:v,Tags:[{Key:"Name",Value:A},{Key:"Environment",Value:s}]}},logicalId:T}}static createListener(n,i){let{port:s,protocol:o="HTTP",certificateArn:c,defaultTargetGroupArn:u}=i,d=t(`listener-${n}-${s}`),p={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:x.Ref(n),Port:s,Protocol:o,DefaultActions:[{Type:"forward",TargetGroupArn:u}]}};if(o==="HTTPS"&&c)p.Properties.Certificates=[{CertificateArn:c}],p.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:p,logicalId:d}}static createEcsCluster(n,i){let s=r({slug:n,environment:i,resourceType:"ecs-cluster"}),o=t(s);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:s,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createFargateService(n){let{slug:i,environment:s,image:o,cpu:c="256",memory:u="512",desiredCount:d=1,containerPort:p=8080,environmentVariables:y={},secrets:h=[],healthCheck:b,logGroup:v,subnets:A,securityGroups:T,targetGroupArn:R}=n,{cluster:P,logicalId:I}=a.createEcsCluster(i,s),M=r({slug:i,environment:s,resourceType:"fargate"}),L=t(`${M}-execution-role`),N={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"]}},O=t(`${M}-task-role`),B={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},F=t(`${M}-task`),U={Type:"AWS::ECS::TaskDefinition",Properties:{Family:M,TaskRoleArn:x.GetAtt(O,"Arn"),ExecutionRoleArn:x.GetAtt(L,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:c,Memory:u,ContainerDefinitions:[{Name:i,Image:o,Essential:!0,PortMappings:[{ContainerPort:p,Protocol:"tcp"}],Environment:Object.entries(y).map(([z,se])=>({Name:z,Value:se})),Secrets:h.map((z)=>({Name:z.name,ValueFrom:z.valueFrom}))}],Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:s}]}};if(b)U.Properties.ContainerDefinitions[0].HealthCheck={Command:b.command,Interval:b.interval||30,Timeout:b.timeout||5,Retries:b.retries||3,StartPeriod:60};if(v)U.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":v,"awslogs-region":x.Ref("AWS::Region"),"awslogs-stream-prefix":i}};let j=t(`${M}-service`),H={Type:"AWS::ECS::Service",Properties:{ServiceName:M,Cluster:x.Ref(I),TaskDefinition:x.Ref(F),DesiredCount:d,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:A,SecurityGroups:T,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:s}]}};if(R)H.Properties.LoadBalancers=[{TargetGroupArn:R,ContainerName:i,ContainerPort:p}];return{cluster:P,taskDefinition:U,service:H,taskRole:B,executionRole:N,clusterLogicalId:I,taskDefinitionLogicalId:F,serviceLogicalId:j,taskRoleLogicalId:O,executionRoleLogicalId:L}}static createLambdaFunction(n){let{slug:i,environment:s,runtime:o,handler:c,code:u,timeout:d=30,memorySize:p=128,environmentVariables:y={},vpcConfig:h}=n,b=r({slug:i,environment:s,resourceType:"lambda"}),v=t(b),A=t(`${b}-role`),T={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(h)T.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let R={Type:"AWS::Lambda::Function",Properties:{FunctionName:b,Runtime:o,Role:x.GetAtt(A,"Arn"),Handler:c,Code:{...u.s3Bucket&&{S3Bucket:u.s3Bucket},...u.s3Key&&{S3Key:u.s3Key},...u.zipFile&&{ZipFile:u.zipFile}},Timeout:d,MemorySize:p,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s}]}};if(Object.keys(y).length>0)R.Properties.Environment={Variables:y};if(h)R.Properties.VpcConfig={SecurityGroupIds:h.securityGroupIds,SubnetIds:h.subnetIds};return{lambdaFunction:R,role:T,logicalId:v,roleLogicalId:A}}static generateNodeServerUserData(n={}){let{nodeVersion:i="20",appRepo:s,environment:o={}}=n,c=Object.entries(o).map(([u,d])=>`echo "export ${u}='${d}'" >> /etc/environment`).join(`
|
|
201
201
|
`);return`#!/bin/bash
|
|
202
202
|
# Update system
|
|
203
203
|
yum update -y
|
|
@@ -569,7 +569,7 @@ ufw default allow outgoing
|
|
|
569
569
|
${n.map((i)=>`ufw allow ${i}`).join(`
|
|
570
570
|
`)}
|
|
571
571
|
ufw --force enable
|
|
572
|
-
`},Presets:{bunWithNginx:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:n,appPort:i,enableSsl:!0}),bunWithCaddy:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:n,appPort:i,enableSsl:!1}),nodeWithPm2:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:n,appPort:i,enableSsl:!0}),worker:(n="bun")=>a.UserData.generateAppServerScript({runtime:n,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(n){let{slug:i,environment:s,domain:o,instanceLogicalId:c}=n,u=r({slug:i,environment:s,resourceType:"eip"}),d=t(u),p={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s},...o?[{Key:"Domain",Value:o}]:[]]}},y={[d]:p},h,b;if(c)b=t(`${u}-assoc`),h={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:x.GetAtt(d,"AllocationId"),InstanceId:x.Ref(c)}},y[b]=h;return{eip:p,eipAssociation:h,eipLogicalId:d,associationLogicalId:b,resources:y}}static createServerModeStack(n){let{slug:i,environment:s,vpcId:o,subnetId:c,instanceType:u="t3.small",imageId:d="ami-0f3caa1cf4417e51b",keyName:p,domain:y,userData:h,allowedPorts:b=[22,80,443],volumeSize:v=20,volumeType:A="gp3"}=n,T={},R=r({slug:i,environment:s,resourceType:"server-sg"}),P=t(R),I={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:R,GroupDescription:`Security group for ${i} server`,VpcId:o,SecurityGroupIngress:b.map((
|
|
572
|
+
`},Presets:{bunWithNginx:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:n,appPort:i,enableSsl:!0}),bunWithCaddy:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:n,appPort:i,enableSsl:!1}),nodeWithPm2:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:n,appPort:i,enableSsl:!0}),worker:(n="bun")=>a.UserData.generateAppServerScript({runtime:n,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(n){let{slug:i,environment:s,domain:o,instanceLogicalId:c}=n,u=r({slug:i,environment:s,resourceType:"eip"}),d=t(u),p={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s},...o?[{Key:"Domain",Value:o}]:[]]}},y={[d]:p},h,b;if(c)b=t(`${u}-assoc`),h={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:x.GetAtt(d,"AllocationId"),InstanceId:x.Ref(c)}},y[b]=h;return{eip:p,eipAssociation:h,eipLogicalId:d,associationLogicalId:b,resources:y}}static createServerModeStack(n){let{slug:i,environment:s,vpcId:o,subnetId:c,instanceType:u="t3.small",imageId:d="ami-0f3caa1cf4417e51b",keyName:p,domain:y,userData:h,allowedPorts:b=[22,80,443],volumeSize:v=20,volumeType:A="gp3"}=n,T={},R=r({slug:i,environment:s,resourceType:"server-sg"}),P=t(R),I={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:R,GroupDescription:`Security group for ${i} server`,VpcId:o,SecurityGroupIngress:b.map((ae)=>({IpProtocol:"tcp",FromPort:ae,ToPort:ae,CidrIp:"0.0.0.0/0",Description:`Port ${ae}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:s}]}};T[P]=I;let M=r({slug:i,environment:s,resourceType:"server-role"}),L=t(M),N={Type:"AWS::IAM::Role",Properties:{RoleName:M,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Policies:[{PolicyName:"StacksServerPermissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:SendBulkEmail","ses:VerifyDomainIdentity","ses:VerifyDomainDkim","ses:GetIdentityDkimAttributes","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["route53:ChangeResourceRecordSets","route53:ListResourceRecordSets","route53:GetHostedZone"],Resource:"*"},{Effect:"Allow",Action:["ssm:GetParameter","ssm:GetParameters"],Resource:"*"}]}}]}};T[L]=N;let O=r({slug:i,environment:s,resourceType:"server-profile"}),B=t(O),F={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:O,Roles:[x.Ref(L)]}};T[B]=F;let U=r({slug:i,environment:s,resourceType:"server"}),j=t(U),H={Type:"AWS::EC2::Instance",DependsOn:[B],Properties:{ImageId:d,InstanceType:u,KeyName:p,SubnetId:c,SecurityGroupIds:[x.Ref(P)],IamInstanceProfile:x.Ref(B),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:v,VolumeType:A,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:U},{Key:"Environment",Value:s},...y?[{Key:"Domain",Value:y}]:[]]}};if(h)H.Properties.UserData=x.Base64(h);T[j]=H;let{eip:z,eipAssociation:se,eipLogicalId:Te,associationLogicalId:oe,resources:pe}=a.createElasticIp({slug:i,environment:s,domain:y,instanceLogicalId:j});return Object.assign(T,pe),{instance:H,securityGroup:I,eip:z,eipAssociation:se,instanceRole:N,instanceProfile:F,resources:T,outputs:{instanceLogicalId:j,securityGroupLogicalId:P,eipLogicalId:Te,associationLogicalId:oe,roleLogicalId:L,profileLogicalId:B}}}static ServerMode={webServer:(n)=>{let i=a.UserData.generateAppServerScript({runtime:n.runtime||"bun",webServer:n.webServer||"nginx",domain:n.domain,enableSsl:!0});return a.createServerModeStack({...n,userData:i,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(n)=>{let i=a.UserData.generateAppServerScript({runtime:n.runtime||"bun",webServer:"none",installRedis:n.installRedis});return a.createServerModeStack({...n,userData:i,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(n)=>a.createServerModeStack({...n,userData:`#!/bin/bash
|
|
573
573
|
set -e
|
|
574
574
|
apt-get update && apt-get upgrade -y
|
|
575
575
|
apt-get install -y redis-server
|
|
@@ -577,7 +577,7 @@ sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
|
|
|
577
577
|
systemctl enable redis-server
|
|
578
578
|
systemctl restart redis-server
|
|
579
579
|
echo "Redis server setup complete!"
|
|
580
|
-
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class S{static createVpc(n){let{slug:i,environment:s,cidr:o="10.0.0.0/16",enableDnsHostnames:c=!0,enableDnsSupport:u=!0}=n,d=r({slug:i,environment:s,resourceType:"vpc"}),p=t(d);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:o,EnableDnsHostnames:c,EnableDnsSupport:u,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:s}]}},logicalId:p}}static createSubnet(n){let{slug:i,environment:s,vpcId:o,type:c,cidr:u,availabilityZone:d,mapPublicIp:p=c==="public"}=n,y=r({slug:i,environment:s,resourceType:`subnet-${c}`}),h=t(`${y}-${d}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:o,CidrBlock:u,AvailabilityZone:d,MapPublicIpOnLaunch:p,Tags:[{Key:"Name",Value:`${y}-${d}`},{Key:"Environment",Value:s},{Key:"Type",Value:c}]}},logicalId:h}}static createInternetGateway(n,i){let s=r({slug:n,environment:i,resourceType:"igw"}),o=t(s);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static attachInternetGateway(n,i){let s=t(`${n}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:x.Ref(n),InternetGatewayId:x.Ref(i)}},logicalId:s}}static createEip(n,i){let s=r({slug:n,environment:i,resourceType:"eip"}),o=t(s);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createNatGateway(n,i){let{slug:s,environment:o,subnetId:c}=n,u=r({slug:s,environment:o,resourceType:"nat"}),d=t(u);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:x.GetAtt(i,"AllocationId"),SubnetId:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:d}}static createRouteTable(n,i,s,o){let c=r({slug:n,environment:i,resourceType:`rt-${o}`}),u=t(c);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:x.Ref(s),Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i},{Key:"Type",Value:o}]}},logicalId:u}}static createRoute(n,i,s){let o=t(`${n}-route-${s.type}`),c={Type:"AWS::EC2::Route",Properties:{RouteTableId:x.Ref(n),DestinationCidrBlock:i}};if(s.type==="igw")c.Properties.GatewayId=x.Ref(s.logicalId);else if(s.type==="nat")c.Properties.NatGatewayId=x.Ref(s.logicalId);else if(s.type==="instance")c.Properties.InstanceId=x.Ref(s.logicalId);return{route:c,logicalId:o}}static associateSubnetWithRouteTable(n,i){let s=t(`${n}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:x.Ref(n),RouteTableId:x.Ref(i)}},logicalId:s}}static enableFlowLogs(n){let{slug:i,environment:s,resourceId:o,resourceType:c,trafficType:u="ALL",logGroupName:d}=n,p=r({slug:i,environment:s,resourceType:"flowlog"}),y=t(p);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:c,ResourceIds:[o],TrafficType:u,LogDestinationType:"cloud-watch-logs",LogGroupName:d||`/aws/vpc/${i}-${s}`,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}},logicalId:y}}static calculateSubnetCidrs(n,i,s=3){let[o,c]=n.split("/"),u=Number.parseInt(c,10),d=Math.ceil(Math.log2(i*s)),p=u+d;if(p>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[y,h,b,v]=o.split(".").map(Number),A=(y<<24)+(h<<16)+(b<<8)+v,T=2**(32-p),R=[];for(let P=0;P<i*s;P++){let I=A+P*T,M=[I>>>24&255,I>>>16&255,I>>>8&255,I&255].join(".");R.push(`${M}/${p}`)}return R}static getAvailabilityZones(n,i){return["a","b","c","d","e","f"].slice(0,i).map((o)=>`${n}${o}`)}static createMultiAzNetwork(n){let{slug:i,environment:s,region:o,cidr:c="10.0.0.0/16",zones:u=3,enableNatGateway:d=!1,singleNatGateway:p=!1,enableFlowLogs:y=!1}=n,h={},b=[],v=[],A=[],{vpc:T,logicalId:R}=S.createVpc({slug:i,environment:s,cidr:c});h[R]=T;let{internetGateway:P,logicalId:I}=S.createInternetGateway(i,s);h[I]=P;let{attachment:M,logicalId:L}=S.attachInternetGateway(R,I);h[L]=M;let{routeTable:N,logicalId:O}=S.createRouteTable(i,s,R,"public");h[O]=N;let{route:B,logicalId:F}=S.createRoute(O,"0.0.0.0/0",{type:"igw",logicalId:I});B.DependsOn=L,h[F]=B;let U=S.calculateSubnetCidrs(c,u,2),j=S.getAvailabilityZones(o,u),H=[];for(let z=0;z<u;z++){let
|
|
580
|
+
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class S{static createVpc(n){let{slug:i,environment:s,cidr:o="10.0.0.0/16",enableDnsHostnames:c=!0,enableDnsSupport:u=!0}=n,d=r({slug:i,environment:s,resourceType:"vpc"}),p=t(d);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:o,EnableDnsHostnames:c,EnableDnsSupport:u,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:s}]}},logicalId:p}}static createSubnet(n){let{slug:i,environment:s,vpcId:o,type:c,cidr:u,availabilityZone:d,mapPublicIp:p=c==="public"}=n,y=r({slug:i,environment:s,resourceType:`subnet-${c}`}),h=t(`${y}-${d}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:o,CidrBlock:u,AvailabilityZone:d,MapPublicIpOnLaunch:p,Tags:[{Key:"Name",Value:`${y}-${d}`},{Key:"Environment",Value:s},{Key:"Type",Value:c}]}},logicalId:h}}static createInternetGateway(n,i){let s=r({slug:n,environment:i,resourceType:"igw"}),o=t(s);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static attachInternetGateway(n,i){let s=t(`${n}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:x.Ref(n),InternetGatewayId:x.Ref(i)}},logicalId:s}}static createEip(n,i){let s=r({slug:n,environment:i,resourceType:"eip"}),o=t(s);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createNatGateway(n,i){let{slug:s,environment:o,subnetId:c}=n,u=r({slug:s,environment:o,resourceType:"nat"}),d=t(u);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:x.GetAtt(i,"AllocationId"),SubnetId:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:d}}static createRouteTable(n,i,s,o){let c=r({slug:n,environment:i,resourceType:`rt-${o}`}),u=t(c);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:x.Ref(s),Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i},{Key:"Type",Value:o}]}},logicalId:u}}static createRoute(n,i,s){let o=t(`${n}-route-${s.type}`),c={Type:"AWS::EC2::Route",Properties:{RouteTableId:x.Ref(n),DestinationCidrBlock:i}};if(s.type==="igw")c.Properties.GatewayId=x.Ref(s.logicalId);else if(s.type==="nat")c.Properties.NatGatewayId=x.Ref(s.logicalId);else if(s.type==="instance")c.Properties.InstanceId=x.Ref(s.logicalId);return{route:c,logicalId:o}}static associateSubnetWithRouteTable(n,i){let s=t(`${n}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:x.Ref(n),RouteTableId:x.Ref(i)}},logicalId:s}}static enableFlowLogs(n){let{slug:i,environment:s,resourceId:o,resourceType:c,trafficType:u="ALL",logGroupName:d}=n,p=r({slug:i,environment:s,resourceType:"flowlog"}),y=t(p);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:c,ResourceIds:[o],TrafficType:u,LogDestinationType:"cloud-watch-logs",LogGroupName:d||`/aws/vpc/${i}-${s}`,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}},logicalId:y}}static calculateSubnetCidrs(n,i,s=3){let[o,c]=n.split("/"),u=Number.parseInt(c,10),d=Math.ceil(Math.log2(i*s)),p=u+d;if(p>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[y,h,b,v]=o.split(".").map(Number),A=(y<<24)+(h<<16)+(b<<8)+v,T=2**(32-p),R=[];for(let P=0;P<i*s;P++){let I=A+P*T,M=[I>>>24&255,I>>>16&255,I>>>8&255,I&255].join(".");R.push(`${M}/${p}`)}return R}static getAvailabilityZones(n,i){return["a","b","c","d","e","f"].slice(0,i).map((o)=>`${n}${o}`)}static createMultiAzNetwork(n){let{slug:i,environment:s,region:o,cidr:c="10.0.0.0/16",zones:u=3,enableNatGateway:d=!1,singleNatGateway:p=!1,enableFlowLogs:y=!1}=n,h={},b=[],v=[],A=[],{vpc:T,logicalId:R}=S.createVpc({slug:i,environment:s,cidr:c});h[R]=T;let{internetGateway:P,logicalId:I}=S.createInternetGateway(i,s);h[I]=P;let{attachment:M,logicalId:L}=S.attachInternetGateway(R,I);h[L]=M;let{routeTable:N,logicalId:O}=S.createRouteTable(i,s,R,"public");h[O]=N;let{route:B,logicalId:F}=S.createRoute(O,"0.0.0.0/0",{type:"igw",logicalId:I});B.DependsOn=L,h[F]=B;let U=S.calculateSubnetCidrs(c,u,2),j=S.getAvailabilityZones(o,u),H=[];for(let z=0;z<u;z++){let se=j[z],Te=U[z*2],oe=U[z*2+1],{subnet:pe,logicalId:ae}=S.createSubnet({slug:i,environment:s,vpcId:x.Ref(R),type:"public",cidr:Te,availabilityZone:se});h[ae]=pe,b.push(ae);let{association:me,logicalId:Ie}=S.associateSubnetWithRouteTable(ae,O);h[Ie]=me;let{subnet:Le,logicalId:fe}=S.createSubnet({slug:i,environment:s,vpcId:x.Ref(R),type:"private",cidr:oe,availabilityZone:se});if(h[fe]=Le,v.push(fe),d&&(!p||z===0)){let{eip:ge,logicalId:he}=S.createEip(`${i}-${se}`,s);h[he]=ge;let{natGateway:De,logicalId:Se}=S.createNatGateway({slug:`${i}-${se}`,environment:s,subnetId:x.Ref(ae)},he);De.DependsOn=L,h[Se]=De,A.push(Se);let{routeTable:Re,logicalId:$e}=S.createRouteTable(`${i}-${se}`,s,R,"private");h[$e]=Re,H.push($e);let{route:We,logicalId:G}=S.createRoute($e,"0.0.0.0/0",{type:"nat",logicalId:Se});h[G]=We;let{association:ne,logicalId:ie}=S.associateSubnetWithRouteTable(fe,$e);h[ie]=ne}else if(d&&p&&z>0){let{association:ge,logicalId:he}=S.associateSubnetWithRouteTable(fe,H[0]);h[he]=ge}else{let{routeTable:ge,logicalId:he}=S.createRouteTable(`${i}-${se}-isolated`,s,R,"private");h[he]=ge;let{association:De,logicalId:Se}=S.associateSubnetWithRouteTable(fe,he);h[Se]=De}}if(y){let{flowLog:z,logicalId:se}=S.enableFlowLogs({slug:i,environment:s,resourceId:x.Ref(R),resourceType:"VPC"});h[se]=z}return{resources:h,outputs:{vpcId:R,publicSubnetIds:b,privateSubnetIds:v,natGatewayIds:A.length>0?A:void 0}}}static NatGatewayCostWarning=`
|
|
581
581
|
⚠️ NAT Gateway Cost Warning:
|
|
582
582
|
- Each NAT Gateway costs approximately $32-45/month (hourly charges)
|
|
583
583
|
- Data processing charges: $0.045/GB processed
|
|
@@ -585,7 +585,7 @@ echo "Redis server setup complete!"
|
|
|
585
585
|
- Using a single NAT Gateway (singleNatGateway: true)
|
|
586
586
|
- Using NAT Instances instead (cheaper but requires management)
|
|
587
587
|
- Disabling NAT entirely for isolated private subnets
|
|
588
|
-
`}class Ze{static createFileSystem(n){let{slug:i,environment:s,encrypted:o=!0,kmsKeyId:c,performanceMode:u="generalPurpose",throughputMode:d="bursting",provisionedThroughput:p,enableBackup:y=!0}=n,h=r({slug:i,environment:s,resourceType:"efs"}),b=t(h),v={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:o,PerformanceMode:u,ThroughputMode:d,FileSystemTags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(c)v.Properties.KmsKeyId=c;if(d==="provisioned"&&p)v.Properties.ProvisionedThroughputInMibps=p;if(y)v.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:v,logicalId:b}}static createMountTarget(n,i){let{slug:s,environment:o,subnetId:c,securityGroups:u,ipAddress:d}=i,p=r({slug:s,environment:o,resourceType:"efs-mt"}),y=t(`${p}-${c}`),h={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:x.Ref(n),SubnetId:c,SecurityGroups:u}};if(d)h.Properties.IpAddress=d;return{mountTarget:h,logicalId:y}}static createAccessPoint(n,i){let{slug:s,environment:o,path:c="/",uid:u="1000",gid:d="1000",permissions:p="755"}=i,y=r({slug:s,environment:o,resourceType:"efs-ap"}),h=t(`${y}-${c.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:x.Ref(n),PosixUser:{Uid:u,Gid:d},RootDirectory:{Path:c,CreationInfo:{OwnerUid:u,OwnerGid:d,Permissions:p}},AccessPointTags:[{Key:"Name",Value:`${y}-${c}`},{Key:"Environment",Value:o}]}},logicalId:h}}static setLifecyclePolicy(n,i){let{transitionToIA:s,transitionToPrimary:o=!1}=i;if(!n.Properties)n.Properties={};if(n.Properties.LifecyclePolicies=[],s){let c=`AFTER_${s}_DAYS`;n.Properties.LifecyclePolicies.push({TransitionToIA:c})}if(o)n.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return n}static enableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"ENABLED"},n}static disableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"DISABLED"},n}static setProvisionedThroughput(n,i){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="provisioned",n.Properties.ProvisionedThroughputInMibps=i,n}static setElasticThroughput(n){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="elastic",n}static enableMaxIO(n){if(!n.Properties)n.Properties={};return n.Properties.PerformanceMode="maxIO",n}static createEfsSecurityGroup(n){let{slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:c=[],sourceCidrBlocks:u=[],description:d}=n,p=r({slug:i,environment:s,resourceType:"efs-sg"}),y=t(p),h=[];for(let v of c)h.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:v,Description:"NFS from security group"});for(let v of u)h.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:v,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:p,GroupDescription:d||`Security group for EFS mount targets - ${i} ${s}`,VpcId:o,SecurityGroupIngress:h,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}},logicalId:y}}static createMultiAzMountTargets(n,i){let{slug:s,environment:o,subnetIds:c,securityGroupId:u}=i,d=[],p=[];for(let y=0;y<c.length;y++){let h=c[y],b=r({slug:s,environment:o,resourceType:"efs-mt"}),v=t(`${b}-az${y+1}`),A={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:x.Ref(n),SubnetId:h,SecurityGroups:[u]}};d.push(A),p.push(v)}return{mountTargets:d,logicalIds:p}}static createCompleteFileSystem(n){let{slug:i,environment:s,vpcId:o,subnetIds:c,sourceSecurityGroupIds:u=[],encrypted:d=!0,performanceMode:p="generalPurpose",throughputMode:y="elastic",enableBackup:h=!0,transitionToIA:b}=n,v={},{fileSystem:A,logicalId:T}=Ze.createFileSystem({slug:i,environment:s,encrypted:d,performanceMode:p,throughputMode:y,enableBackup:h});if(b)Ze.setLifecyclePolicy(A,{transitionToIA:b,transitionToPrimary:!0});v[T]=A;let{securityGroup:R,logicalId:P}=Ze.createEfsSecurityGroup({slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:u});v[P]=R;let{mountTargets:I,logicalIds:M}=Ze.createMultiAzMountTargets(T,{slug:i,environment:s,subnetIds:c,securityGroupId:x.Ref(P)});for(let L=0;L<I.length;L++)v[M[L]]=I[L];return{resources:v,outputs:{fileSystemId:T,securityGroupId:P,mountTargetIds:M}}}}class f{static verifyDomain(n){let{domain:i,slug:s,environment:o,enableDkim:c=!0,dkimKeyLength:u="RSA_2048_BIT"}=n,d=r({slug:s,environment:o,resourceType:"ses-identity"}),p=t(`${d}-${i.replace(/\./g,"")}`),y={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(c)y.Properties.DkimSigningAttributes={NextSigningKeyLength:u};return{emailIdentity:y,logicalId:p}}static createDkimRecords(n,i,s){let o=[];for(let c=0;c<i.length;c++){let u=i[c],d=t(`dkim-${n.replace(/\./g,"")}-${c+1}`),p={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`${u}._domainkey.${n}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${u}.dkim.amazonses.com`]}};o.push({record:p,logicalId:d})}return o}static createConfigurationSet(n){let{slug:i,environment:s,name:o,reputationMetrics:c=!0,sendingEnabled:u=!0,suppressBounces:d=!0,suppressComplaints:p=!0}=n,y=o||r({slug:i,environment:s,resourceType:"ses-config"}),h=t(y),b=[];if(d)b.push("BOUNCE");if(p)b.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:y,ReputationOptions:{ReputationMetricsEnabled:c},SendingOptions:{SendingEnabled:u},SuppressionOptions:{SuppressedReasons:b}}},logicalId:h}}static createReceiptRuleSet(n){let{slug:i,environment:s,name:o}=n,c=o||r({slug:i,environment:s,resourceType:"ses-ruleset"}),u=t(c);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:c}},logicalId:u}}static createReceiptRule(n,i){let{slug:s,environment:o,ruleSetName:c,recipients:u,enabled:d=!0,scanEnabled:p=!0,tlsPolicy:y="Require",s3Action:h,lambdaAction:b,snsAction:v}=i,A=r({slug:s,environment:o,resourceType:"ses-rule"}),T=t(A),R=[];if(h)R.push({S3Action:{BucketName:h.bucketName,ObjectKeyPrefix:h.prefix,KmsKeyArn:h.kmsKeyArn}});if(b)R.push({LambdaAction:{FunctionArn:b.functionArn,InvocationType:b.invocationType||"Event"}});if(v)R.push({SNSAction:{TopicArn:v.topicArn,Encoding:v.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:c,Rule:{Name:A,Enabled:d,ScanEnabled:p,TlsPolicy:y,Recipients:u,Actions:R.length>0?R:void 0}}},logicalId:T}}static createMxRecord(n,i,s){let o=t(`mx-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${s}.amazonaws.com`]}},logicalId:o}}static createVerificationRecord(n,i,s){let o=t(`verification-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`_amazonses.${n}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${i}"`]}},logicalId:o}}static getSmtpEndpoint(n){return`email-smtp.${n}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(n,i,s){let{includeDomains:o=[],softFail:c=!1}=s||{},u=t(`spf-${n.replace(/\./g,"")}`),d="v=spf1 include:amazonses.com";for(let y of o)d+=` include:${y}`;return d+=c?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"TXT",TTL:300,ResourceRecords:[`"${d}"`]}},logicalId:u}}static createDmarcRecord(n,i,s){let{policy:o="none",subdomainPolicy:c,percentage:u=100,reportingEmail:d,forensicEmail:p}=s||{},y=t(`dmarc-${n.replace(/\./g,"")}`),h=`v=DMARC1; p=${o}; pct=${u}`;if(c)h+=`; sp=${c}`;if(d)h+=`; rua=mailto:${d}`;if(p)h+=`; ruf=mailto:${p}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:`_dmarc.${n}`,Type:"TXT",TTL:300,ResourceRecords:[`"${h}"`]}},logicalId:y}}static createInboundEmailSetup(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3KeyPrefix:u="inbound/",region:d,hostedZoneId:p,lambdaFunctionArn:y,snsTopicArn:h}=n,b={},{ruleSet:v,logicalId:A}=f.createReceiptRuleSet({slug:i,environment:s});b[A]=v;let{receiptRule:T,logicalId:R}=f.createReceiptRule(A,{slug:i,environment:s,ruleSetName:v.Properties.RuleSetName||`${i}-${s}-receipt-rule-set`,recipients:[o],s3Action:{bucketName:c,prefix:u},lambdaAction:y?{functionArn:y,invocationType:"Event"}:void 0,snsAction:h?{topicArn:h}:void 0});b[R]=T;let{record:P,logicalId:I}=f.createMxRecord(o,p,d);return b[I]=P,{resources:b,outputs:{ruleSetLogicalId:A,ruleLogicalId:R,mxRecordLogicalId:I}}}static createCompleteDomainSetup(n){let{slug:i,environment:s,domain:o,hostedZoneId:c,region:u,enableInbound:d=!1,inboundS3Bucket:p,dmarcReportingEmail:y}=n,h={},{emailIdentity:b,logicalId:v}=f.verifyDomain({domain:o,slug:i,environment:s});h[v]=b;let{configurationSet:A,logicalId:T}=f.createConfigurationSet({slug:i,environment:s});h[T]=A;let{record:R,logicalId:P}=f.createSpfRecord(o,c);h[P]=R;let{record:I,logicalId:M}=f.createDmarcRecord(o,c,{policy:"none",reportingEmail:y||`dmarc-reports@${o}`});if(h[M]=I,d&&p){let L=f.createInboundEmailSetup({slug:i,environment:s,domain:o,s3BucketName:p,region:u,hostedZoneId:c});Object.assign(h,L.resources)}return{resources:h,outputs:{identityLogicalId:v,configSetLogicalId:T}}}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(n){return n in f.InboundSmtpEndpoints}static createEmailLambdaRole(n){let{slug:i,environment:s,s3BucketArn:o,sesIdentityArn:c}=n,u=r({slug:i,environment:s,resourceType:"email-lambda-role"}),d=t(u),p=t(`${u}-policy`),y={Type:"AWS::IAM::Role",Properties:{RoleName:u,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:u},{Key:"Environment",Value:s}]}},h=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[o,`${o}/*`]}];if(c)h.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:c});let b={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:h},Roles:[x.Ref(d)]}};return{role:y,policy:b,roleLogicalId:d,policyLogicalId:p}}static createOutboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,domain:c,configurationSetName:u,timeout:d=30,memorySize:p=256}=n,y=r({slug:i,environment:s,resourceType:"outbound-email"}),h=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:d,MemorySize:p,Environment:{Variables:{DOMAIN:c,CONFIGURATION_SET:u||""}},Code:{ZipFile:f.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:h}}static createInboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,organizedPrefix:u="organized/",timeout:d=60,memorySize:p=512}=n,y=r({slug:i,environment:s,resourceType:"inbound-email"}),h=t(y),b=t(`${y}-permission`),v={Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:d,MemorySize:p,Environment:{Variables:{S3_BUCKET:c,ORGANIZED_PREFIX:u}},Code:{ZipFile:f.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"InboundEmail"}]}},A={Type:"AWS::Lambda::Permission",Properties:{FunctionName:x.Ref(h),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:x.Ref("AWS::AccountId")}};return{function:v,permission:A,logicalId:h,permissionLogicalId:b}}static createEmailConversionLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,convertedPrefix:u="converted/",timeout:d=60,memorySize:p=512}=n,y=r({slug:i,environment:s,resourceType:"email-conversion"}),h=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:d,MemorySize:p,Environment:{Variables:{S3_BUCKET:c,CONVERTED_PREFIX:u}},Code:{ZipFile:f.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:h}}static createEmailBucketNotification(n){let{lambdaArn:i,prefix:s="inbound/",suffix:o,events:c}=n,u=c??["s3:ObjectCreated:*"],d={};if(s||o){if(d.S3Key={Rules:[]},s)d.S3Key.Rules.push({Name:"prefix",Value:s});if(o)d.S3Key.Rules.push({Name:"suffix",Value:o})}return{notificationConfiguration:{LambdaConfigurations:[{Event:u[0],Function:i,Filter:Object.keys(d).length>0?d:void 0}]}}}static createS3LambdaPermission(n){let{slug:i,environment:s,lambdaLogicalId:o,s3BucketArn:c}=n,u=r({slug:i,environment:s,resourceType:"s3-lambda-permission"}),d=t(u);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:x.Ref(o),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:c}},logicalId:d}}static createEmailProcessingStack(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3BucketArn:u,configurationSetName:d,enableInbound:p=!0,enableConversion:y=!0}=n,h={},{role:b,policy:v,roleLogicalId:A,policyLogicalId:T}=f.createEmailLambdaRole({slug:i,environment:s,s3BucketArn:u,sesIdentityArn:`arn:aws:ses:*:*:identity/${o}`});h[A]=b,h[T]=v;let{function:R,logicalId:P}=f.createOutboundEmailLambda({slug:i,environment:s,roleArn:x.GetAtt(A,"Arn"),domain:o,configurationSetName:d});h[P]=R;let I={roleLogicalId:A,outboundLambdaLogicalId:P};if(p){let{function:M,permission:L,logicalId:N,permissionLogicalId:O}=f.createInboundEmailLambda({slug:i,environment:s,roleArn:x.GetAtt(A,"Arn"),s3BucketName:c});h[N]=M,h[O]=L;let{permission:B,logicalId:F}=f.createS3LambdaPermission({slug:i,environment:s,lambdaLogicalId:N,s3BucketArn:u});h[F]=B,I.inboundLambdaLogicalId=N}if(y){let{function:M,logicalId:L}=f.createEmailConversionLambda({slug:i,environment:s,roleArn:x.GetAtt(A,"Arn"),s3BucketName:c});h[L]=M,I.conversionLambdaLogicalId=L}return{resources:h,outputs:I}}static LambdaCode={outboundEmail:`
|
|
588
|
+
`}class et{static createFileSystem(n){let{slug:i,environment:s,encrypted:o=!0,kmsKeyId:c,performanceMode:u="generalPurpose",throughputMode:d="bursting",provisionedThroughput:p,enableBackup:y=!0}=n,h=r({slug:i,environment:s,resourceType:"efs"}),b=t(h),v={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:o,PerformanceMode:u,ThroughputMode:d,FileSystemTags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(c)v.Properties.KmsKeyId=c;if(d==="provisioned"&&p)v.Properties.ProvisionedThroughputInMibps=p;if(y)v.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:v,logicalId:b}}static createMountTarget(n,i){let{slug:s,environment:o,subnetId:c,securityGroups:u,ipAddress:d}=i,p=r({slug:s,environment:o,resourceType:"efs-mt"}),y=t(`${p}-${c}`),h={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:x.Ref(n),SubnetId:c,SecurityGroups:u}};if(d)h.Properties.IpAddress=d;return{mountTarget:h,logicalId:y}}static createAccessPoint(n,i){let{slug:s,environment:o,path:c="/",uid:u="1000",gid:d="1000",permissions:p="755"}=i,y=r({slug:s,environment:o,resourceType:"efs-ap"}),h=t(`${y}-${c.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:x.Ref(n),PosixUser:{Uid:u,Gid:d},RootDirectory:{Path:c,CreationInfo:{OwnerUid:u,OwnerGid:d,Permissions:p}},AccessPointTags:[{Key:"Name",Value:`${y}-${c}`},{Key:"Environment",Value:o}]}},logicalId:h}}static setLifecyclePolicy(n,i){let{transitionToIA:s,transitionToPrimary:o=!1}=i;if(!n.Properties)n.Properties={};if(n.Properties.LifecyclePolicies=[],s){let c=`AFTER_${s}_DAYS`;n.Properties.LifecyclePolicies.push({TransitionToIA:c})}if(o)n.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return n}static enableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"ENABLED"},n}static disableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"DISABLED"},n}static setProvisionedThroughput(n,i){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="provisioned",n.Properties.ProvisionedThroughputInMibps=i,n}static setElasticThroughput(n){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="elastic",n}static enableMaxIO(n){if(!n.Properties)n.Properties={};return n.Properties.PerformanceMode="maxIO",n}static createEfsSecurityGroup(n){let{slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:c=[],sourceCidrBlocks:u=[],description:d}=n,p=r({slug:i,environment:s,resourceType:"efs-sg"}),y=t(p),h=[];for(let v of c)h.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:v,Description:"NFS from security group"});for(let v of u)h.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:v,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:p,GroupDescription:d||`Security group for EFS mount targets - ${i} ${s}`,VpcId:o,SecurityGroupIngress:h,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}},logicalId:y}}static createMultiAzMountTargets(n,i){let{slug:s,environment:o,subnetIds:c,securityGroupId:u}=i,d=[],p=[];for(let y=0;y<c.length;y++){let h=c[y],b=r({slug:s,environment:o,resourceType:"efs-mt"}),v=t(`${b}-az${y+1}`),A={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:x.Ref(n),SubnetId:h,SecurityGroups:[u]}};d.push(A),p.push(v)}return{mountTargets:d,logicalIds:p}}static createCompleteFileSystem(n){let{slug:i,environment:s,vpcId:o,subnetIds:c,sourceSecurityGroupIds:u=[],encrypted:d=!0,performanceMode:p="generalPurpose",throughputMode:y="elastic",enableBackup:h=!0,transitionToIA:b}=n,v={},{fileSystem:A,logicalId:T}=et.createFileSystem({slug:i,environment:s,encrypted:d,performanceMode:p,throughputMode:y,enableBackup:h});if(b)et.setLifecyclePolicy(A,{transitionToIA:b,transitionToPrimary:!0});v[T]=A;let{securityGroup:R,logicalId:P}=et.createEfsSecurityGroup({slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:u});v[P]=R;let{mountTargets:I,logicalIds:M}=et.createMultiAzMountTargets(T,{slug:i,environment:s,subnetIds:c,securityGroupId:x.Ref(P)});for(let L=0;L<I.length;L++)v[M[L]]=I[L];return{resources:v,outputs:{fileSystemId:T,securityGroupId:P,mountTargetIds:M}}}}class f{static verifyDomain(n){let{domain:i,slug:s,environment:o,enableDkim:c=!0,dkimKeyLength:u="RSA_2048_BIT"}=n,d=r({slug:s,environment:o,resourceType:"ses-identity"}),p=t(`${d}-${i.replace(/\./g,"")}`),y={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(c)y.Properties.DkimSigningAttributes={NextSigningKeyLength:u};return{emailIdentity:y,logicalId:p}}static createDkimRecords(n,i,s){let o=[];for(let c=0;c<i.length;c++){let u=i[c],d=t(`dkim-${n.replace(/\./g,"")}-${c+1}`),p={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`${u}._domainkey.${n}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${u}.dkim.amazonses.com`]}};o.push({record:p,logicalId:d})}return o}static createConfigurationSet(n){let{slug:i,environment:s,name:o,reputationMetrics:c=!0,sendingEnabled:u=!0,suppressBounces:d=!0,suppressComplaints:p=!0}=n,y=o||r({slug:i,environment:s,resourceType:"ses-config"}),h=t(y),b=[];if(d)b.push("BOUNCE");if(p)b.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:y,ReputationOptions:{ReputationMetricsEnabled:c},SendingOptions:{SendingEnabled:u},SuppressionOptions:{SuppressedReasons:b}}},logicalId:h}}static createReceiptRuleSet(n){let{slug:i,environment:s,name:o}=n,c=o||r({slug:i,environment:s,resourceType:"ses-ruleset"}),u=t(c);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:c}},logicalId:u}}static createReceiptRule(n,i){let{slug:s,environment:o,ruleSetName:c,recipients:u,enabled:d=!0,scanEnabled:p=!0,tlsPolicy:y="Require",s3Action:h,lambdaAction:b,snsAction:v}=i,A=r({slug:s,environment:o,resourceType:"ses-rule"}),T=t(A),R=[];if(h)R.push({S3Action:{BucketName:h.bucketName,ObjectKeyPrefix:h.prefix,KmsKeyArn:h.kmsKeyArn}});if(b)R.push({LambdaAction:{FunctionArn:b.functionArn,InvocationType:b.invocationType||"Event"}});if(v)R.push({SNSAction:{TopicArn:v.topicArn,Encoding:v.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:c,Rule:{Name:A,Enabled:d,ScanEnabled:p,TlsPolicy:y,Recipients:u,Actions:R.length>0?R:void 0}}},logicalId:T}}static createMxRecord(n,i,s){let o=t(`mx-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${s}.amazonaws.com`]}},logicalId:o}}static createVerificationRecord(n,i,s){let o=t(`verification-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`_amazonses.${n}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${i}"`]}},logicalId:o}}static getSmtpEndpoint(n){return`email-smtp.${n}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(n,i,s){let{includeDomains:o=[],softFail:c=!1}=s||{},u=t(`spf-${n.replace(/\./g,"")}`),d="v=spf1 include:amazonses.com";for(let y of o)d+=` include:${y}`;return d+=c?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"TXT",TTL:300,ResourceRecords:[`"${d}"`]}},logicalId:u}}static createDmarcRecord(n,i,s){let{policy:o="none",subdomainPolicy:c,percentage:u=100,reportingEmail:d,forensicEmail:p}=s||{},y=t(`dmarc-${n.replace(/\./g,"")}`),h=`v=DMARC1; p=${o}; pct=${u}`;if(c)h+=`; sp=${c}`;if(d)h+=`; rua=mailto:${d}`;if(p)h+=`; ruf=mailto:${p}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:`_dmarc.${n}`,Type:"TXT",TTL:300,ResourceRecords:[`"${h}"`]}},logicalId:y}}static createInboundEmailSetup(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3KeyPrefix:u="inbound/",region:d,hostedZoneId:p,lambdaFunctionArn:y,snsTopicArn:h}=n,b={},{ruleSet:v,logicalId:A}=f.createReceiptRuleSet({slug:i,environment:s});b[A]=v;let{receiptRule:T,logicalId:R}=f.createReceiptRule(A,{slug:i,environment:s,ruleSetName:v.Properties.RuleSetName||`${i}-${s}-receipt-rule-set`,recipients:[o],s3Action:{bucketName:c,prefix:u},lambdaAction:y?{functionArn:y,invocationType:"Event"}:void 0,snsAction:h?{topicArn:h}:void 0});b[R]=T;let{record:P,logicalId:I}=f.createMxRecord(o,p,d);return b[I]=P,{resources:b,outputs:{ruleSetLogicalId:A,ruleLogicalId:R,mxRecordLogicalId:I}}}static createCompleteDomainSetup(n){let{slug:i,environment:s,domain:o,hostedZoneId:c,region:u,enableInbound:d=!1,inboundS3Bucket:p,dmarcReportingEmail:y}=n,h={},{emailIdentity:b,logicalId:v}=f.verifyDomain({domain:o,slug:i,environment:s});h[v]=b;let{configurationSet:A,logicalId:T}=f.createConfigurationSet({slug:i,environment:s});h[T]=A;let{record:R,logicalId:P}=f.createSpfRecord(o,c);h[P]=R;let{record:I,logicalId:M}=f.createDmarcRecord(o,c,{policy:"none",reportingEmail:y||`dmarc-reports@${o}`});if(h[M]=I,d&&p){let L=f.createInboundEmailSetup({slug:i,environment:s,domain:o,s3BucketName:p,region:u,hostedZoneId:c});Object.assign(h,L.resources)}return{resources:h,outputs:{identityLogicalId:v,configSetLogicalId:T}}}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(n){return n in f.InboundSmtpEndpoints}static createEmailLambdaRole(n){let{slug:i,environment:s,s3BucketArn:o,sesIdentityArn:c}=n,u=r({slug:i,environment:s,resourceType:"email-lambda-role"}),d=t(u),p=t(`${u}-policy`),y={Type:"AWS::IAM::Role",Properties:{RoleName:u,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:u},{Key:"Environment",Value:s}]}},h=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[o,`${o}/*`]}];if(c)h.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:c});let b={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:h},Roles:[x.Ref(d)]}};return{role:y,policy:b,roleLogicalId:d,policyLogicalId:p}}static createOutboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,domain:c,configurationSetName:u,timeout:d=30,memorySize:p=256}=n,y=r({slug:i,environment:s,resourceType:"outbound-email"}),h=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:d,MemorySize:p,Environment:{Variables:{DOMAIN:c,CONFIGURATION_SET:u||""}},Code:{ZipFile:f.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:h}}static createInboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,organizedPrefix:u="organized/",timeout:d=60,memorySize:p=512}=n,y=r({slug:i,environment:s,resourceType:"inbound-email"}),h=t(y),b=t(`${y}-permission`),v={Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:d,MemorySize:p,Environment:{Variables:{S3_BUCKET:c,ORGANIZED_PREFIX:u}},Code:{ZipFile:f.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"InboundEmail"}]}},A={Type:"AWS::Lambda::Permission",Properties:{FunctionName:x.Ref(h),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:x.Ref("AWS::AccountId")}};return{function:v,permission:A,logicalId:h,permissionLogicalId:b}}static createEmailConversionLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,convertedPrefix:u="converted/",timeout:d=60,memorySize:p=512}=n,y=r({slug:i,environment:s,resourceType:"email-conversion"}),h=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:d,MemorySize:p,Environment:{Variables:{S3_BUCKET:c,CONVERTED_PREFIX:u}},Code:{ZipFile:f.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:h}}static createEmailBucketNotification(n){let{lambdaArn:i,prefix:s="inbound/",suffix:o,events:c}=n,u=c??["s3:ObjectCreated:*"],d={};if(s||o){if(d.S3Key={Rules:[]},s)d.S3Key.Rules.push({Name:"prefix",Value:s});if(o)d.S3Key.Rules.push({Name:"suffix",Value:o})}return{notificationConfiguration:{LambdaConfigurations:[{Event:u[0],Function:i,Filter:Object.keys(d).length>0?d:void 0}]}}}static createS3LambdaPermission(n){let{slug:i,environment:s,lambdaLogicalId:o,s3BucketArn:c}=n,u=r({slug:i,environment:s,resourceType:"s3-lambda-permission"}),d=t(u);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:x.Ref(o),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:c}},logicalId:d}}static createEmailProcessingStack(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3BucketArn:u,configurationSetName:d,enableInbound:p=!0,enableConversion:y=!0}=n,h={},{role:b,policy:v,roleLogicalId:A,policyLogicalId:T}=f.createEmailLambdaRole({slug:i,environment:s,s3BucketArn:u,sesIdentityArn:`arn:aws:ses:*:*:identity/${o}`});h[A]=b,h[T]=v;let{function:R,logicalId:P}=f.createOutboundEmailLambda({slug:i,environment:s,roleArn:x.GetAtt(A,"Arn"),domain:o,configurationSetName:d});h[P]=R;let I={roleLogicalId:A,outboundLambdaLogicalId:P};if(p){let{function:M,permission:L,logicalId:N,permissionLogicalId:O}=f.createInboundEmailLambda({slug:i,environment:s,roleArn:x.GetAtt(A,"Arn"),s3BucketName:c});h[N]=M,h[O]=L;let{permission:B,logicalId:F}=f.createS3LambdaPermission({slug:i,environment:s,lambdaLogicalId:N,s3BucketArn:u});h[F]=B,I.inboundLambdaLogicalId=N}if(y){let{function:M,logicalId:L}=f.createEmailConversionLambda({slug:i,environment:s,roleArn:x.GetAtt(A,"Arn"),s3BucketName:c});h[L]=M,I.conversionLambdaLogicalId=L}return{resources:h,outputs:I}}static LambdaCode={outboundEmail:`
|
|
589
589
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
590
590
|
const ses = new SESClient({});
|
|
591
591
|
|
|
@@ -1452,7 +1452,7 @@ catch (error) {
|
|
|
1452
1452
|
};
|
|
1453
1453
|
}
|
|
1454
1454
|
};
|
|
1455
|
-
`;var
|
|
1455
|
+
`;var sn=`
|
|
1456
1456
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
1457
1457
|
const { TranscribeClient, StartTranscriptionJobCommand, GetTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
1458
1458
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -1623,7 +1623,7 @@ catch (error) {
|
|
|
1623
1623
|
|
|
1624
1624
|
return { statusCode: 200, body: 'OK' };
|
|
1625
1625
|
};
|
|
1626
|
-
`;class et{static LambdaCode={incomingCall:At,voicemail:an,missedCall:rn};static createConnectInstance(n){let{slug:i,environment:s,instanceAlias:o,inboundCallsEnabled:c=!0,outboundCallsEnabled:u=!0}=n;return{[`${i}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:o,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:c,OutboundCalls:u,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(n){return{[`${n.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:n.instanceArn,Name:n.name,TimeZone:n.timezone,Config:n.schedule.map((i)=>({Day:i.day,StartTime:{Hours:i.startHour,Minutes:i.startMinute},EndTime:{Hours:i.endHour,Minutes:i.endMinute}}))}}}}static createQueue(n){return{[`${n.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:n.instanceArn,Name:n.name,HoursOfOperationArn:n.hoursOfOperationArn,MaxContacts:n.maxContacts||10}}}}static createContactFlow(n){return{[`${n.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:n.instanceArn,Name:n.name,Type:n.type,Content:n.content}}}}static createBasicIvrFlow(n){let i={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:n.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:n.queueArn},Transitions:{NextAction:n.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...n.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:n.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(i)}static createPhoneLambdaRole(n){return{[`${n.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.slug}-phone-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(n){return{[`${n.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:et.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createVoicemailLambda(n){return{[`${n.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:et.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:n.voicemailBucket,NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",TRANSCRIPTION_ENABLED:n.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(n){return{[`${n.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:et.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createCallLogTable(n){return{[`${n.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,et.createPhoneLambdaRole({slug:n.slug})),Object.assign(i,et.createCallLogTable({slug:n.slug})),i[`${n.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-phone-notifications`}},i[`${n.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${n.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let o={"Fn::GetAtt":[`${n.slug}PhoneLambdaRole`,"Arn"]},c={Ref:`${n.slug}PhoneNotificationTopic`},u={Ref:`${n.slug}CallLogTable`},d={Ref:`${n.slug}VoicemailBucket`};if(Object.assign(i,et.createIncomingCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:u,webhookUrl:n.webhookUrl})),n.voicemailEnabled!==!1)Object.assign(i,et.createVoicemailLambda({slug:n.slug,roleArn:o,voicemailBucket:d,notificationTopicArn:c,callLogTable:u,transcriptionEnabled:n.transcriptionEnabled}));return Object.assign(i,et.createMissedCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:u,webhookUrl:n.webhookUrl})),s[`${n.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${n.slug}PhoneNotificationTopic`}},s[`${n.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${n.slug}CallLogTable`}},s[`${n.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${n.slug}VoicemailBucket`}},{resources:i,outputs:s}}}class J{static createQueue(n){let{slug:i,environment:s,name:o,delaySeconds:c=0,visibilityTimeout:u=30,messageRetentionPeriod:d=345600,maxMessageSize:p=262144,receiveMessageWaitTime:y=0,fifo:h=!1,contentBasedDeduplication:b=!1,encrypted:v=!0,kmsKeyId:A}=n,T=o||r({slug:i,environment:s,resourceType:"queue"}),R=h?`${T}.fifo`:T,P=t(T),I={Type:"AWS::SQS::Queue",Properties:{QueueName:R,DelaySeconds:c,MaximumMessageSize:p,MessageRetentionPeriod:d,ReceiveMessageWaitTimeSeconds:y,VisibilityTimeout:u,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:s}]}};if(h)I.Properties.FifoQueue=!0,I.Properties.ContentBasedDeduplication=b;if(v)if(A)I.Properties.KmsMasterKeyId=A;else I.Properties.SqsManagedSseEnabled=!0;return{queue:I,logicalId:P}}static createDeadLetterQueue(n,i){let{slug:s,environment:o,maxReceiveCount:c=3}=i,u=r({slug:s,environment:o,resourceType:"dlq"}),d=t(u),p={Type:"AWS::SQS::Queue",Properties:{QueueName:u,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o},{Key:"Type",Value:"DeadLetterQueue"}]}},y={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:x.GetAtt(d,"Arn"),maxReceiveCount:c}}};return{deadLetterQueue:p,updatedSourceQueue:y,deadLetterLogicalId:d}}static createSchedule(n,i){let{slug:s,environment:o,name:c,description:u,enabled:d=!0}=i,p=c||r({slug:s,environment:o,resourceType:"schedule"}),y=t(p);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:p,Description:u,ScheduleExpression:n,State:d?"ENABLED":"DISABLED",Targets:[]}},logicalId:y}}static scheduleEcsTask(n,i,s){let{slug:o,environment:c,name:u,description:d,enabled:p=!0,taskDefinitionArn:y,clusterArn:h,subnets:b,securityGroups:v=[],assignPublicIp:A=!1,taskCount:T=1,containerOverrides:R}=s,P=u||r({slug:o,environment:c,resourceType:"ecs-schedule"}),I=t(P),L={Id:"1",Arn:h,RoleArn:i,EcsParameters:{TaskDefinitionArn:y,TaskCount:T,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:b,SecurityGroups:v,AssignPublicIp:A?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(R&&R.length>0)L.Input=JSON.stringify({containerOverrides:R});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:P,Description:d||`Scheduled ECS task: ${y}`,ScheduleExpression:n,State:p?"ENABLED":"DISABLED",Targets:[L]}},logicalId:I}}static scheduleLambda(n,i){let{slug:s,environment:o,name:c,description:u,enabled:d=!0,functionArn:p,input:y}=i,h=c||r({slug:s,environment:o,resourceType:"lambda-schedule"}),b=t(h),v={Id:"1",Arn:p};if(y)v.Input=JSON.stringify(y);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:u||`Scheduled Lambda: ${p}`,ScheduleExpression:n,State:d?"ENABLED":"DISABLED",Targets:[v]}},logicalId:b}}static scheduleSqsMessage(n,i){let{slug:s,environment:o,name:c,description:u,enabled:d=!0,queueArn:p,messageGroupId:y}=i,h=c||r({slug:s,environment:o,resourceType:"sqs-schedule"}),b=t(h),v={Id:"1",Arn:p};if(y)v.SqsParameters={MessageGroupId:y};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:u||`Scheduled SQS message: ${p}`,ScheduleExpression:n,State:d?"ENABLED":"DISABLED",Targets:[v]}},logicalId:b}}static addTarget(n,i){if(!n.Properties.Targets)n.Properties.Targets=[];let s={Id:i.id,Arn:i.arn};if(i.roleArn)s.RoleArn=i.roleArn;if(i.input)s.Input=JSON.stringify(i.input);return n.Properties.Targets.push(s),n}static toCronExpression(n){if(n.startsWith("cron(")||n.startsWith("rate("))return n;return`cron(${n})`}static rateExpression(n,i){return`rate(${n} ${i})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(n){let i=n.toLowerCase().trim(),s=i.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(s){let h=parseInt(s[1],10),b=s[2].toLowerCase(),v=b.endsWith("s")&&h===1?b.slice(0,-1):b,A=!b.endsWith("s")&&h>1?`${b}s`:b;return`rate(${h} ${h===1?v:A})`}let o=i.match(/^every\s+(minute|hour|day)$/i);if(o)return`rate(1 ${o[1]})`;let c={"every minute":"rate(1 minute)","every hour":"rate(1 hour)","every day":"rate(1 day)",hourly:"cron(0 * * * ? *)",daily:"cron(0 0 * * ? *)","daily at midnight":"cron(0 0 * * ? *)",weekly:"cron(0 0 ? * SUN *)",monthly:"cron(0 0 1 * ? *)",yearly:"cron(0 0 1 1 ? *)"};if(c[i])return c[i];let u=i.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(u){let h=parseInt(u[1],10),b=u[2]?.toLowerCase();if(b==="pm"&&h!==12)h+=12;else if(b==="am"&&h===12)h=0;return`cron(0 ${h} * * ? *)`}let d=i.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(d){let h=parseInt(d[1],10);return`cron(${parseInt(d[2],10)} ${h} * * ? *)`}let p={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},y=i.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(y)return`cron(0 0 ? * ${p[y[1].toLowerCase()]} *)`;return J.toCronExpression(n)}static JobConfig={create:(n)=>{let{name:i,handler:s,retries:o=3,backoff:c="exponential",backoffDelay:u=1000,maxDelay:d=30000,timeout:p=60000,jitter:y=!0}=n;return{name:i,handler:s,retries:o,backoff:c,backoffDelay:u,maxDelay:d,timeout:p,jitter:y}},calculateDelay:(n,i)=>{let{backoff:s,backoffDelay:o,maxDelay:c,jitter:u}=i,d;switch(s){case"linear":d=o*n;break;case"exponential":d=o*2**(n-1);break;case"fixed":default:d=o}if(d=Math.min(d,c||Number.MAX_SAFE_INTEGER),u){let p=d*0.25*Math.random();d+=p}return Math.floor(d)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(n){let{containerName:i,jobClass:s,jobData:o,environment:c={}}=n,u=[{name:"JOB_CLASS",value:s}];if(o)u.push({name:"JOB_DATA",value:JSON.stringify(o)});for(let[d,p]of Object.entries(c))u.push({name:d,value:p});return{name:i,command:["bun","run","app/Jobs/runner.ts"],environment:u}}static createScheduledJob(n){let{slug:i,environment:s,schedule:o,jobClass:c,jobData:u,taskDefinitionArn:d,clusterArn:p,subnets:y,securityGroups:h=[],roleArn:b,containerName:v="app"}=n,A=J.rateStringToExpression(o),T=J.createJobContainerOverride({containerName:v,jobClass:c,jobData:u});return J.scheduleEcsTask(A,b,{slug:i,environment:s,name:`${i}-${c.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${c}`,taskDefinitionArn:d,clusterArn:p,subnets:y,securityGroups:h,containerOverrides:[T]})}static QueuePresets={highThroughput:(n,i)=>J.createQueue({slug:n,environment:i,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(n,i)=>J.createQueue({slug:n,environment:i,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(n,i)=>J.createQueue({slug:n,environment:i,fifo:!0,contentBasedDeduplication:!0}),delayed:(n,i,s=60)=>J.createQueue({slug:n,environment:i,delaySeconds:s})}}class kt{static async discoverJobs(n){let{projectRoot:i,jobsPath:s="app/Jobs"}=n,o=`${i}/${s}`,c=[];try{let u=await import("node:fs"),d=await import("node:path");if(!u.existsSync(o))return[];let p=u.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_")&&y!=="runner.ts");for(let y of p){let h=d.join(o,y),b=y.replace(".ts",""),v=u.readFileSync(h,"utf-8"),A=kt.parseJobMetadata(v,b,h);if(A)c.push(A)}}catch{return[]}return c}static parseJobMetadata(n,i,s){let o=n.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/schedule:\s*['"`]([^'"`]+)['"`]/),c=n.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||n.match(/enabled:\s*(true|false)/),u=n.match(/export\s+const\s+retries\s*=\s*(\d+)/)||n.match(/retries:\s*(\d+)/),d=n.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||n.match(/timeout:\s*(\d+)/),p=n.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||n.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),y=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;return{name:i,path:s,schedule:o?.[1],handler:`${i}.handle`,enabled:c?.[1]!=="false",retries:u?parseInt(u[1],10):void 0,backoff:p?.[1],timeout:d?parseInt(d[1],10):void 0,description:y?.[1]}}static async discoverActions(n){let{projectRoot:i,actionsPath:s="app/Actions"}=n,o=`${i}/${s}`,c=[];try{let u=await import("node:fs"),d=await import("node:path");if(!u.existsSync(o))return[];let p=u.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_"));for(let y of p){let h=d.join(o,y),b=y.replace(".ts",""),v=u.readFileSync(h,"utf-8"),A=kt.parseActionMetadata(v,b,h);if(A)c.push(A)}}catch{return[]}return c}static parseActionMetadata(n,i,s){if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;let c=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:i,path:s,handler:`${i}.handle`,description:c?.[1]}}static generateScheduledJobResources(n){let{slug:i,environment:s,jobs:o,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:p=[],roleArn:y,containerName:h="app"}=n,b={},v=0;for(let A of o){if(!A.schedule||!A.enabled)continue;let{rule:T,logicalId:R}=J.createScheduledJob({slug:i,environment:s,schedule:A.schedule,jobClass:A.name,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:p,roleArn:y,containerName:h});b[R]=T,v++}return{rules:b,count:v}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1626
|
+
`;class tt{static LambdaCode={incomingCall:At,voicemail:sn,missedCall:rn};static createConnectInstance(n){let{slug:i,environment:s,instanceAlias:o,inboundCallsEnabled:c=!0,outboundCallsEnabled:u=!0}=n;return{[`${i}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:o,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:c,OutboundCalls:u,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(n){return{[`${n.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:n.instanceArn,Name:n.name,TimeZone:n.timezone,Config:n.schedule.map((i)=>({Day:i.day,StartTime:{Hours:i.startHour,Minutes:i.startMinute},EndTime:{Hours:i.endHour,Minutes:i.endMinute}}))}}}}static createQueue(n){return{[`${n.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:n.instanceArn,Name:n.name,HoursOfOperationArn:n.hoursOfOperationArn,MaxContacts:n.maxContacts||10}}}}static createContactFlow(n){return{[`${n.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:n.instanceArn,Name:n.name,Type:n.type,Content:n.content}}}}static createBasicIvrFlow(n){let i={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:n.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:n.queueArn},Transitions:{NextAction:n.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...n.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:n.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(i)}static createPhoneLambdaRole(n){return{[`${n.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.slug}-phone-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(n){return{[`${n.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:tt.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createVoicemailLambda(n){return{[`${n.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:tt.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:n.voicemailBucket,NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",TRANSCRIPTION_ENABLED:n.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(n){return{[`${n.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:tt.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createCallLogTable(n){return{[`${n.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,tt.createPhoneLambdaRole({slug:n.slug})),Object.assign(i,tt.createCallLogTable({slug:n.slug})),i[`${n.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-phone-notifications`}},i[`${n.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${n.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let o={"Fn::GetAtt":[`${n.slug}PhoneLambdaRole`,"Arn"]},c={Ref:`${n.slug}PhoneNotificationTopic`},u={Ref:`${n.slug}CallLogTable`},d={Ref:`${n.slug}VoicemailBucket`};if(Object.assign(i,tt.createIncomingCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:u,webhookUrl:n.webhookUrl})),n.voicemailEnabled!==!1)Object.assign(i,tt.createVoicemailLambda({slug:n.slug,roleArn:o,voicemailBucket:d,notificationTopicArn:c,callLogTable:u,transcriptionEnabled:n.transcriptionEnabled}));return Object.assign(i,tt.createMissedCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:u,webhookUrl:n.webhookUrl})),s[`${n.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${n.slug}PhoneNotificationTopic`}},s[`${n.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${n.slug}CallLogTable`}},s[`${n.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${n.slug}VoicemailBucket`}},{resources:i,outputs:s}}}class J{static createQueue(n){let{slug:i,environment:s,name:o,delaySeconds:c=0,visibilityTimeout:u=30,messageRetentionPeriod:d=345600,maxMessageSize:p=262144,receiveMessageWaitTime:y=0,fifo:h=!1,contentBasedDeduplication:b=!1,encrypted:v=!0,kmsKeyId:A}=n,T=o||r({slug:i,environment:s,resourceType:"queue"}),R=h?`${T}.fifo`:T,P=t(T),I={Type:"AWS::SQS::Queue",Properties:{QueueName:R,DelaySeconds:c,MaximumMessageSize:p,MessageRetentionPeriod:d,ReceiveMessageWaitTimeSeconds:y,VisibilityTimeout:u,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:s}]}};if(h)I.Properties.FifoQueue=!0,I.Properties.ContentBasedDeduplication=b;if(v)if(A)I.Properties.KmsMasterKeyId=A;else I.Properties.SqsManagedSseEnabled=!0;return{queue:I,logicalId:P}}static createDeadLetterQueue(n,i){let{slug:s,environment:o,maxReceiveCount:c=3}=i,u=r({slug:s,environment:o,resourceType:"dlq"}),d=t(u),p={Type:"AWS::SQS::Queue",Properties:{QueueName:u,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o},{Key:"Type",Value:"DeadLetterQueue"}]}},y={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:x.GetAtt(d,"Arn"),maxReceiveCount:c}}};return{deadLetterQueue:p,updatedSourceQueue:y,deadLetterLogicalId:d}}static createSchedule(n,i){let{slug:s,environment:o,name:c,description:u,enabled:d=!0}=i,p=c||r({slug:s,environment:o,resourceType:"schedule"}),y=t(p);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:p,Description:u,ScheduleExpression:n,State:d?"ENABLED":"DISABLED",Targets:[]}},logicalId:y}}static scheduleEcsTask(n,i,s){let{slug:o,environment:c,name:u,description:d,enabled:p=!0,taskDefinitionArn:y,clusterArn:h,subnets:b,securityGroups:v=[],assignPublicIp:A=!1,taskCount:T=1,containerOverrides:R}=s,P=u||r({slug:o,environment:c,resourceType:"ecs-schedule"}),I=t(P),L={Id:"1",Arn:h,RoleArn:i,EcsParameters:{TaskDefinitionArn:y,TaskCount:T,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:b,SecurityGroups:v,AssignPublicIp:A?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(R&&R.length>0)L.Input=JSON.stringify({containerOverrides:R});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:P,Description:d||`Scheduled ECS task: ${y}`,ScheduleExpression:n,State:p?"ENABLED":"DISABLED",Targets:[L]}},logicalId:I}}static scheduleLambda(n,i){let{slug:s,environment:o,name:c,description:u,enabled:d=!0,functionArn:p,input:y}=i,h=c||r({slug:s,environment:o,resourceType:"lambda-schedule"}),b=t(h),v={Id:"1",Arn:p};if(y)v.Input=JSON.stringify(y);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:u||`Scheduled Lambda: ${p}`,ScheduleExpression:n,State:d?"ENABLED":"DISABLED",Targets:[v]}},logicalId:b}}static scheduleSqsMessage(n,i){let{slug:s,environment:o,name:c,description:u,enabled:d=!0,queueArn:p,messageGroupId:y}=i,h=c||r({slug:s,environment:o,resourceType:"sqs-schedule"}),b=t(h),v={Id:"1",Arn:p};if(y)v.SqsParameters={MessageGroupId:y};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:u||`Scheduled SQS message: ${p}`,ScheduleExpression:n,State:d?"ENABLED":"DISABLED",Targets:[v]}},logicalId:b}}static addTarget(n,i){if(!n.Properties.Targets)n.Properties.Targets=[];let s={Id:i.id,Arn:i.arn};if(i.roleArn)s.RoleArn=i.roleArn;if(i.input)s.Input=JSON.stringify(i.input);return n.Properties.Targets.push(s),n}static toCronExpression(n){if(n.startsWith("cron(")||n.startsWith("rate("))return n;return`cron(${n})`}static rateExpression(n,i){return`rate(${n} ${i})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(n){let i=n.toLowerCase().trim(),s=i.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(s){let h=parseInt(s[1],10),b=s[2].toLowerCase(),v=b.endsWith("s")&&h===1?b.slice(0,-1):b,A=!b.endsWith("s")&&h>1?`${b}s`:b;return`rate(${h} ${h===1?v:A})`}let o=i.match(/^every\s+(minute|hour|day)$/i);if(o)return`rate(1 ${o[1]})`;let c={"every minute":"rate(1 minute)","every hour":"rate(1 hour)","every day":"rate(1 day)",hourly:"cron(0 * * * ? *)",daily:"cron(0 0 * * ? *)","daily at midnight":"cron(0 0 * * ? *)",weekly:"cron(0 0 ? * SUN *)",monthly:"cron(0 0 1 * ? *)",yearly:"cron(0 0 1 1 ? *)"};if(c[i])return c[i];let u=i.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(u){let h=parseInt(u[1],10),b=u[2]?.toLowerCase();if(b==="pm"&&h!==12)h+=12;else if(b==="am"&&h===12)h=0;return`cron(0 ${h} * * ? *)`}let d=i.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(d){let h=parseInt(d[1],10);return`cron(${parseInt(d[2],10)} ${h} * * ? *)`}let p={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},y=i.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(y)return`cron(0 0 ? * ${p[y[1].toLowerCase()]} *)`;return J.toCronExpression(n)}static JobConfig={create:(n)=>{let{name:i,handler:s,retries:o=3,backoff:c="exponential",backoffDelay:u=1000,maxDelay:d=30000,timeout:p=60000,jitter:y=!0}=n;return{name:i,handler:s,retries:o,backoff:c,backoffDelay:u,maxDelay:d,timeout:p,jitter:y}},calculateDelay:(n,i)=>{let{backoff:s,backoffDelay:o,maxDelay:c,jitter:u}=i,d;switch(s){case"linear":d=o*n;break;case"exponential":d=o*2**(n-1);break;case"fixed":default:d=o}if(d=Math.min(d,c||Number.MAX_SAFE_INTEGER),u){let p=d*0.25*Math.random();d+=p}return Math.floor(d)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(n){let{containerName:i,jobClass:s,jobData:o,environment:c={}}=n,u=[{name:"JOB_CLASS",value:s}];if(o)u.push({name:"JOB_DATA",value:JSON.stringify(o)});for(let[d,p]of Object.entries(c))u.push({name:d,value:p});return{name:i,command:["bun","run","app/Jobs/runner.ts"],environment:u}}static createScheduledJob(n){let{slug:i,environment:s,schedule:o,jobClass:c,jobData:u,taskDefinitionArn:d,clusterArn:p,subnets:y,securityGroups:h=[],roleArn:b,containerName:v="app"}=n,A=J.rateStringToExpression(o),T=J.createJobContainerOverride({containerName:v,jobClass:c,jobData:u});return J.scheduleEcsTask(A,b,{slug:i,environment:s,name:`${i}-${c.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${c}`,taskDefinitionArn:d,clusterArn:p,subnets:y,securityGroups:h,containerOverrides:[T]})}static QueuePresets={highThroughput:(n,i)=>J.createQueue({slug:n,environment:i,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(n,i)=>J.createQueue({slug:n,environment:i,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(n,i)=>J.createQueue({slug:n,environment:i,fifo:!0,contentBasedDeduplication:!0}),delayed:(n,i,s=60)=>J.createQueue({slug:n,environment:i,delaySeconds:s})}}class Nt{static async discoverJobs(n){let{projectRoot:i,jobsPath:s="app/Jobs"}=n,o=`${i}/${s}`,c=[];try{let u=await import("node:fs"),d=await import("node:path");if(!u.existsSync(o))return[];let p=u.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_")&&y!=="runner.ts");for(let y of p){let h=d.join(o,y),b=y.replace(".ts",""),v=u.readFileSync(h,"utf-8"),A=Nt.parseJobMetadata(v,b,h);if(A)c.push(A)}}catch{return[]}return c}static parseJobMetadata(n,i,s){let o=n.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/schedule:\s*['"`]([^'"`]+)['"`]/),c=n.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||n.match(/enabled:\s*(true|false)/),u=n.match(/export\s+const\s+retries\s*=\s*(\d+)/)||n.match(/retries:\s*(\d+)/),d=n.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||n.match(/timeout:\s*(\d+)/),p=n.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||n.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),y=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;return{name:i,path:s,schedule:o?.[1],handler:`${i}.handle`,enabled:c?.[1]!=="false",retries:u?parseInt(u[1],10):void 0,backoff:p?.[1],timeout:d?parseInt(d[1],10):void 0,description:y?.[1]}}static async discoverActions(n){let{projectRoot:i,actionsPath:s="app/Actions"}=n,o=`${i}/${s}`,c=[];try{let u=await import("node:fs"),d=await import("node:path");if(!u.existsSync(o))return[];let p=u.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_"));for(let y of p){let h=d.join(o,y),b=y.replace(".ts",""),v=u.readFileSync(h,"utf-8"),A=Nt.parseActionMetadata(v,b,h);if(A)c.push(A)}}catch{return[]}return c}static parseActionMetadata(n,i,s){if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;let c=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:i,path:s,handler:`${i}.handle`,description:c?.[1]}}static generateScheduledJobResources(n){let{slug:i,environment:s,jobs:o,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:p=[],roleArn:y,containerName:h="app"}=n,b={},v=0;for(let A of o){if(!A.schedule||!A.enabled)continue;let{rule:T,logicalId:R}=J.createScheduledJob({slug:i,environment:s,schedule:A.schedule,jobClass:A.name,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:p,roleArn:y,containerName:h});b[R]=T,v++}return{rules:b,count:v}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1627
1627
|
/**
|
|
1628
1628
|
* Job Runner Script
|
|
1629
1629
|
* This script is invoked by ECS scheduled tasks to run jobs
|
|
@@ -1668,7 +1668,7 @@ catch (error) {
|
|
|
1668
1668
|
}
|
|
1669
1669
|
|
|
1670
1670
|
run()
|
|
1671
|
-
`}static async generateJobManifest(n){let i=await
|
|
1671
|
+
`}static async generateJobManifest(n){let i=await Nt.discoverJobs(n),s=i.filter((o)=>o.schedule&&o.enabled);return{jobs:i,scheduledCount:s.length,totalCount:i.length}}}var WI={loadJobs:Nt.discoverJobs,loadActions:Nt.discoverActions,generateScheduledJobs:Nt.generateScheduledJobResources,generateRunner:Nt.generateJobRunnerScript,paths:{jobs:"app/Jobs",actions:"app/Actions",runner:"app/Jobs/runner.ts"}};var an=`
|
|
1672
1672
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1673
1673
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1674
1674
|
|
|
@@ -2271,14 +2271,14 @@ function resolveTemplate(template, data) {
|
|
|
2271
2271
|
}
|
|
2272
2272
|
return result;
|
|
2273
2273
|
}
|
|
2274
|
-
`;class X{static LambdaCode={send:Ct,receive:on,deliveryStatus:sn};static createPinpointApp(n){return{[`${n.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:n.name||`${n.slug}-sms`}}}}static createSmsChannel(n){let i={ApplicationId:n.applicationId,Enabled:n.enabled!==!1};if(n.senderId)i.SenderId=n.senderId;if(n.shortCode)i.ShortCode=n.shortCode;return{[`${n.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:i}}}static createSmsLambdaRole(n){return{[`${n.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.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(n){return{[`${n.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:X.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:n.pinpointAppId,MESSAGE_LOG_TABLE:n.messageLogTable||"",SMS_SENDER_ID:n.senderId||"",SMS_ORIGINATION_NUMBER:n.originationNumber||""}}}}}}static createReceiveLambda(n){return{[`${n.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:X.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:n.optOutTable||"",MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createDeliveryStatusLambda(n){return{[`${n.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:X.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createMessageLogTable(n){return{[`${n.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(n){return{[`${n.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(n){return{[`${n.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-sms-notifications`}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,X.createPinpointApp({slug:n.slug})),Object.assign(i,X.createSmsChannel({slug:n.slug,applicationId:{Ref:`${n.slug}PinpointApp`},senderId:n.senderId})),Object.assign(i,X.createSmsLambdaRole({slug:n.slug})),Object.assign(i,X.createMessageLogTable({slug:n.slug})),Object.assign(i,X.createOptOutTable({slug:n.slug})),Object.assign(i,X.createNotificationTopic({slug:n.slug}));let o={"Fn::GetAtt":[`${n.slug}SmsLambdaRole`,"Arn"]},c={Ref:`${n.slug}PinpointApp`},u={Ref:`${n.slug}SmsMessageLogTable`},d={Ref:`${n.slug}SmsOptOutTable`},p={Ref:`${n.slug}SmsNotificationTopic`};if(Object.assign(i,X.createSendLambda({slug:n.slug,roleArn:o,pinpointAppId:c,messageLogTable:u,senderId:n.senderId,originationNumber:n.originationNumber})),n.twoWayEnabled)Object.assign(i,X.createReceiveLambda({slug:n.slug,roleArn:o,optOutTable:d,messageLogTable:u,notificationTopicArn:p,webhookUrl:n.webhookUrl}));return Object.assign(i,X.createDeliveryStatusLambda({slug:n.slug,roleArn:o,messageLogTable:u,notificationTopicArn:p,webhookUrl:n.webhookUrl})),s[`${n.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${n.slug}PinpointApp`}},s[`${n.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${n.slug}SmsSendLambda`,"Arn"]}},s[`${n.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${n.slug}SmsNotificationTopic`}},s[`${n.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${n.slug}SmsMessageLogTable`}},{resources:i,outputs:s}}}function vt(n){return n.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((o)=>o.charAt(0).toUpperCase()+o.slice(1)).join("")||"User"}function Er(n,i){let s=(n||i).replace(/^\/+|\/+$/g,"");if(!s||s.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${i}`);return s}function wr(n){let i=n.storage;if(i?.type==="efs"){let o="fileSystemId"in i?i.fileSystemId:void 0;if(!o||typeof o==="string"&&!o.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:o,posixProfile:i.posixProfile}}let s=(i?.type==="s3"?i.bucket??n.bucket:n.bucket)?.trim();if(!s)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:s}}function Ir(n,i,s){let o=i.posixProfile??s;if(!o)throw Error(`sftp: user ${n} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let c of[o.uid,o.gid,...o.secondaryGids??[]])if(!Number.isInteger(c)||c<0||c>4294967295)throw Error(`sftp: user ${n} has an invalid posixProfile id ${c}`);return{Uid:o.uid,Gid:o.gid,...o.secondaryGids?.length?{SecondaryGids:o.secondaryGids}:{}}}function Dr(n,i){return typeof n==="string"?`/${n}/${i}`:{"Fn::Sub":[`/\${FileSystemId}/${i}`,{FileSystemId:n}]}}function Nr(n){return typeof n==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",n)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:n}]}}class pl{static create(n){let i=wr(n),s=i.type==="efs"?"EFS":"S3",o=n.endpointType??"PUBLIC";if(o==="VPC"&&(!n.endpointDetails?.vpcId||!n.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let c=`${vt(n.slug)}${vt(n.environment)}Sftp`,u=`${c}Server`,d={},p;if(n.logging!==!1){let y=`${c}LoggingRole`;d[y]={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/*"}]}}]}},p={"Fn::GetAtt":[y,"Arn"]}}d[u]={Type:"AWS::Transfer::Server",Properties:{Domain:s,EndpointType:o,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...o==="VPC"?{EndpointDetails:{VpcId:n.endpointDetails.vpcId,SubnetIds:n.endpointDetails.subnetIds,...n.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:n.endpointDetails.securityGroupIds}:{},...n.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:n.endpointDetails.addressAllocationIds}:{}}}:{},...n.securityPolicyName?{SecurityPolicyName:n.securityPolicyName}:{},...p?{LoggingRole:p}:{},Tags:[{Key:"Project",Value:n.slug},{Key:"Environment",Value:n.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[y,h]of Object.entries(n.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(y))throw Error(`sftp: invalid username ${y}`);if(!h.sshPublicKeys.length)throw Error(`sftp: user ${y} requires at least one SSH public key`);let b=vt(y),v=Er(h.homeDirectory,y),A=`${c}${b}User`,T=h.roleArn;if(!T){let R=`${c}${b}Role`,P;if(i.type==="efs")P=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Nr(i.fileSystemId)}];else{let I=`arn:aws:s3:::${i.bucket}`;P=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:I,Condition:{StringLike:{"s3:prefix":[v,`${v}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${I}/${v}/*`}]}d[R]={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:P}}]}},T={"Fn::GetAtt":[R,"Arn"]}}d[A]={Type:"AWS::Transfer::User",DependsOn:[u],Properties:{ServerId:{Ref:u},UserName:y,Role:T,HomeDirectoryType:"PATH",HomeDirectory:i.type==="efs"?Dr(i.fileSystemId,v):`/${i.bucket}/${v}`,...i.type==="efs"?{PosixProfile:Ir(y,h,i.posixProfile)}:{},SshPublicKeys:h.sshPublicKeys}}}return{resources:d,serverLogicalId:u,domain:s}}}class Oe{static createBedrockRole(n,i){let{slug:s,environment:o,name:c,models:u=["*"],allowStreaming:d=!0}=i,p=c||r({slug:s,environment:o,resourceType:"bedrock-role"}),y=t(p),h=["bedrock:InvokeModel"];if(d)h.push("bedrock:InvokeModelWithResponseStream");let b=u.map((A)=>A==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${A}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:p,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:n},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${p}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:h,Resource:b}]}}],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:o}]}},logicalId:y}}static createBedrockPolicy(n){let{slug:i,environment:s,name:o,models:c=["*"],allowInvoke:u=!0,allowStreaming:d=!0,allowAsync:p=!1}=n,y=o||r({slug:i,environment:s,resourceType:"bedrock-policy"}),h=t(y),b=[];if(u)b.push("bedrock:InvokeModel");if(d)b.push("bedrock:InvokeModelWithResponseStream");if(p)b.push("bedrock:InvokeModelAsync");let v=c.map((T)=>T==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${T}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:y,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:b,Resource:v}]}}},logicalId:h}}static enableBedrockForLambda(n){return Oe.createBedrockRole("lambda.amazonaws.com",n)}static enableBedrockForEcs(n){return Oe.createBedrockRole("ecs-tasks.amazonaws.com",n)}static enableBedrockForEc2(n){return Oe.createBedrockRole("ec2.amazonaws.com",n)}static addBedrockPermissions(n,i=["*"],s=!0){let o=["bedrock:InvokeModel"];if(s)o.push("bedrock:InvokeModelWithResponseStream");let c=i.map((u)=>u==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${u}`);if(!n.Properties.Policies)n.Properties.Policies=[];return n.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:o,Resource:c}]}}),n}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 lr{static createPostgres(n){return lr.createRDSInstance("postgres","16.2",n)}static createMysql(n){return lr.createRDSInstance("mysql","8.0.35",n)}static createRDSInstance(n,i,s){let{slug:o,environment:c,instanceClass:u="db.t3.micro",allocatedStorage:d=20,storageType:p="gp3",masterUsername:y="admin",masterPassword:h,databaseName:b,subnetIds:v,securityGroupIds:A,encrypted:T=!0,kmsKeyId:R,multiAz:P=!1,backupRetentionDays:I=7,publiclyAccessible:M=!1,enableCloudwatchLogs:L=!0,deletionProtection:N=!0}=s,O=r({slug:o,environment:c,resourceType:`${n}-db`}),B=t(O),F,U;if(v&&v.length>0){let H=r({slug:o,environment:c,resourceType:"db-subnet-group"});U=t(H),F={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:H,DBSubnetGroupDescription:`Subnet group for ${O}`,SubnetIds:v,Tags:[{Key:"Name",Value:H},{Key:"Environment",Value:c}]}}}let j={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:O,DBInstanceClass:u,Engine:n,EngineVersion:i,MasterUsername:y,MasterUserPassword:h,AllocatedStorage:d,StorageType:p,StorageEncrypted:T,MultiAZ:P,BackupRetentionPeriod:I,PubliclyAccessible:M,DeletionProtection:N,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:c}]}};if(b)j.Properties.DBName=b;if(R)j.Properties.KmsKeyId=R;if(U)j.Properties.DBSubnetGroupName=x.Ref(U);if(A&&A.length>0)j.Properties.VPCSecurityGroups=A;if(L)j.Properties.EnableCloudwatchLogsExports=n==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:j,subnetGroup:F,logicalId:B,subnetGroupId:U}}static createReadReplica(n,i){let{slug:s,environment:o,instanceClass:c="db.t3.micro",securityGroupIds:u,publiclyAccessible:d=!1}=i,p=r({slug:s,environment:o,resourceType:"db-replica"}),y=t(p),h={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:p,DBInstanceClass:c,SourceDBInstanceIdentifier:x.Ref(n),PubliclyAccessible:d,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:o},{Key:"Type",Value:"ReadReplica"}]}};if(u&&u.length>0)h.Properties.VPCSecurityGroups=u;return{replica:h,logicalId:y}}static createParameterGroup(n,i,s){let{slug:o,environment:c,parameters:u={}}=s,d=r({slug:o,environment:c,resourceType:"db-params"}),p=t(d),y=n==="postgres"?`postgres${i.split(".")[0]}`:`mysql${i.split(".")[0]}.${i.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:d,Description:`Parameter group for ${d}`,Family:y,Parameters:u,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:c}]}},logicalId:p}}static enableBackup(n,i=7){return n.Properties.BackupRetentionPeriod=i,n}static createTable(n){let{slug:i,environment:s,tableName:o,partitionKey:c,sortKey:u,billingMode:d="PAY_PER_REQUEST",readCapacity:p=5,writeCapacity:y=5,streamEnabled:h=!1,streamViewType:b="NEW_AND_OLD_IMAGES",encrypted:v=!0,kmsKeyId:A,pointInTimeRecovery:T=!0,ttlAttribute:R}=n,P=o||r({slug:i,environment:s,resourceType:"table"}),I=t(P),M=[{AttributeName:c.name,AttributeType:c.type}];if(u)M.push({AttributeName:u.name,AttributeType:u.type});let L=[{AttributeName:c.name,KeyType:"HASH"}];if(u)L.push({AttributeName:u.name,KeyType:"RANGE"});let N={Type:"AWS::DynamoDB::Table",Properties:{TableName:P,BillingMode:d,AttributeDefinitions:M,KeySchema:L,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:s}]}};if(d==="PROVISIONED")N.Properties.ProvisionedThroughput={ReadCapacityUnits:p,WriteCapacityUnits:y};if(h)N.Properties.StreamSpecification={StreamViewType:b};if(v)N.Properties.SSESpecification={SSEEnabled:!0,SSEType:A?"KMS":"AES256",KMSMasterKeyId:A};if(T)N.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(R)N.Properties.TimeToLiveSpecification={AttributeName:R,Enabled:!0};return{table:N,logicalId:I}}static addGlobalSecondaryIndex(n,i){let{indexName:s,partitionKey:o,sortKey:c,projectionType:u="ALL",nonKeyAttributes:d,readCapacity:p=5,writeCapacity:y=5}=i;if(!n.Properties.AttributeDefinitions.some((v)=>v.AttributeName===o.name))n.Properties.AttributeDefinitions.push({AttributeName:o.name,AttributeType:o.type});if(c&&!n.Properties.AttributeDefinitions.some((v)=>v.AttributeName===c.name))n.Properties.AttributeDefinitions.push({AttributeName:c.name,AttributeType:c.type});let h=[{AttributeName:o.name,KeyType:"HASH"}];if(c)h.push({AttributeName:c.name,KeyType:"RANGE"});let b={IndexName:s,KeySchema:h,Projection:{ProjectionType:u,NonKeyAttributes:u==="INCLUDE"?d:void 0},ProvisionedThroughput:void 0};if(n.Properties.BillingMode==="PROVISIONED")b.ProvisionedThroughput={ReadCapacityUnits:p,WriteCapacityUnits:y};if(!n.Properties.GlobalSecondaryIndexes)n.Properties.GlobalSecondaryIndexes=[];return n.Properties.GlobalSecondaryIndexes.push(b),n}static enableStreams(n,i="NEW_AND_OLD_IMAGES"){return n.Properties.StreamSpecification={StreamViewType:i},n}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 Vo{static createRedis(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="7.1",port:u=6379,subnetIds:d,securityGroupIds:p,numCacheClusters:y=2,automaticFailover:h=!0,multiAz:b=!0,clusterMode:v=!1,numNodeGroups:A=1,replicasPerNodeGroup:T=1,atRestEncryption:R=!0,transitEncryption:P=!0,authToken:I,kmsKeyId:M,snapshotRetentionDays:L=7,snapshotWindow:N,maintenanceWindow:O}=n,B=r({slug:i,environment:s,resourceType:"redis"}),F=t(B),U,j;if(d&&d.length>0){let z=r({slug:i,environment:s,resourceType:"cache-subnet-group"});j=t(z),U={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:z,Description:`Subnet group for ${B}`,SubnetIds:d,Tags:[{Key:"Name",Value:z},{Key:"Environment",Value:s}]}}}let H={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:B,ReplicationGroupDescription:`Redis cluster for ${i} ${s}`,Engine:"redis",EngineVersion:c,CacheNodeType:o,Port:u,AutomaticFailoverEnabled:h,MultiAZEnabled:b,AtRestEncryptionEnabled:R,TransitEncryptionEnabled:P,SnapshotRetentionLimit:L,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:B},{Key:"Environment",Value:s}]}};if(v)H.Properties.NumNodeGroups=A,H.Properties.ReplicasPerNodeGroup=T;else H.Properties.NumCacheClusters=y;if(I)H.Properties.AuthToken=I;if(M)H.Properties.KmsKeyId=M;if(j)H.Properties.CacheSubnetGroupName=x.Ref(j);if(p&&p.length>0)H.Properties.SecurityGroupIds=p;if(N)H.Properties.SnapshotWindow=N;if(O)H.Properties.PreferredMaintenanceWindow=O;return{replicationGroup:H,subnetGroup:U,logicalId:F,subnetGroupId:j}}static createMemcached(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="1.6.22",port:u=11211,numCacheNodes:d=2,subnetIds:p,securityGroupIds:y,azMode:h="cross-az",preferredAzs:b,maintenanceWindow:v}=n,A=r({slug:i,environment:s,resourceType:"memcached"}),T=t(A),R,P;if(p&&p.length>0){let M=r({slug:i,environment:s,resourceType:"cache-subnet-group"});P=t(M),R={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:M,Description:`Subnet group for ${A}`,SubnetIds:p,Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:s}]}}}let I={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:A,CacheNodeType:o,Engine:"memcached",EngineVersion:c,NumCacheNodes:d,Port:u,AZMode:h,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:A},{Key:"Environment",Value:s}]}};if(P)I.Properties.CacheSubnetGroupName=x.Ref(P);if(y&&y.length>0)I.Properties.VpcSecurityGroupIds=y;if(b&&b.length>0)I.Properties.PreferredAvailabilityZones=b;if(v)I.Properties.PreferredMaintenanceWindow=v;return{cluster:I,subnetGroup:R,logicalId:T,subnetGroupId:P}}static enableClusterMode(n,i=3,s=2){return delete n.Properties.NumCacheClusters,n.Properties.NumNodeGroups=i,n.Properties.ReplicasPerNodeGroup=s,n}static createRedisParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,u=r({slug:s,environment:o,resourceType:"redis-params"}),d=t(u);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${n.split(".")[0]}.x`,Description:`Parameter group for ${u}`,Properties:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o}]}},logicalId:d}}static createMemcachedParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,u=r({slug:s,environment:o,resourceType:"memcached-params"}),d=t(u);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${n.split(".")[0]}.${n.split(".")[1]}`,Description:`Parameter group for ${u}`,Properties:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o}]}},logicalId:d}}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 de{static createUser(n){let{slug:i,environment:s,userName:o,groups:c,managedPolicyArns:u}=n,d=o||r({slug:i,environment:s,resourceType:"user"}),p=t(d),y={Type:"AWS::IAM::User",Properties:{UserName:d,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:s}]}};if(c&&c.length>0)y.Properties.Groups=c;if(u&&u.length>0)y.Properties.ManagedPolicyArns=u;return{user:y,logicalId:p}}static createRole(n){let{slug:i,environment:s,roleName:o,servicePrincipal:c,awsPrincipal:u,managedPolicyArns:d}=n,p=o||r({slug:i,environment:s,resourceType:"role"}),y=t(p),h={};if(c)h.Service=c;if(u)h.AWS=u;let b={Type:"AWS::IAM::Role",Properties:{RoleName:p,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:h,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(d&&d.length>0)b.Properties.ManagedPolicyArns=d;return{role:b,logicalId:y}}static createGroup(n){let{slug:i,environment:s,groupName:o,managedPolicyArns:c}=n,u=o||r({slug:i,environment:s,resourceType:"group"}),d=t(u),p={Type:"AWS::IAM::Group",Properties:{GroupName:u}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{group:p,logicalId:d}}static createPolicy(n){let{slug:i,environment:s,policyName:o,description:c,statements:u}=n,d=o||r({slug:i,environment:s,resourceType:"policy"}),p=t(d),y=u.map((b)=>({Sid:b.sid,Effect:b.effect||"Allow",Action:b.actions,Resource:b.resources,Condition:b.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,Description:c||`Managed policy for ${d}`,PolicyDocument:{Version:"2012-10-17",Statement:y}}},logicalId:p}}static attachPolicyToRole(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToUser(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToGroup(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static addInlinePolicyToRole(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static addInlinePolicyToUser(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static createAccessKey(n,i){let{slug:s,environment:o,status:c="Active"}=i,u=r({slug:s,environment:o,resourceType:"access-key"}),d=t(u);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:x.Ref(n),Status:c}},logicalId:d}}static createInstanceProfile(n,i){let{slug:s,environment:o,profileName:c}=i,u=c||r({slug:s,environment:o,resourceType:"instance-profile"}),d=t(u);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:u,Roles:[x.Ref(n)]}},logicalId:d}}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(n){let{slug:i,environment:s,permissions:o,createAccessKey:c=!0}=n,u={},d=[];if(o.s3Buckets&&o.s3Buckets.length>0)d.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...o.s3Buckets,...o.s3Buckets.map((T)=>`${T}/*`)]});if(o.cloudFrontDistributions&&o.cloudFrontDistributions.length>0)d.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:o.cloudFrontDistributions});if(o.ecrRepositories&&o.ecrRepositories.length>0)d.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:o.ecrRepositories}),d.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(o.ecsServices&&o.ecsServices.length>0)d.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:o.ecsServices}),d.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),d.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(o.cloudFormationStacks&&o.cloudFormationStacks.length>0)d.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:o.cloudFormationStacks});if(o.lambdaFunctions&&o.lambdaFunctions.length>0)d.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:o.lambdaFunctions});if(o.secretsManagerSecrets&&o.secretsManagerSecrets.length>0)d.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:o.secretsManagerSecrets});let{policy:p,logicalId:y}=de.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${i} (${s})`,statements:d});u[y]=p;let{user:h,logicalId:b}=de.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cicd-user"}),managedPolicyArns:[x.Ref(y)]});u[b]=h;let v,A;if(c){let T=de.createAccessKey(b,{slug:i,environment:s});v=T.accessKey,A=T.logicalId,u[A]=v}return{user:h,accessKey:v,policy:p,userLogicalId:b,accessKeyLogicalId:A,policyLogicalId:y,resources:u}}static createCrossAccountRole(n){let{slug:i,environment:s,trustedAccountIds:o,externalId:c,permissions:u,maxSessionDuration:d=3600}=n,p={},{policy:y,logicalId:h}=de.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${i} (${s})`,statements:u});p[h]=y;let b=r({slug:i,environment:s,resourceType:"cross-account-role"}),v=t(b),A={};if(c)A.StringEquals={"sts:ExternalId":c};let T={Type:"AWS::IAM::Role",Properties:{RoleName:b,MaxSessionDuration:d,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:o.map((R)=>`arn:aws:iam::${R}:root`)},Action:"sts:AssumeRole",...Object.keys(A).length>0?{Condition:A}:{}}]},ManagedPolicyArns:[x.Ref(h)],Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Cross-Account Access"}]}};return p[v]=T,{role:T,policy:y,roleLogicalId:v,policyLogicalId:h,resources:p}}static createCliUser(n){let{slug:i,environment:s,permissions:o="readonly"}=n,c={},u=[],d=[];switch(o){case"readonly":d=[de.ManagedPolicies.ReadOnlyAccess];break;case"deploy":u=[{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":d=[de.ManagedPolicies.AdministratorAccess];break}let p,y;if(u.length>0){let T=de.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cli-policy"}),description:`CLI access policy for ${i} (${s})`,statements:u});p=T.policy,y=T.logicalId,c[y]=p,d=[x.Ref(y)]}let{user:h,logicalId:b}=de.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cli-user"}),managedPolicyArns:d});c[b]=h;let{accessKey:v,logicalId:A}=de.createAccessKey(b,{slug:i,environment:s});return c[A]=v,{user:h,accessKey:v,policy:p,userLogicalId:b,accessKeyLogicalId:A,policyLogicalId:y,resources:c}}static CiCdPolicies={s3Deployment:(n)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:n},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:n.map((i)=>`${i}/*`)}],cloudFrontInvalidation:(n)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:n}],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:(n)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:n}],lambdaDeployment:(n)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:n}],cloudFormationDeployment:(n)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:n}]}}class ml{static createRestApi(n){let{slug:i,environment:s,name:o,description:c,endpointType:u="REGIONAL",binaryMediaTypes:d,compressionSize:p}=n,y=o||r({slug:i,environment:s,resourceType:"rest-api"}),h=t(y),b={Type:"AWS::ApiGateway::RestApi",Properties:{Name:y,Description:c||`REST API for ${i} ${s}`,EndpointConfiguration:{Types:[u]},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s}]}};if(d&&d.length>0)b.Properties.BinaryMediaTypes=d;if(p!==void 0)b.Properties.MinimumCompressionSize=p;return{restApi:b,logicalId:h}}static createHttpApi(n){let{slug:i,environment:s,name:o,description:c,corsEnabled:u=!0,corsOrigins:d=["*"],corsMethods:p=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:y=["*"],corsMaxAge:h=86400,corsAllowCredentials:b=!1}=n,v=o||r({slug:i,environment:s,resourceType:"http-api"}),A=t(v),T={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:v,Description:c||`HTTP API for ${i} ${s}`,ProtocolType:"HTTP",Tags:{Name:v,Environment:s}}};if(u)T.Properties.CorsConfiguration={AllowOrigins:d,AllowMethods:p,AllowHeaders:y,MaxAge:h,AllowCredentials:b};return{httpApi:T,logicalId:A}}static createWebSocketApi(n){let{slug:i,environment:s,name:o,description:c}=n,u=o||r({slug:i,environment:s,resourceType:"ws-api"}),d=t(u);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:u,Description:c||`WebSocket API for ${i} ${s}`,ProtocolType:"WEBSOCKET",Tags:{Name:u,Environment:s}}},logicalId:d}}static createDeployment(n,i){let{slug:s,environment:o,description:c}=i,u=r({slug:s,environment:o,resourceType:"api-deployment"}),d=t(u);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:x.Ref(n),Description:c||`Deployment for ${u}`}},logicalId:d}}static createStage(n,i,s){let{slug:o,environment:c,stageName:u,description:d,cacheEnabled:p=!1,cacheSize:y="0.5",variables:h,throttling:b}=s,v=r({slug:o,environment:c,resourceType:"api-stage"}),A=t(v),T={Type:"AWS::ApiGateway::Stage",Properties:{StageName:u||c,RestApiId:x.Ref(n),DeploymentId:x.Ref(i),Description:d,CacheClusterEnabled:p,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:c}]}};if(p)T.Properties.CacheClusterSize=y;if(h)T.Properties.Variables=h;if(b)T.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:b.burstLimit,ThrottlingRateLimit:b.rateLimit}];return{stage:T,logicalId:A}}static createAuthorizer(n,i){let{slug:s,environment:o,name:c,type:u,functionArn:d,identitySource:p,userPoolArns:y,ttl:h=300}=i,b=c||r({slug:s,environment:o,resourceType:"api-authorizer"}),v=t(b),A={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:b,Type:u,RestApiId:x.Ref(n),AuthorizerResultTtlInSeconds:h}};if(u==="TOKEN"||u==="REQUEST"){if(!d)throw Error("Lambda authorizer requires functionArn");A.Properties.AuthorizerUri=d,A.Properties.IdentitySource=p||"method.request.header.Authorization"}if(u==="COGNITO_USER_POOLS"){if(!y||y.length===0)throw Error("Cognito authorizer requires userPoolArns");A.Properties.ProviderARNs=y,A.Properties.IdentitySource=p||"method.request.header.Authorization"}return{authorizer:A,logicalId:v}}static setCors(n,i={}){let{origins:s=["*"],methods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:c=["*"],maxAge:u=86400,allowCredentials:d=!1}=i;return n.Properties.CorsConfiguration={AllowOrigins:s,AllowMethods:o,AllowHeaders:c,MaxAge:u,AllowCredentials:d},n}static addThrottling(n,i=5000,s=1e4){if(!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:i,ThrottlingRateLimit:s}),n}static enableCaching(n,i="0.5",s=300){if(n.Properties.CacheClusterEnabled=!0,n.Properties.CacheClusterSize=i,!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:s}),n}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class le{static createTopic(n){let{slug:i,environment:s,topicName:o,displayName:c,encrypted:u=!1,kmsKeyId:d}=n,p=o||r({slug:i,environment:s,resourceType:"topic"}),y=t(p),h={Type:"AWS::SNS::Topic",Properties:{TopicName:p,DisplayName:c||p,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(u&&d)h.Properties.KmsMasterKeyId=d;return{topic:h,logicalId:y}}static subscribe(n,i){let{slug:s,environment:o,protocol:c,endpoint:u,filterPolicy:d,rawMessageDelivery:p=!1}=i,y=r({slug:s,environment:o,resourceType:"subscription"}),h=u.replace(/[^a-zA-Z0-9]/g,""),b=h.length>12?h.slice(-12):h,v=t(`${y}-${c}-${b}`),A={Type:"AWS::SNS::Subscription",Properties:{TopicArn:x.Ref(n),Protocol:c,Endpoint:u,RawMessageDelivery:p}};if(d)A.Properties.FilterPolicy=d;return{subscription:A,logicalId:v}}static subscribeEmail(n,i,s){return le.subscribe(n,{...s,protocol:"email",endpoint:i})}static subscribeLambda(n,i,s){return le.subscribe(n,{...s,protocol:"lambda",endpoint:i,rawMessageDelivery:!0})}static subscribeSqs(n,i,s){return le.subscribe(n,{...s,protocol:"sqs",endpoint:i})}static subscribeHttp(n,i,s){let o=i.startsWith("https://")?"https":"http";return le.subscribe(n,{...s,protocol:o,endpoint:i})}static subscribeSms(n,i,s){return le.subscribe(n,{...s,protocol:"sms",endpoint:i})}static setTopicPolicy(n,i){let{slug:s,environment:o,allowedPrincipals:c,allowedServices:u,actions:d="SNS:Publish"}=i,p=r({slug:s,environment:o,resourceType:"topic-policy"}),y=t(p),h={};if(c)h.AWS=c;if(u)h.Service=u;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[x.Ref(n)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:h,Action:d,Resource:x.Ref(n)}]}}},logicalId:y}}static allowCloudWatchAlarms(n,i){return le.setTopicPolicy(n,{...i,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(n,i){return le.setTopicPolicy(n,{...i,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(n,i){return le.setTopicPolicy(n,{...i,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(n,i){if(!n.Properties)n.Properties={};return n.Properties.KmsMasterKeyId=i,n}static addInlineSubscription(n,i,s){if(!n.Properties)n.Properties={};if(!n.Properties.Subscription)n.Properties.Subscription=[];return n.Properties.Subscription.push({Protocol:i,Endpoint:s}),n}static FilterPolicies={eventType:(n)=>({eventType:n}),status:(n)=>({status:n}),numericRange:(n,i,s)=>({[n]:[{numeric:[">=",i,"<=",s]}]}),prefix:(n,i)=>({[n]:[{prefix:i}]}),and:(...n)=>Object.assign({},...n),exists:(n,i)=>({[n]:[{exists:i}]})};static UseCases={createAlertTopic:(n)=>le.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-alerts`,displayName:n.displayName||"Alert Notifications"}),createEventFanout:(n)=>le.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-events`,displayName:n.displayName||"Event Fanout"}),createNotificationTopic:(n)=>le.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-notifications`,displayName:n.displayName||"User Notifications"})}}class ay{static createStateMachine(n){let{slug:i,environment:s,stateMachineName:o,type:c="STANDARD",definition:u,roleArn:d,loggingConfiguration:p,tracingConfiguration:y}=n,h=o||r({slug:i,environment:s,resourceType:"state-machine"}),b=t(h),v,A,T;if(d)T=d;else{let P=r({slug:i,environment:s,resourceType:"state-machine-role"});A=t(P),v={Type:"AWS::IAM::Role",Properties:{RoleName:P,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:P},{Key:"Environment",Value:s}]}},T=x.GetAtt(A,"Arn")}let R={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:h,StateMachineType:c,DefinitionString:JSON.stringify(u),RoleArn:T,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(p)R.Properties.LoggingConfiguration={Level:p.level,IncludeExecutionData:p.includeExecutionData,Destinations:p.destinations?.map((P)=>({CloudWatchLogsLogGroup:{LogGroupArn:P}}))};if(y)R.Properties.TracingConfiguration={Enabled:y.enabled};return{stateMachine:R,logicalId:b,role:v,roleLogicalId:A}}static createLambdaTask(n,i){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:n,Payload:i?.parameters||{"Input.$":"$"}},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createDynamoDBTask(n,i,s,o){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"}[n],Parameters:{TableName:i,...s},ResultPath:o?.resultPath,Retry:o?.retry,Catch:o?.catch,Next:o?.next,End:o?.end}}static createSNSPublishTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:n,Message:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createSQSSendMessageTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:n,MessageBody:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createPassState(n){return{Type:"Pass",Result:n?.result,ResultPath:n?.resultPath,Parameters:n?.parameters,Next:n?.next,End:n?.end}}static createWaitState(n){return{Type:"Wait",Seconds:n.seconds,Timestamp:n.timestamp,SecondsPath:n.secondsPath,TimestampPath:n.timestampPath,Next:n.next,End:n.end}}static createChoiceState(n,i){return{Type:"Choice",Choices:n,Default:i}}static createParallelState(n,i){return{Type:"Parallel",Branches:n,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createMapState(n,i){return{Type:"Map",ItemsPath:i?.itemsPath||"$.items",Iterator:n,MaxConcurrency:i?.maxConcurrency,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(n,i){return{Type:"Fail",Error:n,Cause:i}}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:(n,i,s,o)=>({ErrorEquals:n,IntervalSeconds:i,MaxAttempts:s,BackoffRate:o})};static CatchPolicies={all:(n,i)=>({ErrorEquals:["States.ALL"],Next:n,ResultPath:i||"$.error"}),specific:(n,i,s)=>({ErrorEquals:n,Next:i,ResultPath:s||"$.error"})};static Patterns={sequential:(n,i,s)=>{let o={};return s.forEach((c,u)=>{let d=u===s.length-1;o[c.name]={...c.state,Next:d?void 0:s[u+1].name,End:d}}),{Comment:"Sequential workflow",StartAt:s[0].name,States:o}},fanout:(n,i,s)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:s.map((o)=>o.definition),End:!0}}}),map:(n,i,s,o)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:s,MaxConcurrency:o,End:!0}}}),withErrorHandling:(n,i,s,o)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...s,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:o,Success:{Type:"Succeed"}}})}}class qo{static createAlarm(n){let{slug:i,environment:s,alarmName:o,metricName:c,namespace:u,statistic:d="Average",period:p=300,evaluationPeriods:y=1,threshold:h,comparisonOperator:b,treatMissingData:v="notBreaching",actionsEnabled:A=!0,alarmActions:T,okActions:R,insufficientDataActions:P,dimensions:I,unit:M,datapointsToAlarm:L}=n,N=o||r({slug:i,environment:s,resourceType:"alarm"}),O=t(N),B={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:N,MetricName:c,Namespace:u,Statistic:d,Period:p,EvaluationPeriods:y,Threshold:h,ComparisonOperator:b,TreatMissingData:v,ActionsEnabled:A}};if(T&&T.length>0)B.Properties.AlarmActions=T;if(R&&R.length>0)B.Properties.OKActions=R;if(P&&P.length>0)B.Properties.InsufficientDataActions=P;if(I)B.Properties.Dimensions=Object.entries(I).map(([F,U])=>({Name:F,Value:U}));if(M)B.Properties.Unit=M;if(L!==void 0)B.Properties.DatapointsToAlarm=L;return{alarm:B,logicalId:O}}static createCompositeAlarm(n){let{slug:i,environment:s,alarmName:o,alarmRule:c,actionsEnabled:u=!0,alarmActions:d,okActions:p,insufficientDataActions:y}=n,h=o||r({slug:i,environment:s,resourceType:"composite-alarm"}),b=t(h),v={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:h,AlarmRule:c,ActionsEnabled:u}};if(d&&d.length>0)v.Properties.AlarmActions=d;if(p&&p.length>0)v.Properties.OKActions=p;if(y&&y.length>0)v.Properties.InsufficientDataActions=y;return{alarm:v,logicalId:b}}static createDashboard(n){let{slug:i,environment:s,dashboardName:o,widgets:c}=n,u=o||r({slug:i,environment:s,resourceType:"dashboard"}),d=t(u),p={widgets:c.map((h)=>({type:h.type,x:h.x,y:h.y,width:h.width,height:h.height,properties:h.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:u,DashboardBody:JSON.stringify(p)}},logicalId:d}}static createLogGroup(n){let{slug:i,environment:s,logGroupName:o,retentionInDays:c,kmsKeyId:u}=n,d=o||r({slug:i,environment:s,resourceType:"log-group"}),p=t(d),y={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:d}};if(c!==void 0)y.Properties.RetentionInDays=c;if(u)y.Properties.KmsKeyId=u;return{logGroup:y,logicalId:p}}static createLogStream(n,i){let{slug:s,environment:o,logStreamName:c}=i,u=c||r({slug:s,environment:o,resourceType:"log-stream"}),d=t(u);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:x.Ref(n),LogStreamName:u}},logicalId:d}}static createMetricFilter(n,i){let{slug:s,environment:o,filterName:c,filterPattern:u,metricTransformations:d}=i,p=c||r({slug:s,environment:o,resourceType:"metric-filter"}),y=t(p);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:x.Ref(n),FilterPattern:u,MetricTransformations:d.map((b)=>({MetricName:b.metricName,MetricNamespace:b.metricNamespace,MetricValue:b.metricValue,DefaultValue:b.defaultValue,Unit:b.unit}))}},logicalId:y}}static AlarmTypes={highCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highMemory:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highDisk:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:c?[c]:void 0}),lambdaErrors:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),lambdaThrottles:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),apiGateway5xxErrors:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),apiGateway4xxErrors:(n,i,s,o=50,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),dynamoDBThrottles:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:s},alarmActions:c?[c]:void 0}),rdsCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0}),rdsFreeStorage:(n,i,s,o=5368709120,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0,unit:"Bytes"}),sqsQueueDepth:(n,i,s,o=100,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:s},alarmActions:c?[c]:void 0}),albUnhealthyTargets:(n,i,s,o,c=1,u)=>({slug:n,environment:i,alarmName:`${n}-${i}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:c,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:s,TargetGroup:o},alarmActions:u?[u]:void 0}),sesBounceRate:(n,i,s=5,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),sesComplaintRate:(n,i,s=0.1,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),smsDeliveryFailure:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:s},alarmActions:c?[c]:void 0}),smsSpendLimit:(n,i,s=100,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:s,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),connectMissedCalls:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0})};static DashboardWidgets={metric:(n,i,s,o,c,u)=>({type:"metric",x:n,y:i,width:s,height:o,properties:{metrics:c,title:u||"Metrics",region:"us-east-1",period:300}}),text:(n,i,s,o,c)=>({type:"text",x:n,y:i,width:s,height:o,properties:{markdown:c}}),log:(n,i,s,o,c,u)=>({type:"log",x:n,y:i,width:s,height:o,properties:{query:`SOURCE '${c.join("' | SOURCE '")}'
|
|
2274
|
+
`;class X{static LambdaCode={send:Ct,receive:on,deliveryStatus:an};static createPinpointApp(n){return{[`${n.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:n.name||`${n.slug}-sms`}}}}static createSmsChannel(n){let i={ApplicationId:n.applicationId,Enabled:n.enabled!==!1};if(n.senderId)i.SenderId=n.senderId;if(n.shortCode)i.ShortCode=n.shortCode;return{[`${n.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:i}}}static createSmsLambdaRole(n){return{[`${n.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.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(n){return{[`${n.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:X.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:n.pinpointAppId,MESSAGE_LOG_TABLE:n.messageLogTable||"",SMS_SENDER_ID:n.senderId||"",SMS_ORIGINATION_NUMBER:n.originationNumber||""}}}}}}static createReceiveLambda(n){return{[`${n.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:X.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:n.optOutTable||"",MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createDeliveryStatusLambda(n){return{[`${n.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:X.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createMessageLogTable(n){return{[`${n.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(n){return{[`${n.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(n){return{[`${n.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-sms-notifications`}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,X.createPinpointApp({slug:n.slug})),Object.assign(i,X.createSmsChannel({slug:n.slug,applicationId:{Ref:`${n.slug}PinpointApp`},senderId:n.senderId})),Object.assign(i,X.createSmsLambdaRole({slug:n.slug})),Object.assign(i,X.createMessageLogTable({slug:n.slug})),Object.assign(i,X.createOptOutTable({slug:n.slug})),Object.assign(i,X.createNotificationTopic({slug:n.slug}));let o={"Fn::GetAtt":[`${n.slug}SmsLambdaRole`,"Arn"]},c={Ref:`${n.slug}PinpointApp`},u={Ref:`${n.slug}SmsMessageLogTable`},d={Ref:`${n.slug}SmsOptOutTable`},p={Ref:`${n.slug}SmsNotificationTopic`};if(Object.assign(i,X.createSendLambda({slug:n.slug,roleArn:o,pinpointAppId:c,messageLogTable:u,senderId:n.senderId,originationNumber:n.originationNumber})),n.twoWayEnabled)Object.assign(i,X.createReceiveLambda({slug:n.slug,roleArn:o,optOutTable:d,messageLogTable:u,notificationTopicArn:p,webhookUrl:n.webhookUrl}));return Object.assign(i,X.createDeliveryStatusLambda({slug:n.slug,roleArn:o,messageLogTable:u,notificationTopicArn:p,webhookUrl:n.webhookUrl})),s[`${n.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${n.slug}PinpointApp`}},s[`${n.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${n.slug}SmsSendLambda`,"Arn"]}},s[`${n.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${n.slug}SmsNotificationTopic`}},s[`${n.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${n.slug}SmsMessageLogTable`}},{resources:i,outputs:s}}}function vt(n){return n.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((o)=>o.charAt(0).toUpperCase()+o.slice(1)).join("")||"User"}function Er(n,i){let s=(n||i).replace(/^\/+|\/+$/g,"");if(!s||s.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${i}`);return s}function wr(n){let i=n.storage;if(i?.type==="efs"){let o="fileSystemId"in i?i.fileSystemId:void 0;if(!o||typeof o==="string"&&!o.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:o,posixProfile:i.posixProfile}}let s=(i?.type==="s3"?i.bucket??n.bucket:n.bucket)?.trim();if(!s)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:s}}function Ir(n,i,s){let o=i.posixProfile??s;if(!o)throw Error(`sftp: user ${n} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let c of[o.uid,o.gid,...o.secondaryGids??[]])if(!Number.isInteger(c)||c<0||c>4294967295)throw Error(`sftp: user ${n} has an invalid posixProfile id ${c}`);return{Uid:o.uid,Gid:o.gid,...o.secondaryGids?.length?{SecondaryGids:o.secondaryGids}:{}}}function Dr(n,i){return typeof n==="string"?`/${n}/${i}`:{"Fn::Sub":[`/\${FileSystemId}/${i}`,{FileSystemId:n}]}}function Nr(n){return typeof n==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",n)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:n}]}}class pl{static create(n){let i=wr(n),s=i.type==="efs"?"EFS":"S3",o=n.endpointType??"PUBLIC";if(o==="VPC"&&(!n.endpointDetails?.vpcId||!n.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let c=`${vt(n.slug)}${vt(n.environment)}Sftp`,u=`${c}Server`,d={},p;if(n.logging!==!1){let y=`${c}LoggingRole`;d[y]={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/*"}]}}]}},p={"Fn::GetAtt":[y,"Arn"]}}d[u]={Type:"AWS::Transfer::Server",Properties:{Domain:s,EndpointType:o,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...o==="VPC"?{EndpointDetails:{VpcId:n.endpointDetails.vpcId,SubnetIds:n.endpointDetails.subnetIds,...n.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:n.endpointDetails.securityGroupIds}:{},...n.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:n.endpointDetails.addressAllocationIds}:{}}}:{},...n.securityPolicyName?{SecurityPolicyName:n.securityPolicyName}:{},...p?{LoggingRole:p}:{},Tags:[{Key:"Project",Value:n.slug},{Key:"Environment",Value:n.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[y,h]of Object.entries(n.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(y))throw Error(`sftp: invalid username ${y}`);if(!h.sshPublicKeys.length)throw Error(`sftp: user ${y} requires at least one SSH public key`);let b=vt(y),v=Er(h.homeDirectory,y),A=`${c}${b}User`,T=h.roleArn;if(!T){let R=`${c}${b}Role`,P;if(i.type==="efs")P=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Nr(i.fileSystemId)}];else{let I=`arn:aws:s3:::${i.bucket}`;P=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:I,Condition:{StringLike:{"s3:prefix":[v,`${v}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${I}/${v}/*`}]}d[R]={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:P}}]}},T={"Fn::GetAtt":[R,"Arn"]}}d[A]={Type:"AWS::Transfer::User",DependsOn:[u],Properties:{ServerId:{Ref:u},UserName:y,Role:T,HomeDirectoryType:"PATH",HomeDirectory:i.type==="efs"?Dr(i.fileSystemId,v):`/${i.bucket}/${v}`,...i.type==="efs"?{PosixProfile:Ir(y,h,i.posixProfile)}:{},SshPublicKeys:h.sshPublicKeys}}}return{resources:d,serverLogicalId:u,domain:s}}}class Oe{static createBedrockRole(n,i){let{slug:s,environment:o,name:c,models:u=["*"],allowStreaming:d=!0}=i,p=c||r({slug:s,environment:o,resourceType:"bedrock-role"}),y=t(p),h=["bedrock:InvokeModel"];if(d)h.push("bedrock:InvokeModelWithResponseStream");let b=u.map((A)=>A==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${A}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:p,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:n},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${p}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:h,Resource:b}]}}],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:o}]}},logicalId:y}}static createBedrockPolicy(n){let{slug:i,environment:s,name:o,models:c=["*"],allowInvoke:u=!0,allowStreaming:d=!0,allowAsync:p=!1}=n,y=o||r({slug:i,environment:s,resourceType:"bedrock-policy"}),h=t(y),b=[];if(u)b.push("bedrock:InvokeModel");if(d)b.push("bedrock:InvokeModelWithResponseStream");if(p)b.push("bedrock:InvokeModelAsync");let v=c.map((T)=>T==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${T}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:y,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:b,Resource:v}]}}},logicalId:h}}static enableBedrockForLambda(n){return Oe.createBedrockRole("lambda.amazonaws.com",n)}static enableBedrockForEcs(n){return Oe.createBedrockRole("ecs-tasks.amazonaws.com",n)}static enableBedrockForEc2(n){return Oe.createBedrockRole("ec2.amazonaws.com",n)}static addBedrockPermissions(n,i=["*"],s=!0){let o=["bedrock:InvokeModel"];if(s)o.push("bedrock:InvokeModelWithResponseStream");let c=i.map((u)=>u==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${u}`);if(!n.Properties.Policies)n.Properties.Policies=[];return n.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:o,Resource:c}]}}),n}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 ur{static createPostgres(n){return ur.createRDSInstance("postgres","16.2",n)}static createMysql(n){return ur.createRDSInstance("mysql","8.0.35",n)}static createRDSInstance(n,i,s){let{slug:o,environment:c,instanceClass:u="db.t3.micro",allocatedStorage:d=20,storageType:p="gp3",masterUsername:y="admin",masterPassword:h,databaseName:b,subnetIds:v,securityGroupIds:A,encrypted:T=!0,kmsKeyId:R,multiAz:P=!1,backupRetentionDays:I=7,publiclyAccessible:M=!1,enableCloudwatchLogs:L=!0,deletionProtection:N=!0}=s,O=r({slug:o,environment:c,resourceType:`${n}-db`}),B=t(O),F,U;if(v&&v.length>0){let H=r({slug:o,environment:c,resourceType:"db-subnet-group"});U=t(H),F={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:H,DBSubnetGroupDescription:`Subnet group for ${O}`,SubnetIds:v,Tags:[{Key:"Name",Value:H},{Key:"Environment",Value:c}]}}}let j={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:O,DBInstanceClass:u,Engine:n,EngineVersion:i,MasterUsername:y,MasterUserPassword:h,AllocatedStorage:d,StorageType:p,StorageEncrypted:T,MultiAZ:P,BackupRetentionPeriod:I,PubliclyAccessible:M,DeletionProtection:N,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:c}]}};if(b)j.Properties.DBName=b;if(R)j.Properties.KmsKeyId=R;if(U)j.Properties.DBSubnetGroupName=x.Ref(U);if(A&&A.length>0)j.Properties.VPCSecurityGroups=A;if(L)j.Properties.EnableCloudwatchLogsExports=n==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:j,subnetGroup:F,logicalId:B,subnetGroupId:U}}static createReadReplica(n,i){let{slug:s,environment:o,instanceClass:c="db.t3.micro",securityGroupIds:u,publiclyAccessible:d=!1}=i,p=r({slug:s,environment:o,resourceType:"db-replica"}),y=t(p),h={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:p,DBInstanceClass:c,SourceDBInstanceIdentifier:x.Ref(n),PubliclyAccessible:d,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:o},{Key:"Type",Value:"ReadReplica"}]}};if(u&&u.length>0)h.Properties.VPCSecurityGroups=u;return{replica:h,logicalId:y}}static createParameterGroup(n,i,s){let{slug:o,environment:c,parameters:u={}}=s,d=r({slug:o,environment:c,resourceType:"db-params"}),p=t(d),y=n==="postgres"?`postgres${i.split(".")[0]}`:`mysql${i.split(".")[0]}.${i.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:d,Description:`Parameter group for ${d}`,Family:y,Parameters:u,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:c}]}},logicalId:p}}static enableBackup(n,i=7){return n.Properties.BackupRetentionPeriod=i,n}static createTable(n){let{slug:i,environment:s,tableName:o,partitionKey:c,sortKey:u,billingMode:d="PAY_PER_REQUEST",readCapacity:p=5,writeCapacity:y=5,streamEnabled:h=!1,streamViewType:b="NEW_AND_OLD_IMAGES",encrypted:v=!0,kmsKeyId:A,pointInTimeRecovery:T=!0,ttlAttribute:R}=n,P=o||r({slug:i,environment:s,resourceType:"table"}),I=t(P),M=[{AttributeName:c.name,AttributeType:c.type}];if(u)M.push({AttributeName:u.name,AttributeType:u.type});let L=[{AttributeName:c.name,KeyType:"HASH"}];if(u)L.push({AttributeName:u.name,KeyType:"RANGE"});let N={Type:"AWS::DynamoDB::Table",Properties:{TableName:P,BillingMode:d,AttributeDefinitions:M,KeySchema:L,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:s}]}};if(d==="PROVISIONED")N.Properties.ProvisionedThroughput={ReadCapacityUnits:p,WriteCapacityUnits:y};if(h)N.Properties.StreamSpecification={StreamViewType:b};if(v)N.Properties.SSESpecification={SSEEnabled:!0,SSEType:A?"KMS":"AES256",KMSMasterKeyId:A};if(T)N.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(R)N.Properties.TimeToLiveSpecification={AttributeName:R,Enabled:!0};return{table:N,logicalId:I}}static addGlobalSecondaryIndex(n,i){let{indexName:s,partitionKey:o,sortKey:c,projectionType:u="ALL",nonKeyAttributes:d,readCapacity:p=5,writeCapacity:y=5}=i;if(!n.Properties.AttributeDefinitions.some((v)=>v.AttributeName===o.name))n.Properties.AttributeDefinitions.push({AttributeName:o.name,AttributeType:o.type});if(c&&!n.Properties.AttributeDefinitions.some((v)=>v.AttributeName===c.name))n.Properties.AttributeDefinitions.push({AttributeName:c.name,AttributeType:c.type});let h=[{AttributeName:o.name,KeyType:"HASH"}];if(c)h.push({AttributeName:c.name,KeyType:"RANGE"});let b={IndexName:s,KeySchema:h,Projection:{ProjectionType:u,NonKeyAttributes:u==="INCLUDE"?d:void 0},ProvisionedThroughput:void 0};if(n.Properties.BillingMode==="PROVISIONED")b.ProvisionedThroughput={ReadCapacityUnits:p,WriteCapacityUnits:y};if(!n.Properties.GlobalSecondaryIndexes)n.Properties.GlobalSecondaryIndexes=[];return n.Properties.GlobalSecondaryIndexes.push(b),n}static enableStreams(n,i="NEW_AND_OLD_IMAGES"){return n.Properties.StreamSpecification={StreamViewType:i},n}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 Vo{static createRedis(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="7.1",port:u=6379,subnetIds:d,securityGroupIds:p,numCacheClusters:y=2,automaticFailover:h=!0,multiAz:b=!0,clusterMode:v=!1,numNodeGroups:A=1,replicasPerNodeGroup:T=1,atRestEncryption:R=!0,transitEncryption:P=!0,authToken:I,kmsKeyId:M,snapshotRetentionDays:L=7,snapshotWindow:N,maintenanceWindow:O}=n,B=r({slug:i,environment:s,resourceType:"redis"}),F=t(B),U,j;if(d&&d.length>0){let z=r({slug:i,environment:s,resourceType:"cache-subnet-group"});j=t(z),U={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:z,Description:`Subnet group for ${B}`,SubnetIds:d,Tags:[{Key:"Name",Value:z},{Key:"Environment",Value:s}]}}}let H={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:B,ReplicationGroupDescription:`Redis cluster for ${i} ${s}`,Engine:"redis",EngineVersion:c,CacheNodeType:o,Port:u,AutomaticFailoverEnabled:h,MultiAZEnabled:b,AtRestEncryptionEnabled:R,TransitEncryptionEnabled:P,SnapshotRetentionLimit:L,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:B},{Key:"Environment",Value:s}]}};if(v)H.Properties.NumNodeGroups=A,H.Properties.ReplicasPerNodeGroup=T;else H.Properties.NumCacheClusters=y;if(I)H.Properties.AuthToken=I;if(M)H.Properties.KmsKeyId=M;if(j)H.Properties.CacheSubnetGroupName=x.Ref(j);if(p&&p.length>0)H.Properties.SecurityGroupIds=p;if(N)H.Properties.SnapshotWindow=N;if(O)H.Properties.PreferredMaintenanceWindow=O;return{replicationGroup:H,subnetGroup:U,logicalId:F,subnetGroupId:j}}static createMemcached(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="1.6.22",port:u=11211,numCacheNodes:d=2,subnetIds:p,securityGroupIds:y,azMode:h="cross-az",preferredAzs:b,maintenanceWindow:v}=n,A=r({slug:i,environment:s,resourceType:"memcached"}),T=t(A),R,P;if(p&&p.length>0){let M=r({slug:i,environment:s,resourceType:"cache-subnet-group"});P=t(M),R={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:M,Description:`Subnet group for ${A}`,SubnetIds:p,Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:s}]}}}let I={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:A,CacheNodeType:o,Engine:"memcached",EngineVersion:c,NumCacheNodes:d,Port:u,AZMode:h,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:A},{Key:"Environment",Value:s}]}};if(P)I.Properties.CacheSubnetGroupName=x.Ref(P);if(y&&y.length>0)I.Properties.VpcSecurityGroupIds=y;if(b&&b.length>0)I.Properties.PreferredAvailabilityZones=b;if(v)I.Properties.PreferredMaintenanceWindow=v;return{cluster:I,subnetGroup:R,logicalId:T,subnetGroupId:P}}static enableClusterMode(n,i=3,s=2){return delete n.Properties.NumCacheClusters,n.Properties.NumNodeGroups=i,n.Properties.ReplicasPerNodeGroup=s,n}static createRedisParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,u=r({slug:s,environment:o,resourceType:"redis-params"}),d=t(u);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${n.split(".")[0]}.x`,Description:`Parameter group for ${u}`,Properties:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o}]}},logicalId:d}}static createMemcachedParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,u=r({slug:s,environment:o,resourceType:"memcached-params"}),d=t(u);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${n.split(".")[0]}.${n.split(".")[1]}`,Description:`Parameter group for ${u}`,Properties:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:o}]}},logicalId:d}}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 de{static createUser(n){let{slug:i,environment:s,userName:o,groups:c,managedPolicyArns:u}=n,d=o||r({slug:i,environment:s,resourceType:"user"}),p=t(d),y={Type:"AWS::IAM::User",Properties:{UserName:d,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:s}]}};if(c&&c.length>0)y.Properties.Groups=c;if(u&&u.length>0)y.Properties.ManagedPolicyArns=u;return{user:y,logicalId:p}}static createRole(n){let{slug:i,environment:s,roleName:o,servicePrincipal:c,awsPrincipal:u,managedPolicyArns:d}=n,p=o||r({slug:i,environment:s,resourceType:"role"}),y=t(p),h={};if(c)h.Service=c;if(u)h.AWS=u;let b={Type:"AWS::IAM::Role",Properties:{RoleName:p,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:h,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(d&&d.length>0)b.Properties.ManagedPolicyArns=d;return{role:b,logicalId:y}}static createGroup(n){let{slug:i,environment:s,groupName:o,managedPolicyArns:c}=n,u=o||r({slug:i,environment:s,resourceType:"group"}),d=t(u),p={Type:"AWS::IAM::Group",Properties:{GroupName:u}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{group:p,logicalId:d}}static createPolicy(n){let{slug:i,environment:s,policyName:o,description:c,statements:u}=n,d=o||r({slug:i,environment:s,resourceType:"policy"}),p=t(d),y=u.map((b)=>({Sid:b.sid,Effect:b.effect||"Allow",Action:b.actions,Resource:b.resources,Condition:b.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,Description:c||`Managed policy for ${d}`,PolicyDocument:{Version:"2012-10-17",Statement:y}}},logicalId:p}}static attachPolicyToRole(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToUser(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToGroup(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static addInlinePolicyToRole(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static addInlinePolicyToUser(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static createAccessKey(n,i){let{slug:s,environment:o,status:c="Active"}=i,u=r({slug:s,environment:o,resourceType:"access-key"}),d=t(u);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:x.Ref(n),Status:c}},logicalId:d}}static createInstanceProfile(n,i){let{slug:s,environment:o,profileName:c}=i,u=c||r({slug:s,environment:o,resourceType:"instance-profile"}),d=t(u);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:u,Roles:[x.Ref(n)]}},logicalId:d}}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(n){let{slug:i,environment:s,permissions:o,createAccessKey:c=!0}=n,u={},d=[];if(o.s3Buckets&&o.s3Buckets.length>0)d.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...o.s3Buckets,...o.s3Buckets.map((T)=>`${T}/*`)]});if(o.cloudFrontDistributions&&o.cloudFrontDistributions.length>0)d.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:o.cloudFrontDistributions});if(o.ecrRepositories&&o.ecrRepositories.length>0)d.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:o.ecrRepositories}),d.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(o.ecsServices&&o.ecsServices.length>0)d.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:o.ecsServices}),d.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),d.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(o.cloudFormationStacks&&o.cloudFormationStacks.length>0)d.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:o.cloudFormationStacks});if(o.lambdaFunctions&&o.lambdaFunctions.length>0)d.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:o.lambdaFunctions});if(o.secretsManagerSecrets&&o.secretsManagerSecrets.length>0)d.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:o.secretsManagerSecrets});let{policy:p,logicalId:y}=de.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${i} (${s})`,statements:d});u[y]=p;let{user:h,logicalId:b}=de.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cicd-user"}),managedPolicyArns:[x.Ref(y)]});u[b]=h;let v,A;if(c){let T=de.createAccessKey(b,{slug:i,environment:s});v=T.accessKey,A=T.logicalId,u[A]=v}return{user:h,accessKey:v,policy:p,userLogicalId:b,accessKeyLogicalId:A,policyLogicalId:y,resources:u}}static createCrossAccountRole(n){let{slug:i,environment:s,trustedAccountIds:o,externalId:c,permissions:u,maxSessionDuration:d=3600}=n,p={},{policy:y,logicalId:h}=de.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${i} (${s})`,statements:u});p[h]=y;let b=r({slug:i,environment:s,resourceType:"cross-account-role"}),v=t(b),A={};if(c)A.StringEquals={"sts:ExternalId":c};let T={Type:"AWS::IAM::Role",Properties:{RoleName:b,MaxSessionDuration:d,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:o.map((R)=>`arn:aws:iam::${R}:root`)},Action:"sts:AssumeRole",...Object.keys(A).length>0?{Condition:A}:{}}]},ManagedPolicyArns:[x.Ref(h)],Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Cross-Account Access"}]}};return p[v]=T,{role:T,policy:y,roleLogicalId:v,policyLogicalId:h,resources:p}}static createCliUser(n){let{slug:i,environment:s,permissions:o="readonly"}=n,c={},u=[],d=[];switch(o){case"readonly":d=[de.ManagedPolicies.ReadOnlyAccess];break;case"deploy":u=[{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":d=[de.ManagedPolicies.AdministratorAccess];break}let p,y;if(u.length>0){let T=de.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cli-policy"}),description:`CLI access policy for ${i} (${s})`,statements:u});p=T.policy,y=T.logicalId,c[y]=p,d=[x.Ref(y)]}let{user:h,logicalId:b}=de.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cli-user"}),managedPolicyArns:d});c[b]=h;let{accessKey:v,logicalId:A}=de.createAccessKey(b,{slug:i,environment:s});return c[A]=v,{user:h,accessKey:v,policy:p,userLogicalId:b,accessKeyLogicalId:A,policyLogicalId:y,resources:c}}static CiCdPolicies={s3Deployment:(n)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:n},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:n.map((i)=>`${i}/*`)}],cloudFrontInvalidation:(n)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:n}],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:(n)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:n}],lambdaDeployment:(n)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:n}],cloudFormationDeployment:(n)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:n}]}}class ml{static createRestApi(n){let{slug:i,environment:s,name:o,description:c,endpointType:u="REGIONAL",binaryMediaTypes:d,compressionSize:p}=n,y=o||r({slug:i,environment:s,resourceType:"rest-api"}),h=t(y),b={Type:"AWS::ApiGateway::RestApi",Properties:{Name:y,Description:c||`REST API for ${i} ${s}`,EndpointConfiguration:{Types:[u]},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s}]}};if(d&&d.length>0)b.Properties.BinaryMediaTypes=d;if(p!==void 0)b.Properties.MinimumCompressionSize=p;return{restApi:b,logicalId:h}}static createHttpApi(n){let{slug:i,environment:s,name:o,description:c,corsEnabled:u=!0,corsOrigins:d=["*"],corsMethods:p=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:y=["*"],corsMaxAge:h=86400,corsAllowCredentials:b=!1}=n,v=o||r({slug:i,environment:s,resourceType:"http-api"}),A=t(v),T={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:v,Description:c||`HTTP API for ${i} ${s}`,ProtocolType:"HTTP",Tags:{Name:v,Environment:s}}};if(u)T.Properties.CorsConfiguration={AllowOrigins:d,AllowMethods:p,AllowHeaders:y,MaxAge:h,AllowCredentials:b};return{httpApi:T,logicalId:A}}static createWebSocketApi(n){let{slug:i,environment:s,name:o,description:c}=n,u=o||r({slug:i,environment:s,resourceType:"ws-api"}),d=t(u);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:u,Description:c||`WebSocket API for ${i} ${s}`,ProtocolType:"WEBSOCKET",Tags:{Name:u,Environment:s}}},logicalId:d}}static createDeployment(n,i){let{slug:s,environment:o,description:c}=i,u=r({slug:s,environment:o,resourceType:"api-deployment"}),d=t(u);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:x.Ref(n),Description:c||`Deployment for ${u}`}},logicalId:d}}static createStage(n,i,s){let{slug:o,environment:c,stageName:u,description:d,cacheEnabled:p=!1,cacheSize:y="0.5",variables:h,throttling:b}=s,v=r({slug:o,environment:c,resourceType:"api-stage"}),A=t(v),T={Type:"AWS::ApiGateway::Stage",Properties:{StageName:u||c,RestApiId:x.Ref(n),DeploymentId:x.Ref(i),Description:d,CacheClusterEnabled:p,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:c}]}};if(p)T.Properties.CacheClusterSize=y;if(h)T.Properties.Variables=h;if(b)T.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:b.burstLimit,ThrottlingRateLimit:b.rateLimit}];return{stage:T,logicalId:A}}static createAuthorizer(n,i){let{slug:s,environment:o,name:c,type:u,functionArn:d,identitySource:p,userPoolArns:y,ttl:h=300}=i,b=c||r({slug:s,environment:o,resourceType:"api-authorizer"}),v=t(b),A={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:b,Type:u,RestApiId:x.Ref(n),AuthorizerResultTtlInSeconds:h}};if(u==="TOKEN"||u==="REQUEST"){if(!d)throw Error("Lambda authorizer requires functionArn");A.Properties.AuthorizerUri=d,A.Properties.IdentitySource=p||"method.request.header.Authorization"}if(u==="COGNITO_USER_POOLS"){if(!y||y.length===0)throw Error("Cognito authorizer requires userPoolArns");A.Properties.ProviderARNs=y,A.Properties.IdentitySource=p||"method.request.header.Authorization"}return{authorizer:A,logicalId:v}}static setCors(n,i={}){let{origins:s=["*"],methods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:c=["*"],maxAge:u=86400,allowCredentials:d=!1}=i;return n.Properties.CorsConfiguration={AllowOrigins:s,AllowMethods:o,AllowHeaders:c,MaxAge:u,AllowCredentials:d},n}static addThrottling(n,i=5000,s=1e4){if(!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:i,ThrottlingRateLimit:s}),n}static enableCaching(n,i="0.5",s=300){if(n.Properties.CacheClusterEnabled=!0,n.Properties.CacheClusterSize=i,!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:s}),n}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class le{static createTopic(n){let{slug:i,environment:s,topicName:o,displayName:c,encrypted:u=!1,kmsKeyId:d}=n,p=o||r({slug:i,environment:s,resourceType:"topic"}),y=t(p),h={Type:"AWS::SNS::Topic",Properties:{TopicName:p,DisplayName:c||p,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:s}]}};if(u&&d)h.Properties.KmsMasterKeyId=d;return{topic:h,logicalId:y}}static subscribe(n,i){let{slug:s,environment:o,protocol:c,endpoint:u,filterPolicy:d,rawMessageDelivery:p=!1}=i,y=r({slug:s,environment:o,resourceType:"subscription"}),h=u.replace(/[^a-zA-Z0-9]/g,""),b=h.length>12?h.slice(-12):h,v=t(`${y}-${c}-${b}`),A={Type:"AWS::SNS::Subscription",Properties:{TopicArn:x.Ref(n),Protocol:c,Endpoint:u,RawMessageDelivery:p}};if(d)A.Properties.FilterPolicy=d;return{subscription:A,logicalId:v}}static subscribeEmail(n,i,s){return le.subscribe(n,{...s,protocol:"email",endpoint:i})}static subscribeLambda(n,i,s){return le.subscribe(n,{...s,protocol:"lambda",endpoint:i,rawMessageDelivery:!0})}static subscribeSqs(n,i,s){return le.subscribe(n,{...s,protocol:"sqs",endpoint:i})}static subscribeHttp(n,i,s){let o=i.startsWith("https://")?"https":"http";return le.subscribe(n,{...s,protocol:o,endpoint:i})}static subscribeSms(n,i,s){return le.subscribe(n,{...s,protocol:"sms",endpoint:i})}static setTopicPolicy(n,i){let{slug:s,environment:o,allowedPrincipals:c,allowedServices:u,actions:d="SNS:Publish"}=i,p=r({slug:s,environment:o,resourceType:"topic-policy"}),y=t(p),h={};if(c)h.AWS=c;if(u)h.Service=u;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[x.Ref(n)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:h,Action:d,Resource:x.Ref(n)}]}}},logicalId:y}}static allowCloudWatchAlarms(n,i){return le.setTopicPolicy(n,{...i,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(n,i){return le.setTopicPolicy(n,{...i,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(n,i){return le.setTopicPolicy(n,{...i,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(n,i){if(!n.Properties)n.Properties={};return n.Properties.KmsMasterKeyId=i,n}static addInlineSubscription(n,i,s){if(!n.Properties)n.Properties={};if(!n.Properties.Subscription)n.Properties.Subscription=[];return n.Properties.Subscription.push({Protocol:i,Endpoint:s}),n}static FilterPolicies={eventType:(n)=>({eventType:n}),status:(n)=>({status:n}),numericRange:(n,i,s)=>({[n]:[{numeric:[">=",i,"<=",s]}]}),prefix:(n,i)=>({[n]:[{prefix:i}]}),and:(...n)=>Object.assign({},...n),exists:(n,i)=>({[n]:[{exists:i}]})};static UseCases={createAlertTopic:(n)=>le.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-alerts`,displayName:n.displayName||"Alert Notifications"}),createEventFanout:(n)=>le.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-events`,displayName:n.displayName||"Event Fanout"}),createNotificationTopic:(n)=>le.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-notifications`,displayName:n.displayName||"User Notifications"})}}class ay{static createStateMachine(n){let{slug:i,environment:s,stateMachineName:o,type:c="STANDARD",definition:u,roleArn:d,loggingConfiguration:p,tracingConfiguration:y}=n,h=o||r({slug:i,environment:s,resourceType:"state-machine"}),b=t(h),v,A,T;if(d)T=d;else{let P=r({slug:i,environment:s,resourceType:"state-machine-role"});A=t(P),v={Type:"AWS::IAM::Role",Properties:{RoleName:P,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:P},{Key:"Environment",Value:s}]}},T=x.GetAtt(A,"Arn")}let R={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:h,StateMachineType:c,DefinitionString:JSON.stringify(u),RoleArn:T,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(p)R.Properties.LoggingConfiguration={Level:p.level,IncludeExecutionData:p.includeExecutionData,Destinations:p.destinations?.map((P)=>({CloudWatchLogsLogGroup:{LogGroupArn:P}}))};if(y)R.Properties.TracingConfiguration={Enabled:y.enabled};return{stateMachine:R,logicalId:b,role:v,roleLogicalId:A}}static createLambdaTask(n,i){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:n,Payload:i?.parameters||{"Input.$":"$"}},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createDynamoDBTask(n,i,s,o){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"}[n],Parameters:{TableName:i,...s},ResultPath:o?.resultPath,Retry:o?.retry,Catch:o?.catch,Next:o?.next,End:o?.end}}static createSNSPublishTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:n,Message:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createSQSSendMessageTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:n,MessageBody:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createPassState(n){return{Type:"Pass",Result:n?.result,ResultPath:n?.resultPath,Parameters:n?.parameters,Next:n?.next,End:n?.end}}static createWaitState(n){return{Type:"Wait",Seconds:n.seconds,Timestamp:n.timestamp,SecondsPath:n.secondsPath,TimestampPath:n.timestampPath,Next:n.next,End:n.end}}static createChoiceState(n,i){return{Type:"Choice",Choices:n,Default:i}}static createParallelState(n,i){return{Type:"Parallel",Branches:n,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createMapState(n,i){return{Type:"Map",ItemsPath:i?.itemsPath||"$.items",Iterator:n,MaxConcurrency:i?.maxConcurrency,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(n,i){return{Type:"Fail",Error:n,Cause:i}}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:(n,i,s,o)=>({ErrorEquals:n,IntervalSeconds:i,MaxAttempts:s,BackoffRate:o})};static CatchPolicies={all:(n,i)=>({ErrorEquals:["States.ALL"],Next:n,ResultPath:i||"$.error"}),specific:(n,i,s)=>({ErrorEquals:n,Next:i,ResultPath:s||"$.error"})};static Patterns={sequential:(n,i,s)=>{let o={};return s.forEach((c,u)=>{let d=u===s.length-1;o[c.name]={...c.state,Next:d?void 0:s[u+1].name,End:d}}),{Comment:"Sequential workflow",StartAt:s[0].name,States:o}},fanout:(n,i,s)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:s.map((o)=>o.definition),End:!0}}}),map:(n,i,s,o)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:s,MaxConcurrency:o,End:!0}}}),withErrorHandling:(n,i,s,o)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...s,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:o,Success:{Type:"Succeed"}}})}}class qo{static createAlarm(n){let{slug:i,environment:s,alarmName:o,metricName:c,namespace:u,statistic:d="Average",period:p=300,evaluationPeriods:y=1,threshold:h,comparisonOperator:b,treatMissingData:v="notBreaching",actionsEnabled:A=!0,alarmActions:T,okActions:R,insufficientDataActions:P,dimensions:I,unit:M,datapointsToAlarm:L}=n,N=o||r({slug:i,environment:s,resourceType:"alarm"}),O=t(N),B={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:N,MetricName:c,Namespace:u,Statistic:d,Period:p,EvaluationPeriods:y,Threshold:h,ComparisonOperator:b,TreatMissingData:v,ActionsEnabled:A}};if(T&&T.length>0)B.Properties.AlarmActions=T;if(R&&R.length>0)B.Properties.OKActions=R;if(P&&P.length>0)B.Properties.InsufficientDataActions=P;if(I)B.Properties.Dimensions=Object.entries(I).map(([F,U])=>({Name:F,Value:U}));if(M)B.Properties.Unit=M;if(L!==void 0)B.Properties.DatapointsToAlarm=L;return{alarm:B,logicalId:O}}static createCompositeAlarm(n){let{slug:i,environment:s,alarmName:o,alarmRule:c,actionsEnabled:u=!0,alarmActions:d,okActions:p,insufficientDataActions:y}=n,h=o||r({slug:i,environment:s,resourceType:"composite-alarm"}),b=t(h),v={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:h,AlarmRule:c,ActionsEnabled:u}};if(d&&d.length>0)v.Properties.AlarmActions=d;if(p&&p.length>0)v.Properties.OKActions=p;if(y&&y.length>0)v.Properties.InsufficientDataActions=y;return{alarm:v,logicalId:b}}static createDashboard(n){let{slug:i,environment:s,dashboardName:o,widgets:c}=n,u=o||r({slug:i,environment:s,resourceType:"dashboard"}),d=t(u),p={widgets:c.map((h)=>({type:h.type,x:h.x,y:h.y,width:h.width,height:h.height,properties:h.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:u,DashboardBody:JSON.stringify(p)}},logicalId:d}}static createLogGroup(n){let{slug:i,environment:s,logGroupName:o,retentionInDays:c,kmsKeyId:u}=n,d=o||r({slug:i,environment:s,resourceType:"log-group"}),p=t(d),y={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:d}};if(c!==void 0)y.Properties.RetentionInDays=c;if(u)y.Properties.KmsKeyId=u;return{logGroup:y,logicalId:p}}static createLogStream(n,i){let{slug:s,environment:o,logStreamName:c}=i,u=c||r({slug:s,environment:o,resourceType:"log-stream"}),d=t(u);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:x.Ref(n),LogStreamName:u}},logicalId:d}}static createMetricFilter(n,i){let{slug:s,environment:o,filterName:c,filterPattern:u,metricTransformations:d}=i,p=c||r({slug:s,environment:o,resourceType:"metric-filter"}),y=t(p);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:x.Ref(n),FilterPattern:u,MetricTransformations:d.map((b)=>({MetricName:b.metricName,MetricNamespace:b.metricNamespace,MetricValue:b.metricValue,DefaultValue:b.defaultValue,Unit:b.unit}))}},logicalId:y}}static AlarmTypes={highCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highMemory:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highDisk:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:c?[c]:void 0}),lambdaErrors:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),lambdaThrottles:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),apiGateway5xxErrors:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),apiGateway4xxErrors:(n,i,s,o=50,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),dynamoDBThrottles:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:s},alarmActions:c?[c]:void 0}),rdsCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0}),rdsFreeStorage:(n,i,s,o=5368709120,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0,unit:"Bytes"}),sqsQueueDepth:(n,i,s,o=100,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:s},alarmActions:c?[c]:void 0}),albUnhealthyTargets:(n,i,s,o,c=1,u)=>({slug:n,environment:i,alarmName:`${n}-${i}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:c,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:s,TargetGroup:o},alarmActions:u?[u]:void 0}),sesBounceRate:(n,i,s=5,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),sesComplaintRate:(n,i,s=0.1,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),smsDeliveryFailure:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:s},alarmActions:c?[c]:void 0}),smsSpendLimit:(n,i,s=100,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:s,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),connectMissedCalls:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0})};static DashboardWidgets={metric:(n,i,s,o,c,u)=>({type:"metric",x:n,y:i,width:s,height:o,properties:{metrics:c,title:u||"Metrics",region:"us-east-1",period:300}}),text:(n,i,s,o,c)=>({type:"text",x:n,y:i,width:s,height:o,properties:{markdown:c}}),log:(n,i,s,o,c,u)=>({type:"log",x:n,y:i,width:s,height:o,properties:{query:`SOURCE '${c.join("' | SOURCE '")}'
|
|
2275
2275
|
| fields @timestamp, @message
|
|
2276
2276
|
| sort @timestamp desc
|
|
2277
2277
|
| limit 20`,region:"us-east-1",title:u||"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:(n,i)=>`{ $.${n} = "${i}" }`,httpStatus:(n)=>`[..., status_code = ${n}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(n){let{slug:i,environment:s,region:o="us-east-1",components:c={}}=n,u=[],d=0;if(u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:`# ${i.toUpperCase()} Dashboard (${s})`}}),d+=1,c.ec2InstanceIds&&c.ec2InstanceIds.length>0)u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),d+=1,u.push({type:"metric",x:0,y:d,width:8,height:6,properties:{title:"CPU Utilization",region:o,metrics:c.ec2InstanceIds.map((p)=>["AWS/EC2","CPUUtilization","InstanceId",p]),period:300,stat:"Average"}}),u.push({type:"metric",x:8,y:d,width:8,height:6,properties:{title:"Network Traffic",region:o,metrics:[...c.ec2InstanceIds.flatMap((p)=>[["AWS/EC2","NetworkIn","InstanceId",p,{label:`${p} In`}],["AWS/EC2","NetworkOut","InstanceId",p,{label:`${p} Out`}]])],period:300,stat:"Sum"}}),u.push({type:"metric",x:16,y:d,width:8,height:6,properties:{title:"Status Checks",region:o,metrics:c.ec2InstanceIds.map((p)=>["AWS/EC2","StatusCheckFailed","InstanceId",p]),period:60,stat:"Maximum"}}),d+=6;if(c.lambdaFunctionNames&&c.lambdaFunctionNames.length>0)u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),d+=1,u.push({type:"metric",x:0,y:d,width:8,height:6,properties:{title:"Invocations",region:o,metrics:c.lambdaFunctionNames.map((p)=>["AWS/Lambda","Invocations","FunctionName",p]),period:300,stat:"Sum"}}),u.push({type:"metric",x:8,y:d,width:8,height:6,properties:{title:"Duration",region:o,metrics:c.lambdaFunctionNames.map((p)=>["AWS/Lambda","Duration","FunctionName",p]),period:300,stat:"Average"}}),u.push({type:"metric",x:16,y:d,width:8,height:6,properties:{title:"Errors",region:o,metrics:c.lambdaFunctionNames.map((p)=>["AWS/Lambda","Errors","FunctionName",p]),period:300,stat:"Sum"}}),d+=6;if(c.ecsClusterName&&c.ecsServiceName)u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:"## ECS Service"}}),d+=1,u.push({type:"metric",x:0,y:d,width:8,height:6,properties:{title:"CPU Utilization",region:o,metrics:[["AWS/ECS","CPUUtilization","ClusterName",c.ecsClusterName,"ServiceName",c.ecsServiceName]],period:300,stat:"Average"}}),u.push({type:"metric",x:8,y:d,width:8,height:6,properties:{title:"Memory Utilization",region:o,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",c.ecsClusterName,"ServiceName",c.ecsServiceName]],period:300,stat:"Average"}}),u.push({type:"metric",x:16,y:d,width:8,height:6,properties:{title:"Running Tasks",region:o,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",c.ecsClusterName,"ServiceName",c.ecsServiceName]],period:60,stat:"Average"}}),d+=6;if(c.albName)u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),d+=1,u.push({type:"metric",x:0,y:d,width:8,height:6,properties:{title:"Request Count",region:o,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",c.albName]],period:60,stat:"Sum"}}),u.push({type:"metric",x:8,y:d,width:8,height:6,properties:{title:"Response Time",region:o,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",c.albName]],period:60,stat:"Average"}}),u.push({type:"metric",x:16,y:d,width:8,height:6,properties:{title:"HTTP Errors",region:o,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",c.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",c.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),d+=6;if(c.rdsInstanceId)u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:"## RDS Database"}}),d+=1,u.push({type:"metric",x:0,y:d,width:8,height:6,properties:{title:"CPU Utilization",region:o,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",c.rdsInstanceId]],period:300,stat:"Average"}}),u.push({type:"metric",x:8,y:d,width:8,height:6,properties:{title:"Database Connections",region:o,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",c.rdsInstanceId]],period:60,stat:"Sum"}}),u.push({type:"metric",x:16,y:d,width:8,height:6,properties:{title:"Free Storage Space",region:o,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",c.rdsInstanceId]],period:300,stat:"Average"}}),d+=6;if(c.sqsQueueNames&&c.sqsQueueNames.length>0)u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:"## SQS Queues"}}),d+=1,u.push({type:"metric",x:0,y:d,width:12,height:6,properties:{title:"Messages Visible",region:o,metrics:c.sqsQueueNames.map((p)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",p]),period:60,stat:"Sum"}}),u.push({type:"metric",x:12,y:d,width:12,height:6,properties:{title:"Message Age",region:o,metrics:c.sqsQueueNames.map((p)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",p]),period:60,stat:"Maximum"}}),d+=6;if(c.logGroupNames&&c.logGroupNames.length>0)u.push({type:"text",x:0,y:d,width:24,height:1,properties:{markdown:"## Application Logs"}}),d+=1,u.push({type:"log",x:0,y:d,width:24,height:6,properties:{query:`SOURCE '${c.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:o,title:"Recent Errors and Warnings"}}),d+=6;return qo.createDashboard({slug:i,environment:s,widgets:u})}static DashboardTemplates={staticWebsite:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.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",n.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",n.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",n.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",n.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:n.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",n.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:n.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",n.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",n.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",n.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",n.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",n.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...n.lambdaFunctionNames.map((i,s)=>({type:"metric",x:s%3*8,y:7+Math.floor(s/3)*6,width:8,height:6,properties:{title:`${i} Metrics`,region:n.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",i],["AWS/Lambda","Duration","FunctionName",i],["AWS/Lambda","Errors","FunctionName",i]],period:300,stat:"Sum"}}))]}),containerService:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:n.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:n.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:n.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",n.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",n.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",n.albName]],period:60,stat:"Average"}},...n.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:n.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",n.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:n.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",n.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(n)=>{let{metricName:i,namespace:s,threshold:o,comparisonOperator:c="GreaterThanThreshold",evaluationPeriods:u=1,period:d=300,statistic:p="Average",treatMissingData:y="missing"}=n;return{MetricName:i,Namespace:s,Threshold:o,ComparisonOperator:c,EvaluationPeriods:u,Period:d,Statistic:p,TreatMissingData:y}},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:(n=80)=>({metricName:"CPUUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(n=80)=>({metricName:"MemoryUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(n=10)=>({metricName:"Errors",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(n=5000)=>({metricName:"Duration",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(n=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(n=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(n=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Y{static createUserPool(n){let{slug:i,environment:s,userPoolName:o,aliasAttributes:c,autoVerifiedAttributes:u,passwordPolicy:d,mfaConfiguration:p,emailConfiguration:y,smsConfiguration:h,lambdaTriggers:b,userPoolAddOns:v,accountRecoverySetting:A}=n,T=o||r({slug:i,environment:s,resourceType:"user-pool"}),R=t(T),P={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:T,Policies:d?{PasswordPolicy:{MinimumLength:d.minimumLength,RequireLowercase:d.requireLowercase,RequireUppercase:d.requireUppercase,RequireNumbers:d.requireNumbers,RequireSymbols:d.requireSymbols,TemporaryPasswordValidityDays:d.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:p,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(c&&c.length>0)P.Properties.UsernameAttributes=c;if(u&&u.length>0)P.Properties.AutoVerifiedAttributes=u;if(y)P.Properties.EmailConfiguration={EmailSendingAccount:y.emailSendingAccount,From:y.from,ReplyToEmailAddress:y.replyToEmailAddress,SourceArn:y.sourceArn,ConfigurationSet:y.configurationSet};if(h)P.Properties.SmsConfiguration={ExternalId:h.externalId,SnsCallerArn:h.snsCallerArn};if(b)P.Properties.LambdaConfig={PreSignUp:b.preSignUp,PostConfirmation:b.postConfirmation,PreAuthentication:b.preAuthentication,PostAuthentication:b.postAuthentication,CustomMessage:b.customMessage,DefineAuthChallenge:b.defineAuthChallenge,CreateAuthChallenge:b.createAuthChallenge,VerifyAuthChallengeResponse:b.verifyAuthChallengeResponse,PreTokenGeneration:b.preTokenGeneration,UserMigration:b.userMigration};if(v)P.Properties.UserPoolAddOns={AdvancedSecurityMode:v.advancedSecurityMode};if(A)P.Properties.AccountRecoverySetting={RecoveryMechanisms:A.recoveryMechanisms};return{userPool:P,logicalId:R}}static createUserPoolClient(n,i){let{slug:s,environment:o,clientName:c,generateSecret:u=!1,refreshTokenValidity:d,accessTokenValidity:p,idTokenValidity:y,tokenValidityUnits:h,readAttributes:b,writeAttributes:v,explicitAuthFlows:A,preventUserExistenceErrors:T,enableTokenRevocation:R,callbackURLs:P,logoutURLs:I,allowedOAuthFlows:M,allowedOAuthScopes:L,allowedOAuthFlowsUserPoolClient:N,supportedIdentityProviders:O}=i,B=c||r({slug:s,environment:o,resourceType:"user-pool-client"}),F=t(B);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:B,UserPoolId:x.Ref(n),GenerateSecret:u,RefreshTokenValidity:d,AccessTokenValidity:p,IdTokenValidity:y,TokenValidityUnits:h,ReadAttributes:b,WriteAttributes:v,ExplicitAuthFlows:A,PreventUserExistenceErrors:T,EnableTokenRevocation:R,CallbackURLs:P,LogoutURLs:I,AllowedOAuthFlows:M,AllowedOAuthScopes:L,AllowedOAuthFlowsUserPoolClient:N,SupportedIdentityProviders:O}},logicalId:F}}static createUserPoolDomain(n,i){let{slug:s,environment:o,domain:c,customDomainConfig:u}=i,d=r({slug:s,environment:o,resourceType:"user-pool-domain"}),p=t(d);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:c,UserPoolId:x.Ref(n),CustomDomainConfig:u}},logicalId:p}}static createIdentityPool(n){let{slug:i,environment:s,identityPoolName:o,allowUnauthenticatedIdentities:c=!1,cognitoIdentityProviders:u,supportedLoginProviders:d,samlProviderARNs:p,openIdConnectProviderARNs:y}=n,h=o||r({slug:i,environment:s,resourceType:"identity-pool"}),b=t(h);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:h,AllowUnauthenticatedIdentities:c,CognitoIdentityProviders:u,SupportedLoginProviders:d,SamlProviderARNs:p,OpenIdConnectProviderARNs:y}},logicalId:b}}static createIdentityPoolRoleAttachment(n,i){let{slug:s,environment:o,authenticatedRole:c,unauthenticatedRole:u,roleMappings:d}=i,p=r({slug:s,environment:o,resourceType:"identity-pool-role-attachment"}),y=t(p),h={authenticated:c};if(u)h.unauthenticated=u;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:x.Ref(n),Roles:h,RoleMappings:d}},logicalId:y}}static createAuthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-authenticated-role"}),u=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":x.Ref(o)},"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:c},{Key:"Environment",Value:s}]}},logicalId:u}}static createUnauthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-unauthenticated-role"}),u=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":x.Ref(o)},"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:c},{Key:"Environment",Value:s}]}},logicalId:u}}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:(n,i,s)=>{let{userPool:o,logicalId:c}=Y.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Y.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:u,logicalId:d}=Y.createUserPoolClient(c,{slug:n,environment:i,explicitAuthFlows:[...Y.AuthFlows.standard],callbackURLs:[s],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Y.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:o,poolId:c,client:u,clientId:d}},mobileApp:(n,i)=>{let{userPool:s,logicalId:o}=Y.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Y.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:c,logicalId:u}=Y.createUserPoolClient(o,{slug:n,environment:i,explicitAuthFlows:[...Y.AuthFlows.standard]}),{identityPool:d,logicalId:p}=Y.createIdentityPool({slug:n,environment:i,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:x.Ref(u),ProviderName:x.GetAtt(o,"ProviderName")}]}),{role:y,logicalId:h}=Y.createAuthenticatedRole({slug:n,environment:i,identityPoolLogicalId:p}),{attachment:b,logicalId:v}=Y.createIdentityPoolRoleAttachment(p,{slug:n,environment:i,authenticatedRole:x.GetAtt(h,"Arn")});return{userPool:s,poolId:o,client:c,clientId:u,identityPool:d,identityPoolId:p,authRole:y,authRoleId:h,attachment:b,attachmentId:v}}}}import{createHash as xr}from"node:crypto";import{copyFileSync as kr,existsSync as Tt,readdirSync as Mr,readFileSync as ot,statSync as Lr,writeFileSync as ct}from"node:fs";import{basename as Or,dirname as yn,extname as bn,join as Ke}from"node:path";class Z{static createApplication(n){let{slug:i,environment:s,applicationName:o,computePlatform:c}=n,u=o||r({slug:i,environment:s,resourceType:"deploy-app"}),d=t(u);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:u,ComputePlatform:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s}]}},logicalId:d}}static createDeploymentGroup(n,i){let{slug:s,environment:o,deploymentGroupName:c,serviceRoleArn:u,autoScalingGroups:d,ec2TagFilters:p,deploymentConfigName:y,autoRollbackConfiguration:h,alarmConfiguration:b,loadBalancerInfo:v,blueGreenDeploymentConfiguration:A}=i,T=c||r({slug:s,environment:o,resourceType:"deploy-group"}),R=t(T);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:x.Ref(n),DeploymentGroupName:T,ServiceRoleArn:u,AutoScalingGroups:d,Ec2TagFilters:p?.map((I)=>({Key:I.key,Value:I.value,Type:I.type})),DeploymentConfigName:y,AutoRollbackConfiguration:h?{Enabled:h.enabled,Events:h.events}:void 0,AlarmConfiguration:b?{Enabled:b.enabled,Alarms:b.alarms?.map((I)=>({Name:I.name})),IgnorePollAlarmFailure:b.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:v?{TargetGroupInfoList:v.targetGroupInfoList?.map((I)=>({Name:I.name})),ElbInfoList:v.elbInfoList?.map((I)=>({Name:I.name}))}:void 0,BlueGreenDeploymentConfiguration:A?{TerminateBlueInstancesOnDeploymentSuccess:A.terminateBlueInstancesOnDeploymentSuccess?{Action:A.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:A.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:A.deploymentReadyOption?{ActionOnTimeout:A.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:A.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:A.greenFleetProvisioningOption?{Action:A.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:o}]}},logicalId:R}}static createDeploymentConfig(n){let{slug:i,environment:s,deploymentConfigName:o,minimumHealthyHosts:c,trafficRoutingConfig:u}=n,d=o||r({slug:i,environment:s,resourceType:"deploy-config"}),p=t(d);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:d,MinimumHealthyHosts:c?{Type:c.type,Value:c.value}:void 0,TrafficRoutingConfig:u?{Type:u.type,TimeBasedCanary:u.timeBasedCanary?{CanaryPercentage:u.timeBasedCanary.canaryPercentage,CanaryInterval:u.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:u.timeBasedLinear?{LinearPercentage:u.timeBasedLinear.linearPercentage,LinearInterval:u.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:p}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(n,i)=>({type:n,value:i})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(n,i)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:n,canaryInterval:i}}),linear:(n,i)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:n,linearInterval:i}})};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:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:n},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:n},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:(n,i,s,o)=>{let{application:c,logicalId:u}=Z.createApplication({slug:n,environment:i,computePlatform:"Server"}),{deploymentGroup:d,logicalId:p}=Z.createDeploymentGroup(u,{slug:n,environment:i,serviceRoleArn:s,autoScalingGroups:o,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Z.RollbackConfigs.onFailure()});return{application:c,appId:u,deploymentGroup:d,groupId:p}},lambdaCanaryDeployment:(n,i,s,o=10,c=5)=>{let{application:u,logicalId:d}=Z.createApplication({slug:n,environment:i,computePlatform:"Lambda"}),{deploymentConfig:p,logicalId:y}=Z.createDeploymentConfig({slug:n,environment:i,trafficRoutingConfig:Z.TrafficRouting.canary(o,c)}),{deploymentGroup:h,logicalId:b}=Z.createDeploymentGroup(d,{slug:n,environment:i,serviceRoleArn:s,deploymentConfigName:x.Ref(y),autoRollbackConfiguration:Z.RollbackConfigs.onAlarmOrFailure()});return{application:u,appId:d,deploymentConfig:p,configId:y,deploymentGroup:h,groupId:b}},ecsBlueGreenDeployment:(n,i,s,o)=>{let{application:c,logicalId:u}=Z.createApplication({slug:n,environment:i,computePlatform:"ECS"}),{deploymentGroup:d,logicalId:p}=Z.createDeploymentGroup(u,{slug:n,environment:i,serviceRoleArn:s,loadBalancerInfo:{targetGroupInfoList:[{name:o}]},blueGreenDeploymentConfiguration:Z.BlueGreenConfigs.standard(),autoRollbackConfiguration:Z.RollbackConfigs.onFailure()});return{application:c,appId:u,deploymentGroup:d,groupId:p}}};static Strategies={rolling:(n=25)=>({type:"rolling",batchPercentage:n}),blueGreen:()=>({type:"blue-green"}),canary:(n=10,i=5)=>({type:"canary",canaryPercentage:n,canaryInterval:i}),allAtOnce:()=>({type:"all-at-once"})}}class _{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(n,i="md5"){let s=ot(n);return xr(i).update(s).digest("hex")}static computeShortHash(n){return _.computeFileHash(n).slice(0,8)}static getContentType(n){let i=bn(n).toLowerCase();return _.ContentTypes[i]||"application/octet-stream"}static shouldHashFile(n,i){return![..._.NoHashPatterns,...i||[]].some((o)=>o.test(n))}static generateHashedFilename(n,i){let s=bn(n),o=Or(n,s),c=yn(n);if(c===".")return`${o}.${i}${s}`;return Ke(c,`${o}.${i}${s}`)}static collectFiles(n,i){let s=[],o=i||n;if(!Tt(n))return s;let c=Mr(n,{withFileTypes:!0});for(let u of c){let d=Ke(n,u.name);if(u.isDirectory())s.push(..._.collectFiles(d,o));else if(u.isFile())s.push(d)}return s}static hashDirectory(n){let{sourceDir:i,outputDir:s,excludePatterns:o=[],hashAlgorithm:c="md5",copyUnhashed:u=!0}=n,d=_.collectFiles(i),p=[],y={};for(let b of d){let v=b.replace(i,"").replace(/^[/\\]/,""),A=_.shouldHashFile(v,o),T=Lr(b),R=A?_.computeFileHash(b,c).slice(0,8):"",P=A?_.generateHashedFilename(v,R):v,I={originalPath:v,hashedPath:P,hash:R,size:T.size,contentType:_.getContentType(b)};if(p.push(I),y[v]=P,s){let M=Ke(s,P),L=yn(M);if(!Tt(L)){let{mkdirSync:N}=nt("node:fs");N(L,{recursive:!0})}if(A||u)kr(b,M)}}let h={version:"1.0",timestamp:new Date().toISOString(),assets:p,hashMap:y};if(s){let b=Ke(s,"asset-manifest.json");ct(b,JSON.stringify(h,null,2))}return h}static getInvalidationPaths(n,i){let s=[];if(!n)return["/*"];let o=n.hashMap,c=i.hashMap;for(let[u,d]of Object.entries(c)){let p=o[u];if(!p||p!==d){if(s.push(`/${u}`),p&&p!==d)s.push(`/${p}`)}}for(let[u,d]of Object.entries(o))if(!c[u])s.push(`/${u}`),s.push(`/${d}`);if(s.length>100)return["/*"];return[...new Set(s)]}static updateHtmlReferences(n){let{htmlDir:i,manifest:s,basePath:o=""}=n,c=_.collectFiles(i).filter((u)=>u.endsWith(".html")||u.endsWith(".htm"));for(let u of c){let d=ot(u,"utf-8");for(let[p,y]of Object.entries(s.hashMap)){if(p===y)continue;let h=[new RegExp(`(src|href)=["']${o}/?${_.escapeRegExp(p)}["']`,"g"),new RegExp(`url\\(["']?${o}/?${_.escapeRegExp(p)}["']?\\)`,"g")];for(let b of h)d=d.replace(b,(v)=>v.replace(p,y))}ct(u,d)}}static updateCssReferences(n){let{cssDir:i,manifest:s,basePath:o=""}=n,c=_.collectFiles(i).filter((u)=>u.endsWith(".css"));for(let u of c){let d=ot(u,"utf-8");for(let[p,y]of Object.entries(s.hashMap)){if(p===y)continue;let h=new RegExp(`url\\(["']?${o}/?${_.escapeRegExp(p)}["']?\\)`,"g");d=d.replace(h,`url(${o}/${y})`)}ct(u,d)}}static escapeRegExp(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(n){let{sourceDir:i,keyPrefix:s="",excludePatterns:o=[],cacheControl:c={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=n;return _.hashDirectory({sourceDir:i,excludePatterns:o}).assets.map((d)=>{let p=d.hash!=="",y=d.contentType==="text/html",h=c.unhashed||"public, max-age=3600";if(y)h=c.html||"public, max-age=0, must-revalidate";else if(p)h=c.hashed||"public, max-age=31536000, immutable";return{localPath:Ke(i,d.originalPath),s3Key:s?`${s}/${d.hashedPath}`:d.hashedPath,contentType:d.contentType,cacheControl:h,hash:d.hash}})}static compareManifests(n,i){let s={added:[],removed:[],changed:[],unchanged:[]},o=new Set(Object.keys(n.hashMap)),c=new Set(Object.keys(i.hashMap));for(let u of c)if(!o.has(u))s.added.push(u);for(let u of o)if(!c.has(u))s.removed.push(u);for(let u of c)if(o.has(u))if(n.hashMap[u]!==i.hashMap[u])s.changed.push(u);else s.unchanged.push(u);return s}static loadManifest(n){if(!Tt(n))return null;try{let i=ot(n,"utf-8");return JSON.parse(i)}catch{return null}}static saveManifest(n,i){ct(i,JSON.stringify(n,null,2))}}class Yi{static createSecret(n){let{slug:i,environment:s,secretName:o,description:c,secretString:u,kmsKeyId:d,tags:p}=n,y=o||r({slug:i,environment:s,resourceType:"secret"}),h=t(y),b={Type:"AWS::SecretsManager::Secret",Properties:{Name:y,Description:c,SecretString:u,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},...p?Object.entries(p).map(([v,A])=>({Key:v,Value:A})):[]]}};if(d)b.Properties.KmsKeyId=d;return{secret:b,logicalId:h}}static createGeneratedSecret(n){let{slug:i,environment:s,secretName:o,description:c,excludeCharacters:u,excludeLowercase:d,excludeNumbers:p,excludePunctuation:y,excludeUppercase:h,passwordLength:b,requireEachIncludedType:v,kmsKeyId:A,tags:T}=n,R=o||r({slug:i,environment:s,resourceType:"secret"}),P=t(R),I={Type:"AWS::SecretsManager::Secret",Properties:{Name:R,Description:c,GenerateSecretString:{ExcludeCharacters:u,ExcludeLowercase:d,ExcludeNumbers:p,ExcludePunctuation:y,ExcludeUppercase:h,PasswordLength:b||32,RequireEachIncludedType:v!==!1},Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:s},...T?Object.entries(T).map(([M,L])=>({Key:M,Value:L})):[]]}};if(A)I.Properties.KmsKeyId=A;return{secret:I,logicalId:P}}static createDatabaseSecret(n){let{slug:i,environment:s,secretName:o,username:c,dbname:u,engine:d,host:p,port:y,kmsKeyId:h}=n,b=o||r({slug:i,environment:s,resourceType:"db-secret"}),v=t(b),A={username:c};if(u)A.dbname=u;if(d)A.engine=d;if(p)A.host=p;if(y)A.port=y;let T={Type:"AWS::SecretsManager::Secret",Properties:{Name:b,Description:`Database credentials for ${c}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(A),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s},{Key:"Type",Value:"database"}]}};if(h)T.Properties.KmsKeyId=h;return{secret:T,logicalId:v}}static attachToDatabase(n){let{slug:i,environment:s,secretId:o,targetId:c,targetType:u}=n,d=r({slug:i,environment:s,resourceType:"secret-attachment"}),p=t(d);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:o,TargetId:c,TargetType:u}},logicalId:p}}static enableRotation(n){let{slug:i,environment:s,secretId:o,rotationLambdaArn:c,automaticallyAfterDays:u,rotationType:d,kmsKeyArn:p,vpcSecurityGroupIds:y,vpcSubnetIds:h}=n,b=r({slug:i,environment:s,resourceType:"secret-rotation"}),v=t(b),A={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:o,RotationRules:{AutomaticallyAfterDays:u||30}}};if(c)A.Properties.RotationLambdaARN=c;else if(d)A.Properties.HostedRotationLambda={RotationType:d,KmsKeyArn:p,VpcSecurityGroupIds:y,VpcSubnetIds:h};return{rotation:A,logicalId:v}}static SecretTypes={apiKey:(n,i,s)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-api-key`,description:`API key for ${s}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(n,i,s)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-oauth-secret`,description:`OAuth client secret for ${s}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(n,i)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(n,i)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-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 D{static createParameter(n){let{slug:i,environment:s,parameterName:o,value:c,type:u="String",description:d,tier:p="Standard",tags:y}=n,h=o||r({slug:i,environment:s,resourceType:"parameter"}),b=t(h);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${i}/${s}/${h}`,Type:u,Value:c,Description:d,Tier:p,Tags:{Name:h,Environment:s,...y}}},logicalId:b}}static createString(n,i,s,o,c){return D.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"String",description:c})}static createSecureString(n,i,s,o,c){return D.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"SecureString",description:c})}static createStringList(n,i,s,o,c){return D.createParameter({slug:n,environment:i,parameterName:s,value:o.join(","),type:"StringList",description:c})}static Parameters={databaseUrl:(n,i,s)=>D.createSecureString(n,i,"database-url",s,"Database connection URL"),apiEndpoint:(n,i,s)=>D.createString(n,i,"api-endpoint",s,"API endpoint URL"),appVersion:(n,i,s)=>D.createString(n,i,"app-version",s,"Application version"),featureFlags:(n,i,s)=>D.createStringList(n,i,"feature-flags",s,"Enabled feature flags"),apiKey:(n,i,s,o)=>D.createSecureString(n,i,`${s}-api-key`,o,`API key for ${s}`),oauthCredentials:(n,i,s,o)=>{let c=D.createString(n,i,"oauth-client-id",s,"OAuth client ID"),u=D.createSecureString(n,i,"oauth-client-secret",o,"OAuth client secret");return{clientId:c,clientSecret:u}},smtpCredentials:(n,i,s,o,c,u)=>{let d=D.createString(n,i,"smtp-username",s,"SMTP username"),p=D.createSecureString(n,i,"smtp-password",o,"SMTP password"),y=D.createString(n,i,"smtp-host",c,"SMTP host"),h=D.createString(n,i,"smtp-port",u.toString(),"SMTP port");return{username:d,password:p,host:y,port:h}},redisUrl:(n,i,s)=>D.createSecureString(n,i,"redis-url",s,"Redis connection URL"),s3Bucket:(n,i,s)=>D.createString(n,i,"s3-bucket",s,"S3 bucket name"),cloudFrontDistribution:(n,i,s)=>D.createString(n,i,"cloudfront-distribution-id",s,"CloudFront distribution ID")}}class ur{static createDomain(n){let{slug:i,environment:s,domainName:o,engineVersion:c="OpenSearch_2.11",instanceType:u="t3.small.search",instanceCount:d=1,volumeSize:p=10,volumeType:y="gp3",dedicatedMaster:h=!1,dedicatedMasterType:b,dedicatedMasterCount:v=3,multiAz:A=!1,availabilityZoneCount:T=2,vpc:R,encryption:P,enforceHttps:I=!0,tlsSecurityPolicy:M="Policy-Min-TLS-1-2-2019-07",advancedSecurity:L,autoSnapshotHour:N=0,autoTune:O=!0,tags:B={}}=n,F=o||r({slug:i,environment:s,resourceType:"search"}),U=t(F);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:F,EngineVersion:c,ClusterConfig:{InstanceType:u,InstanceCount:d,DedicatedMasterEnabled:h,...h&&{DedicatedMasterType:b||u,DedicatedMasterCount:v},ZoneAwarenessEnabled:A,...A&&{ZoneAwarenessConfig:{AvailabilityZoneCount:T}}},EBSOptions:{EBSEnabled:!0,VolumeType:y,VolumeSize:p},DomainEndpointOptions:{EnforceHTTPS:I,TLSSecurityPolicy:M},SnapshotOptions:{AutomatedSnapshotStartHour:N},...R&&{VPCOptions:{SubnetIds:R.subnetIds,SecurityGroupIds:R.securityGroupIds}},...P&&{EncryptionAtRestOptions:{Enabled:P.atRest??!0,...P.kmsKeyId&&{KmsKeyId:P.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:P.nodeToNode??!0}},...L&&{AdvancedSecurityOptions:{Enabled:L.enabled,InternalUserDatabaseEnabled:L.internalUserDatabase??!0,...L.masterUserName&&L.masterUserPassword&&{MasterUserOptions:{MasterUserName:L.masterUserName,MasterUserPassword:L.masterUserPassword}},...L.masterUserArn&&{MasterUserOptions:{MasterUserARN:L.masterUserArn}}}},...O&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:F},{Key:"Environment",Value:s},...Object.entries(B).map(([H,z])=>({Key:H,Value:z}))]}},logicalId:U}}static createAccessPolicy(n,i){let{ipAddresses:s,iamPrincipalArns:o,allowAll:c,vpcEndpoint:u}=i;if(c)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};let d=[];if(o&&o.length>0)d.push({Effect:"Allow",Principal:{AWS:o},Action:"es:*",Resource:n});if(s&&s.length>0)d.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n,Condition:{IpAddress:{"aws:SourceIp":s}}});if(u)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};return{Version:"2012-10-17",Statement:d}}static DomainPresets={development:(n,i)=>ur.createDomain({slug:n,environment:i,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(n,i,s)=>ur.createDomain({slug:n,environment:i,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:s,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(n,i)=>ur.createDomain({slug:n,environment:i,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(n,i,s)=>ur.createDomain({slug:n,environment:i,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:s,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class Nt{static createDomainRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:u="https"}=n,d=r({slug:i,environment:s,resourceType:"s3",suffix:"redirect"}),p=t(d),y=t(`${d}-policy`),h={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:u}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Domain Redirect"}]}},b={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(p),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[x.Join("",[x.GetAtt(p,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:b,logicalId:p,policyLogicalId:y}}static createPathRedirectFunction(n){let{slug:i,environment:s,rules:o}=n,c=r({slug:i,environment:s,resourceType:"cf-redirect"}),u=t(c),d=Nt.generateRedirectFunctionCode(o);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:c,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${i} (${s})`,Runtime:"cloudfront-js-2.0"},FunctionCode:d}},logicalId:u,functionCode:d}}static generateRedirectFunctionCode(n){return`function handler(event) {
|
|
2281
|
+
| limit 50`,region:o,title:"Recent Errors and Warnings"}}),d+=6;return qo.createDashboard({slug:i,environment:s,widgets:u})}static DashboardTemplates={staticWebsite:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.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",n.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",n.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",n.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",n.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:n.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",n.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:n.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",n.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",n.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",n.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",n.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",n.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...n.lambdaFunctionNames.map((i,s)=>({type:"metric",x:s%3*8,y:7+Math.floor(s/3)*6,width:8,height:6,properties:{title:`${i} Metrics`,region:n.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",i],["AWS/Lambda","Duration","FunctionName",i],["AWS/Lambda","Errors","FunctionName",i]],period:300,stat:"Sum"}}))]}),containerService:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:n.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:n.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:n.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",n.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",n.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",n.albName]],period:60,stat:"Average"}},...n.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:n.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",n.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:n.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",n.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(n)=>{let{metricName:i,namespace:s,threshold:o,comparisonOperator:c="GreaterThanThreshold",evaluationPeriods:u=1,period:d=300,statistic:p="Average",treatMissingData:y="missing"}=n;return{MetricName:i,Namespace:s,Threshold:o,ComparisonOperator:c,EvaluationPeriods:u,Period:d,Statistic:p,TreatMissingData:y}},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:(n=80)=>({metricName:"CPUUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(n=80)=>({metricName:"MemoryUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(n=10)=>({metricName:"Errors",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(n=5000)=>({metricName:"Duration",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(n=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(n=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(n=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Y{static createUserPool(n){let{slug:i,environment:s,userPoolName:o,aliasAttributes:c,autoVerifiedAttributes:u,passwordPolicy:d,mfaConfiguration:p,emailConfiguration:y,smsConfiguration:h,lambdaTriggers:b,userPoolAddOns:v,accountRecoverySetting:A}=n,T=o||r({slug:i,environment:s,resourceType:"user-pool"}),R=t(T),P={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:T,Policies:d?{PasswordPolicy:{MinimumLength:d.minimumLength,RequireLowercase:d.requireLowercase,RequireUppercase:d.requireUppercase,RequireNumbers:d.requireNumbers,RequireSymbols:d.requireSymbols,TemporaryPasswordValidityDays:d.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:p,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(c&&c.length>0)P.Properties.UsernameAttributes=c;if(u&&u.length>0)P.Properties.AutoVerifiedAttributes=u;if(y)P.Properties.EmailConfiguration={EmailSendingAccount:y.emailSendingAccount,From:y.from,ReplyToEmailAddress:y.replyToEmailAddress,SourceArn:y.sourceArn,ConfigurationSet:y.configurationSet};if(h)P.Properties.SmsConfiguration={ExternalId:h.externalId,SnsCallerArn:h.snsCallerArn};if(b)P.Properties.LambdaConfig={PreSignUp:b.preSignUp,PostConfirmation:b.postConfirmation,PreAuthentication:b.preAuthentication,PostAuthentication:b.postAuthentication,CustomMessage:b.customMessage,DefineAuthChallenge:b.defineAuthChallenge,CreateAuthChallenge:b.createAuthChallenge,VerifyAuthChallengeResponse:b.verifyAuthChallengeResponse,PreTokenGeneration:b.preTokenGeneration,UserMigration:b.userMigration};if(v)P.Properties.UserPoolAddOns={AdvancedSecurityMode:v.advancedSecurityMode};if(A)P.Properties.AccountRecoverySetting={RecoveryMechanisms:A.recoveryMechanisms};return{userPool:P,logicalId:R}}static createUserPoolClient(n,i){let{slug:s,environment:o,clientName:c,generateSecret:u=!1,refreshTokenValidity:d,accessTokenValidity:p,idTokenValidity:y,tokenValidityUnits:h,readAttributes:b,writeAttributes:v,explicitAuthFlows:A,preventUserExistenceErrors:T,enableTokenRevocation:R,callbackURLs:P,logoutURLs:I,allowedOAuthFlows:M,allowedOAuthScopes:L,allowedOAuthFlowsUserPoolClient:N,supportedIdentityProviders:O}=i,B=c||r({slug:s,environment:o,resourceType:"user-pool-client"}),F=t(B);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:B,UserPoolId:x.Ref(n),GenerateSecret:u,RefreshTokenValidity:d,AccessTokenValidity:p,IdTokenValidity:y,TokenValidityUnits:h,ReadAttributes:b,WriteAttributes:v,ExplicitAuthFlows:A,PreventUserExistenceErrors:T,EnableTokenRevocation:R,CallbackURLs:P,LogoutURLs:I,AllowedOAuthFlows:M,AllowedOAuthScopes:L,AllowedOAuthFlowsUserPoolClient:N,SupportedIdentityProviders:O}},logicalId:F}}static createUserPoolDomain(n,i){let{slug:s,environment:o,domain:c,customDomainConfig:u}=i,d=r({slug:s,environment:o,resourceType:"user-pool-domain"}),p=t(d);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:c,UserPoolId:x.Ref(n),CustomDomainConfig:u}},logicalId:p}}static createIdentityPool(n){let{slug:i,environment:s,identityPoolName:o,allowUnauthenticatedIdentities:c=!1,cognitoIdentityProviders:u,supportedLoginProviders:d,samlProviderARNs:p,openIdConnectProviderARNs:y}=n,h=o||r({slug:i,environment:s,resourceType:"identity-pool"}),b=t(h);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:h,AllowUnauthenticatedIdentities:c,CognitoIdentityProviders:u,SupportedLoginProviders:d,SamlProviderARNs:p,OpenIdConnectProviderARNs:y}},logicalId:b}}static createIdentityPoolRoleAttachment(n,i){let{slug:s,environment:o,authenticatedRole:c,unauthenticatedRole:u,roleMappings:d}=i,p=r({slug:s,environment:o,resourceType:"identity-pool-role-attachment"}),y=t(p),h={authenticated:c};if(u)h.unauthenticated=u;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:x.Ref(n),Roles:h,RoleMappings:d}},logicalId:y}}static createAuthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-authenticated-role"}),u=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":x.Ref(o)},"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:c},{Key:"Environment",Value:s}]}},logicalId:u}}static createUnauthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-unauthenticated-role"}),u=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":x.Ref(o)},"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:c},{Key:"Environment",Value:s}]}},logicalId:u}}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:(n,i,s)=>{let{userPool:o,logicalId:c}=Y.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Y.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:u,logicalId:d}=Y.createUserPoolClient(c,{slug:n,environment:i,explicitAuthFlows:[...Y.AuthFlows.standard],callbackURLs:[s],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Y.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:o,poolId:c,client:u,clientId:d}},mobileApp:(n,i)=>{let{userPool:s,logicalId:o}=Y.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Y.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:c,logicalId:u}=Y.createUserPoolClient(o,{slug:n,environment:i,explicitAuthFlows:[...Y.AuthFlows.standard]}),{identityPool:d,logicalId:p}=Y.createIdentityPool({slug:n,environment:i,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:x.Ref(u),ProviderName:x.GetAtt(o,"ProviderName")}]}),{role:y,logicalId:h}=Y.createAuthenticatedRole({slug:n,environment:i,identityPoolLogicalId:p}),{attachment:b,logicalId:v}=Y.createIdentityPoolRoleAttachment(p,{slug:n,environment:i,authenticatedRole:x.GetAtt(h,"Arn")});return{userPool:s,poolId:o,client:c,clientId:u,identityPool:d,identityPoolId:p,authRole:y,authRoleId:h,attachment:b,attachmentId:v}}}}import{createHash as xr}from"node:crypto";import{copyFileSync as kr,existsSync as Tt,readdirSync as Mr,readFileSync as ot,statSync as Lr,writeFileSync as ct}from"node:fs";import{basename as Or,dirname as yn,extname as bn,join as Ke}from"node:path";class Z{static createApplication(n){let{slug:i,environment:s,applicationName:o,computePlatform:c}=n,u=o||r({slug:i,environment:s,resourceType:"deploy-app"}),d=t(u);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:u,ComputePlatform:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s}]}},logicalId:d}}static createDeploymentGroup(n,i){let{slug:s,environment:o,deploymentGroupName:c,serviceRoleArn:u,autoScalingGroups:d,ec2TagFilters:p,deploymentConfigName:y,autoRollbackConfiguration:h,alarmConfiguration:b,loadBalancerInfo:v,blueGreenDeploymentConfiguration:A}=i,T=c||r({slug:s,environment:o,resourceType:"deploy-group"}),R=t(T);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:x.Ref(n),DeploymentGroupName:T,ServiceRoleArn:u,AutoScalingGroups:d,Ec2TagFilters:p?.map((I)=>({Key:I.key,Value:I.value,Type:I.type})),DeploymentConfigName:y,AutoRollbackConfiguration:h?{Enabled:h.enabled,Events:h.events}:void 0,AlarmConfiguration:b?{Enabled:b.enabled,Alarms:b.alarms?.map((I)=>({Name:I.name})),IgnorePollAlarmFailure:b.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:v?{TargetGroupInfoList:v.targetGroupInfoList?.map((I)=>({Name:I.name})),ElbInfoList:v.elbInfoList?.map((I)=>({Name:I.name}))}:void 0,BlueGreenDeploymentConfiguration:A?{TerminateBlueInstancesOnDeploymentSuccess:A.terminateBlueInstancesOnDeploymentSuccess?{Action:A.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:A.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:A.deploymentReadyOption?{ActionOnTimeout:A.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:A.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:A.greenFleetProvisioningOption?{Action:A.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:o}]}},logicalId:R}}static createDeploymentConfig(n){let{slug:i,environment:s,deploymentConfigName:o,minimumHealthyHosts:c,trafficRoutingConfig:u}=n,d=o||r({slug:i,environment:s,resourceType:"deploy-config"}),p=t(d);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:d,MinimumHealthyHosts:c?{Type:c.type,Value:c.value}:void 0,TrafficRoutingConfig:u?{Type:u.type,TimeBasedCanary:u.timeBasedCanary?{CanaryPercentage:u.timeBasedCanary.canaryPercentage,CanaryInterval:u.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:u.timeBasedLinear?{LinearPercentage:u.timeBasedLinear.linearPercentage,LinearInterval:u.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:p}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(n,i)=>({type:n,value:i})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(n,i)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:n,canaryInterval:i}}),linear:(n,i)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:n,linearInterval:i}})};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:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:n},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:n},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:(n,i,s,o)=>{let{application:c,logicalId:u}=Z.createApplication({slug:n,environment:i,computePlatform:"Server"}),{deploymentGroup:d,logicalId:p}=Z.createDeploymentGroup(u,{slug:n,environment:i,serviceRoleArn:s,autoScalingGroups:o,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Z.RollbackConfigs.onFailure()});return{application:c,appId:u,deploymentGroup:d,groupId:p}},lambdaCanaryDeployment:(n,i,s,o=10,c=5)=>{let{application:u,logicalId:d}=Z.createApplication({slug:n,environment:i,computePlatform:"Lambda"}),{deploymentConfig:p,logicalId:y}=Z.createDeploymentConfig({slug:n,environment:i,trafficRoutingConfig:Z.TrafficRouting.canary(o,c)}),{deploymentGroup:h,logicalId:b}=Z.createDeploymentGroup(d,{slug:n,environment:i,serviceRoleArn:s,deploymentConfigName:x.Ref(y),autoRollbackConfiguration:Z.RollbackConfigs.onAlarmOrFailure()});return{application:u,appId:d,deploymentConfig:p,configId:y,deploymentGroup:h,groupId:b}},ecsBlueGreenDeployment:(n,i,s,o)=>{let{application:c,logicalId:u}=Z.createApplication({slug:n,environment:i,computePlatform:"ECS"}),{deploymentGroup:d,logicalId:p}=Z.createDeploymentGroup(u,{slug:n,environment:i,serviceRoleArn:s,loadBalancerInfo:{targetGroupInfoList:[{name:o}]},blueGreenDeploymentConfiguration:Z.BlueGreenConfigs.standard(),autoRollbackConfiguration:Z.RollbackConfigs.onFailure()});return{application:c,appId:u,deploymentGroup:d,groupId:p}}};static Strategies={rolling:(n=25)=>({type:"rolling",batchPercentage:n}),blueGreen:()=>({type:"blue-green"}),canary:(n=10,i=5)=>({type:"canary",canaryPercentage:n,canaryInterval:i}),allAtOnce:()=>({type:"all-at-once"})}}class _{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(n,i="md5"){let s=ot(n);return xr(i).update(s).digest("hex")}static computeShortHash(n){return _.computeFileHash(n).slice(0,8)}static getContentType(n){let i=bn(n).toLowerCase();return _.ContentTypes[i]||"application/octet-stream"}static shouldHashFile(n,i){return![..._.NoHashPatterns,...i||[]].some((o)=>o.test(n))}static generateHashedFilename(n,i){let s=bn(n),o=Or(n,s),c=yn(n);if(c===".")return`${o}.${i}${s}`;return Ke(c,`${o}.${i}${s}`)}static collectFiles(n,i){let s=[],o=i||n;if(!Tt(n))return s;let c=Mr(n,{withFileTypes:!0});for(let u of c){let d=Ke(n,u.name);if(u.isDirectory())s.push(..._.collectFiles(d,o));else if(u.isFile())s.push(d)}return s}static hashDirectory(n){let{sourceDir:i,outputDir:s,excludePatterns:o=[],hashAlgorithm:c="md5",copyUnhashed:u=!0}=n,d=_.collectFiles(i),p=[],y={};for(let b of d){let v=b.replace(i,"").replace(/^[/\\]/,""),A=_.shouldHashFile(v,o),T=Lr(b),R=A?_.computeFileHash(b,c).slice(0,8):"",P=A?_.generateHashedFilename(v,R):v,I={originalPath:v,hashedPath:P,hash:R,size:T.size,contentType:_.getContentType(b)};if(p.push(I),y[v]=P,s){let M=Ke(s,P),L=yn(M);if(!Tt(L)){let{mkdirSync:N}=it("node:fs");N(L,{recursive:!0})}if(A||u)kr(b,M)}}let h={version:"1.0",timestamp:new Date().toISOString(),assets:p,hashMap:y};if(s){let b=Ke(s,"asset-manifest.json");ct(b,JSON.stringify(h,null,2))}return h}static getInvalidationPaths(n,i){let s=[];if(!n)return["/*"];let o=n.hashMap,c=i.hashMap;for(let[u,d]of Object.entries(c)){let p=o[u];if(!p||p!==d){if(s.push(`/${u}`),p&&p!==d)s.push(`/${p}`)}}for(let[u,d]of Object.entries(o))if(!c[u])s.push(`/${u}`),s.push(`/${d}`);if(s.length>100)return["/*"];return[...new Set(s)]}static updateHtmlReferences(n){let{htmlDir:i,manifest:s,basePath:o=""}=n,c=_.collectFiles(i).filter((u)=>u.endsWith(".html")||u.endsWith(".htm"));for(let u of c){let d=ot(u,"utf-8");for(let[p,y]of Object.entries(s.hashMap)){if(p===y)continue;let h=[new RegExp(`(src|href)=["']${o}/?${_.escapeRegExp(p)}["']`,"g"),new RegExp(`url\\(["']?${o}/?${_.escapeRegExp(p)}["']?\\)`,"g")];for(let b of h)d=d.replace(b,(v)=>v.replace(p,y))}ct(u,d)}}static updateCssReferences(n){let{cssDir:i,manifest:s,basePath:o=""}=n,c=_.collectFiles(i).filter((u)=>u.endsWith(".css"));for(let u of c){let d=ot(u,"utf-8");for(let[p,y]of Object.entries(s.hashMap)){if(p===y)continue;let h=new RegExp(`url\\(["']?${o}/?${_.escapeRegExp(p)}["']?\\)`,"g");d=d.replace(h,`url(${o}/${y})`)}ct(u,d)}}static escapeRegExp(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(n){let{sourceDir:i,keyPrefix:s="",excludePatterns:o=[],cacheControl:c={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=n;return _.hashDirectory({sourceDir:i,excludePatterns:o}).assets.map((d)=>{let p=d.hash!=="",y=d.contentType==="text/html",h=c.unhashed||"public, max-age=3600";if(y)h=c.html||"public, max-age=0, must-revalidate";else if(p)h=c.hashed||"public, max-age=31536000, immutable";return{localPath:Ke(i,d.originalPath),s3Key:s?`${s}/${d.hashedPath}`:d.hashedPath,contentType:d.contentType,cacheControl:h,hash:d.hash}})}static compareManifests(n,i){let s={added:[],removed:[],changed:[],unchanged:[]},o=new Set(Object.keys(n.hashMap)),c=new Set(Object.keys(i.hashMap));for(let u of c)if(!o.has(u))s.added.push(u);for(let u of o)if(!c.has(u))s.removed.push(u);for(let u of c)if(o.has(u))if(n.hashMap[u]!==i.hashMap[u])s.changed.push(u);else s.unchanged.push(u);return s}static loadManifest(n){if(!Tt(n))return null;try{let i=ot(n,"utf-8");return JSON.parse(i)}catch{return null}}static saveManifest(n,i){ct(i,JSON.stringify(n,null,2))}}class Yi{static createSecret(n){let{slug:i,environment:s,secretName:o,description:c,secretString:u,kmsKeyId:d,tags:p}=n,y=o||r({slug:i,environment:s,resourceType:"secret"}),h=t(y),b={Type:"AWS::SecretsManager::Secret",Properties:{Name:y,Description:c,SecretString:u,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},...p?Object.entries(p).map(([v,A])=>({Key:v,Value:A})):[]]}};if(d)b.Properties.KmsKeyId=d;return{secret:b,logicalId:h}}static createGeneratedSecret(n){let{slug:i,environment:s,secretName:o,description:c,excludeCharacters:u,excludeLowercase:d,excludeNumbers:p,excludePunctuation:y,excludeUppercase:h,passwordLength:b,requireEachIncludedType:v,kmsKeyId:A,tags:T}=n,R=o||r({slug:i,environment:s,resourceType:"secret"}),P=t(R),I={Type:"AWS::SecretsManager::Secret",Properties:{Name:R,Description:c,GenerateSecretString:{ExcludeCharacters:u,ExcludeLowercase:d,ExcludeNumbers:p,ExcludePunctuation:y,ExcludeUppercase:h,PasswordLength:b||32,RequireEachIncludedType:v!==!1},Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:s},...T?Object.entries(T).map(([M,L])=>({Key:M,Value:L})):[]]}};if(A)I.Properties.KmsKeyId=A;return{secret:I,logicalId:P}}static createDatabaseSecret(n){let{slug:i,environment:s,secretName:o,username:c,dbname:u,engine:d,host:p,port:y,kmsKeyId:h}=n,b=o||r({slug:i,environment:s,resourceType:"db-secret"}),v=t(b),A={username:c};if(u)A.dbname=u;if(d)A.engine=d;if(p)A.host=p;if(y)A.port=y;let T={Type:"AWS::SecretsManager::Secret",Properties:{Name:b,Description:`Database credentials for ${c}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(A),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s},{Key:"Type",Value:"database"}]}};if(h)T.Properties.KmsKeyId=h;return{secret:T,logicalId:v}}static attachToDatabase(n){let{slug:i,environment:s,secretId:o,targetId:c,targetType:u}=n,d=r({slug:i,environment:s,resourceType:"secret-attachment"}),p=t(d);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:o,TargetId:c,TargetType:u}},logicalId:p}}static enableRotation(n){let{slug:i,environment:s,secretId:o,rotationLambdaArn:c,automaticallyAfterDays:u,rotationType:d,kmsKeyArn:p,vpcSecurityGroupIds:y,vpcSubnetIds:h}=n,b=r({slug:i,environment:s,resourceType:"secret-rotation"}),v=t(b),A={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:o,RotationRules:{AutomaticallyAfterDays:u||30}}};if(c)A.Properties.RotationLambdaARN=c;else if(d)A.Properties.HostedRotationLambda={RotationType:d,KmsKeyArn:p,VpcSecurityGroupIds:y,VpcSubnetIds:h};return{rotation:A,logicalId:v}}static SecretTypes={apiKey:(n,i,s)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-api-key`,description:`API key for ${s}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(n,i,s)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-oauth-secret`,description:`OAuth client secret for ${s}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(n,i)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(n,i)=>Yi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-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 D{static createParameter(n){let{slug:i,environment:s,parameterName:o,value:c,type:u="String",description:d,tier:p="Standard",tags:y}=n,h=o||r({slug:i,environment:s,resourceType:"parameter"}),b=t(h);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${i}/${s}/${h}`,Type:u,Value:c,Description:d,Tier:p,Tags:{Name:h,Environment:s,...y}}},logicalId:b}}static createString(n,i,s,o,c){return D.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"String",description:c})}static createSecureString(n,i,s,o,c){return D.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"SecureString",description:c})}static createStringList(n,i,s,o,c){return D.createParameter({slug:n,environment:i,parameterName:s,value:o.join(","),type:"StringList",description:c})}static Parameters={databaseUrl:(n,i,s)=>D.createSecureString(n,i,"database-url",s,"Database connection URL"),apiEndpoint:(n,i,s)=>D.createString(n,i,"api-endpoint",s,"API endpoint URL"),appVersion:(n,i,s)=>D.createString(n,i,"app-version",s,"Application version"),featureFlags:(n,i,s)=>D.createStringList(n,i,"feature-flags",s,"Enabled feature flags"),apiKey:(n,i,s,o)=>D.createSecureString(n,i,`${s}-api-key`,o,`API key for ${s}`),oauthCredentials:(n,i,s,o)=>{let c=D.createString(n,i,"oauth-client-id",s,"OAuth client ID"),u=D.createSecureString(n,i,"oauth-client-secret",o,"OAuth client secret");return{clientId:c,clientSecret:u}},smtpCredentials:(n,i,s,o,c,u)=>{let d=D.createString(n,i,"smtp-username",s,"SMTP username"),p=D.createSecureString(n,i,"smtp-password",o,"SMTP password"),y=D.createString(n,i,"smtp-host",c,"SMTP host"),h=D.createString(n,i,"smtp-port",u.toString(),"SMTP port");return{username:d,password:p,host:y,port:h}},redisUrl:(n,i,s)=>D.createSecureString(n,i,"redis-url",s,"Redis connection URL"),s3Bucket:(n,i,s)=>D.createString(n,i,"s3-bucket",s,"S3 bucket name"),cloudFrontDistribution:(n,i,s)=>D.createString(n,i,"cloudfront-distribution-id",s,"CloudFront distribution ID")}}class gr{static createDomain(n){let{slug:i,environment:s,domainName:o,engineVersion:c="OpenSearch_2.11",instanceType:u="t3.small.search",instanceCount:d=1,volumeSize:p=10,volumeType:y="gp3",dedicatedMaster:h=!1,dedicatedMasterType:b,dedicatedMasterCount:v=3,multiAz:A=!1,availabilityZoneCount:T=2,vpc:R,encryption:P,enforceHttps:I=!0,tlsSecurityPolicy:M="Policy-Min-TLS-1-2-2019-07",advancedSecurity:L,autoSnapshotHour:N=0,autoTune:O=!0,tags:B={}}=n,F=o||r({slug:i,environment:s,resourceType:"search"}),U=t(F);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:F,EngineVersion:c,ClusterConfig:{InstanceType:u,InstanceCount:d,DedicatedMasterEnabled:h,...h&&{DedicatedMasterType:b||u,DedicatedMasterCount:v},ZoneAwarenessEnabled:A,...A&&{ZoneAwarenessConfig:{AvailabilityZoneCount:T}}},EBSOptions:{EBSEnabled:!0,VolumeType:y,VolumeSize:p},DomainEndpointOptions:{EnforceHTTPS:I,TLSSecurityPolicy:M},SnapshotOptions:{AutomatedSnapshotStartHour:N},...R&&{VPCOptions:{SubnetIds:R.subnetIds,SecurityGroupIds:R.securityGroupIds}},...P&&{EncryptionAtRestOptions:{Enabled:P.atRest??!0,...P.kmsKeyId&&{KmsKeyId:P.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:P.nodeToNode??!0}},...L&&{AdvancedSecurityOptions:{Enabled:L.enabled,InternalUserDatabaseEnabled:L.internalUserDatabase??!0,...L.masterUserName&&L.masterUserPassword&&{MasterUserOptions:{MasterUserName:L.masterUserName,MasterUserPassword:L.masterUserPassword}},...L.masterUserArn&&{MasterUserOptions:{MasterUserARN:L.masterUserArn}}}},...O&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:F},{Key:"Environment",Value:s},...Object.entries(B).map(([H,z])=>({Key:H,Value:z}))]}},logicalId:U}}static createAccessPolicy(n,i){let{ipAddresses:s,iamPrincipalArns:o,allowAll:c,vpcEndpoint:u}=i;if(c)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};let d=[];if(o&&o.length>0)d.push({Effect:"Allow",Principal:{AWS:o},Action:"es:*",Resource:n});if(s&&s.length>0)d.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n,Condition:{IpAddress:{"aws:SourceIp":s}}});if(u)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};return{Version:"2012-10-17",Statement:d}}static DomainPresets={development:(n,i)=>gr.createDomain({slug:n,environment:i,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(n,i,s)=>gr.createDomain({slug:n,environment:i,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:s,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(n,i)=>gr.createDomain({slug:n,environment:i,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(n,i,s)=>gr.createDomain({slug:n,environment:i,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:s,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 Bt{static createDomainRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:u="https"}=n,d=r({slug:i,environment:s,resourceType:"s3",suffix:"redirect"}),p=t(d),y=t(`${d}-policy`),h={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:u}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Domain Redirect"}]}},b={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:x.Ref(p),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[x.Join("",[x.GetAtt(p,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:b,logicalId:p,policyLogicalId:y}}static createPathRedirectFunction(n){let{slug:i,environment:s,rules:o}=n,c=r({slug:i,environment:s,resourceType:"cf-redirect"}),u=t(c),d=Bt.generateRedirectFunctionCode(o);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:c,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${i} (${s})`,Runtime:"cloudfront-js-2.0"},FunctionCode:d}},logicalId:u,functionCode:d}}static generateRedirectFunctionCode(n){return`function handler(event) {
|
|
2282
2282
|
const request = event.request;
|
|
2283
2283
|
const uri = request.uri;
|
|
2284
2284
|
const querystring = request.querystring;
|
|
@@ -2332,7 +2332,7 @@ ${n.map((s)=>{let o=s.preserveQueryString!==!1,c=s.statusCode||301;return` '${s
|
|
|
2332
2332
|
}
|
|
2333
2333
|
|
|
2334
2334
|
return request;
|
|
2335
|
-
}`}static CommonRedirects={wwwToApex:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${n}`,targetDomain:n,protocol:i,preservePath:!0}),apexToWww:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:n,targetDomain:`www.${n}`,protocol:i,preservePath:!0}),httpToHttps:(n="/")=>({source:n,target:n,statusCode:301}),addTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")?i.slice(0,-1):i,target:i.endsWith("/")?i:`${i}/`,statusCode:301})),removeTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")&&i!=="/"?i:`${i}/`,target:i.endsWith("/")&&i!=="/"?i.slice(0,-1):i,statusCode:301}))};static Patterns={flattenBlogUrls:(n)=>n.map(({oldPath:i,newPath:s})=>({source:i,target:s,statusCode:301,preserveQueryString:!0})),categoryRename:(n,i)=>[{source:`/${n}`,target:`/${i}`,statusCode:301},{source:`/${n}/`,target:`/${i}/`,statusCode:301}],productSlugChange:(n)=>n.map(({oldSlug:i,newSlug:s})=>({source:`/products/${i}`,target:`/products/${s}`,statusCode:301})),apiVersionRedirect:(n,i,s)=>s.map((o)=>({source:`/api/${n}/${o}`,target:`/api/${i}/${o}`,statusCode:307,preserveQueryString:!0})),gonePages:(n)=>n.map((i)=>({source:i,target:"/410",statusCode:301}))};static createRedirectSetup(n){let{slug:i,environment:s,domainRedirects:o=[],pathRedirects:c=[]}=n,u={},d=[];for(let y of o){let{bucket:h,bucketPolicy:b,logicalId:v,policyLogicalId:A}=Nt.createDomainRedirectBucket({...y,slug:i,environment:s});u[v]=h,u[A]=b,d.push(v)}let p=null;if(c.length>0){let{function:y,logicalId:h}=Nt.createPathRedirectFunction({slug:i,environment:s,rules:c});u[h]=y,p=h}return{resources:u,outputs:{domainRedirectBuckets:d,pathRedirectFunctionLogicalId:p}}}static fromMapping(n,i){return Object.entries(n).map(([s,o])=>({source:s,target:o,statusCode:i?.statusCode||301,preserveQueryString:i?.preserveQueryString??!0}))}static validateRules(n){let i=[],s=[],o=new Set;for(let c of n){if(o.has(c.source))i.push(`Duplicate source path: ${c.source}`);if(o.add(c.source),c.source===c.target)i.push(`Redirect loop detected: ${c.source} -> ${c.target}`);if(!c.target.startsWith("/")&&!c.target.startsWith("http"))s.push(`Target URL should start with / or http: ${c.target}`);if(!c.source||c.source.trim()==="")i.push("Source path cannot be empty");if(!c.target||c.target.trim()==="")i.push("Target path cannot be empty")}for(let c of n){let u=n.find((d)=>d.source===c.target);if(u)s.push(`Potential redirect chain: ${c.source} -> ${c.target} -> ${u.target}`)}return{valid:i.length===0,errors:i,warnings:s}}}class ee{static generate(n){let i={},{slug:s,environment:o,region:c="us-east-1"}=n,u=ee.createLambdaExecutionRole(s,o);if(Object.assign(i,u.resources),n.email?.enabled){let d=ee.generateEmailResources(n,u.roleArn);Object.assign(i,d)}if(n.phone?.enabled){let d=ee.generatePhoneResources(n,u.roleArn);Object.assign(i,d)}if(n.sms?.enabled){let d=ee.generateSmsResources(n,u.roleArn);Object.assign(i,d)}return i}static createLambdaExecutionRole(n,i){let s=`${n}-${i}-communication-role`,o=t(s);return{resources:{[o]:{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"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:x.GetAtt(o,"Arn"),roleName:s}}static generateEmailResources(n,i){let{slug:s,environment:o,email:c}=n;if(!c)return{};let u={},d=`${s}-${o}`,p=`${d}-email-storage`,y=t(p);u[y]={Type:"AWS::S3::Bucket",Properties:{BucketName:p,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:c.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:c.server.storage.archiveAfterDays}]:[],ExpirationInDays:c.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let h=t(`${d}-ses-identity`);if(u[h]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:c.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},c.notifications?.bounces||c.notifications?.complaints){let b=t(`${d}-bounce-topic`);u[b]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-email-bounces`}};let v=t(`${d}-complaint-topic`);u[v]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-email-complaints`}}}if(c.server?.enabled){let b=t(`${d}-inbound-email`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:ee.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:p,DOMAIN:c.domain}}}};let v=t(`${d}-outbound-email`);u[v]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:p,DOMAIN:c.domain}}}}}if(c.advanced?.analytics){let b=t(`${d}-email-analytics`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.scheduling){let b=t(`${d}-email-scheduler`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:300,MemorySize:256,Code:{ZipFile:ee.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:p}}}};let v=t(`${d}-email-scheduler-rule`);u[v]={Type:"AWS::Events::Rule",Properties:{Name:`${d}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:x.GetAtt(b,"Arn")}]}}}if(c.advanced?.threading){let b=t(`${d}-email-threading`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:ee.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:p}}}}}if(c.advanced?.rules){let b=t(`${d}-email-rules`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(c.advanced?.sharedMailboxes){let b=t(`${d}-shared-mailboxes`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(c.advanced?.search){let b=t(`${d}-email-search`);u[b]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${d}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return u}static generatePhoneResources(n,i){let{slug:s,environment:o,phone:c}=n;if(!c)return{};let u={},d=`${s}-${o}`,p=t(`${d}-call-log`);if(u[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.voicemail?.enabled){let b=t(`${d}-voicemail`);u[b]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${d}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let y=t(`${d}-phone-notifications`);u[y]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-phone-notifications`}};let h=t(`${d}-incoming-call`);if(u[h]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${d}-call-log`,NOTIFICATION_TOPIC_ARN:x.Ref(y)}}}},c.voicemail?.enabled){let b=t(`${d}-voicemail-handler`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ee.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${d}-voicemail`,TRANSCRIPTION_ENABLED:String(c.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:x.Ref(y)}}}}}if(c.advanced?.recording){let b=t(`${d}-call-recordings`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.callbacks){let b=t(`${d}-callbacks`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.analytics){let b=t(`${d}-call-metrics`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return u}static generateSmsResources(n,i){let{slug:s,environment:o,sms:c}=n;if(!c)return{};let u={},d=`${s}-${o}`,p=t(`${d}-pinpoint-app`);u[p]={Type:"AWS::Pinpoint::App",Properties:{Name:`${d}-sms`}};let y=t(`${d}-sms-channel`);u[y]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:x.Ref(p),Enabled:!0,SenderId:c.senderId}};let h=t(`${d}-sms-log`);if(u[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.optOut?.enabled){let T=t(`${d}-sms-optout`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let b=t(`${d}-sms-notifications`);u[b]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-sms-notifications`}};let v=t(`${d}-send-sms`);u[v]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:x.Ref(p),MESSAGE_LOG_TABLE:`${d}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${d}-sms-optout`:"",MESSAGE_TYPE:c.messageType||"TRANSACTIONAL"}}}};let A=t(`${d}-receive-sms`);if(u[A]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${d}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${d}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:x.Ref(b)}}}},c.advanced?.campaigns){let T=t(`${d}-sms-campaigns`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.analytics){let T=t(`${d}-sms-analytics`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.linkTracking){let T=t(`${d}-short-links`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.chatbot){let T=t(`${d}-chatbot-sessions`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let R=t(`${d}-chatbot-rules`);u[R]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.abTesting){let T=t(`${d}-ab-tests`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.mms){let T=t(`${d}-mms-media`);u[T]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${d}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return u}static InboundEmailCode=`
|
|
2335
|
+
}`}static CommonRedirects={wwwToApex:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${n}`,targetDomain:n,protocol:i,preservePath:!0}),apexToWww:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:n,targetDomain:`www.${n}`,protocol:i,preservePath:!0}),httpToHttps:(n="/")=>({source:n,target:n,statusCode:301}),addTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")?i.slice(0,-1):i,target:i.endsWith("/")?i:`${i}/`,statusCode:301})),removeTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")&&i!=="/"?i:`${i}/`,target:i.endsWith("/")&&i!=="/"?i.slice(0,-1):i,statusCode:301}))};static Patterns={flattenBlogUrls:(n)=>n.map(({oldPath:i,newPath:s})=>({source:i,target:s,statusCode:301,preserveQueryString:!0})),categoryRename:(n,i)=>[{source:`/${n}`,target:`/${i}`,statusCode:301},{source:`/${n}/`,target:`/${i}/`,statusCode:301}],productSlugChange:(n)=>n.map(({oldSlug:i,newSlug:s})=>({source:`/products/${i}`,target:`/products/${s}`,statusCode:301})),apiVersionRedirect:(n,i,s)=>s.map((o)=>({source:`/api/${n}/${o}`,target:`/api/${i}/${o}`,statusCode:307,preserveQueryString:!0})),gonePages:(n)=>n.map((i)=>({source:i,target:"/410",statusCode:301}))};static createRedirectSetup(n){let{slug:i,environment:s,domainRedirects:o=[],pathRedirects:c=[]}=n,u={},d=[];for(let y of o){let{bucket:h,bucketPolicy:b,logicalId:v,policyLogicalId:A}=Bt.createDomainRedirectBucket({...y,slug:i,environment:s});u[v]=h,u[A]=b,d.push(v)}let p=null;if(c.length>0){let{function:y,logicalId:h}=Bt.createPathRedirectFunction({slug:i,environment:s,rules:c});u[h]=y,p=h}return{resources:u,outputs:{domainRedirectBuckets:d,pathRedirectFunctionLogicalId:p}}}static fromMapping(n,i){return Object.entries(n).map(([s,o])=>({source:s,target:o,statusCode:i?.statusCode||301,preserveQueryString:i?.preserveQueryString??!0}))}static validateRules(n){let i=[],s=[],o=new Set;for(let c of n){if(o.has(c.source))i.push(`Duplicate source path: ${c.source}`);if(o.add(c.source),c.source===c.target)i.push(`Redirect loop detected: ${c.source} -> ${c.target}`);if(!c.target.startsWith("/")&&!c.target.startsWith("http"))s.push(`Target URL should start with / or http: ${c.target}`);if(!c.source||c.source.trim()==="")i.push("Source path cannot be empty");if(!c.target||c.target.trim()==="")i.push("Target path cannot be empty")}for(let c of n){let u=n.find((d)=>d.source===c.target);if(u)s.push(`Potential redirect chain: ${c.source} -> ${c.target} -> ${u.target}`)}return{valid:i.length===0,errors:i,warnings:s}}}class ee{static generate(n){let i={},{slug:s,environment:o,region:c="us-east-1"}=n,u=ee.createLambdaExecutionRole(s,o);if(Object.assign(i,u.resources),n.email?.enabled){let d=ee.generateEmailResources(n,u.roleArn);Object.assign(i,d)}if(n.phone?.enabled){let d=ee.generatePhoneResources(n,u.roleArn);Object.assign(i,d)}if(n.sms?.enabled){let d=ee.generateSmsResources(n,u.roleArn);Object.assign(i,d)}return i}static createLambdaExecutionRole(n,i){let s=`${n}-${i}-communication-role`,o=t(s);return{resources:{[o]:{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"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:x.GetAtt(o,"Arn"),roleName:s}}static generateEmailResources(n,i){let{slug:s,environment:o,email:c}=n;if(!c)return{};let u={},d=`${s}-${o}`,p=`${d}-email-storage`,y=t(p);u[y]={Type:"AWS::S3::Bucket",Properties:{BucketName:p,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:c.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:c.server.storage.archiveAfterDays}]:[],ExpirationInDays:c.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let h=t(`${d}-ses-identity`);if(u[h]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:c.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},c.notifications?.bounces||c.notifications?.complaints){let b=t(`${d}-bounce-topic`);u[b]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-email-bounces`}};let v=t(`${d}-complaint-topic`);u[v]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-email-complaints`}}}if(c.server?.enabled){let b=t(`${d}-inbound-email`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:ee.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:p,DOMAIN:c.domain}}}};let v=t(`${d}-outbound-email`);u[v]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:p,DOMAIN:c.domain}}}}}if(c.advanced?.analytics){let b=t(`${d}-email-analytics`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.scheduling){let b=t(`${d}-email-scheduler`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:300,MemorySize:256,Code:{ZipFile:ee.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:p}}}};let v=t(`${d}-email-scheduler-rule`);u[v]={Type:"AWS::Events::Rule",Properties:{Name:`${d}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:x.GetAtt(b,"Arn")}]}}}if(c.advanced?.threading){let b=t(`${d}-email-threading`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:ee.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:p}}}}}if(c.advanced?.rules){let b=t(`${d}-email-rules`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(c.advanced?.sharedMailboxes){let b=t(`${d}-shared-mailboxes`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(c.advanced?.search){let b=t(`${d}-email-search`);u[b]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${d}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return u}static generatePhoneResources(n,i){let{slug:s,environment:o,phone:c}=n;if(!c)return{};let u={},d=`${s}-${o}`,p=t(`${d}-call-log`);if(u[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.voicemail?.enabled){let b=t(`${d}-voicemail`);u[b]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${d}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let y=t(`${d}-phone-notifications`);u[y]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-phone-notifications`}};let h=t(`${d}-incoming-call`);if(u[h]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${d}-call-log`,NOTIFICATION_TOPIC_ARN:x.Ref(y)}}}},c.voicemail?.enabled){let b=t(`${d}-voicemail-handler`);u[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ee.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${d}-voicemail`,TRANSCRIPTION_ENABLED:String(c.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:x.Ref(y)}}}}}if(c.advanced?.recording){let b=t(`${d}-call-recordings`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.callbacks){let b=t(`${d}-callbacks`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.analytics){let b=t(`${d}-call-metrics`);u[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return u}static generateSmsResources(n,i){let{slug:s,environment:o,sms:c}=n;if(!c)return{};let u={},d=`${s}-${o}`,p=t(`${d}-pinpoint-app`);u[p]={Type:"AWS::Pinpoint::App",Properties:{Name:`${d}-sms`}};let y=t(`${d}-sms-channel`);u[y]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:x.Ref(p),Enabled:!0,SenderId:c.senderId}};let h=t(`${d}-sms-log`);if(u[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.optOut?.enabled){let T=t(`${d}-sms-optout`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let b=t(`${d}-sms-notifications`);u[b]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${d}-sms-notifications`}};let v=t(`${d}-send-sms`);u[v]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:x.Ref(p),MESSAGE_LOG_TABLE:`${d}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${d}-sms-optout`:"",MESSAGE_TYPE:c.messageType||"TRANSACTIONAL"}}}};let A=t(`${d}-receive-sms`);if(u[A]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${d}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:ee.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${d}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${d}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:x.Ref(b)}}}},c.advanced?.campaigns){let T=t(`${d}-sms-campaigns`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.analytics){let T=t(`${d}-sms-analytics`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.linkTracking){let T=t(`${d}-short-links`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.chatbot){let T=t(`${d}-chatbot-sessions`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let R=t(`${d}-chatbot-rules`);u[R]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.abTesting){let T=t(`${d}-ab-tests`);u[T]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${d}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.mms){let T=t(`${d}-mms-media`);u[T]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${d}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return u}static InboundEmailCode=`
|
|
2336
2336
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
2337
2337
|
const s3 = new S3Client({});
|
|
2338
2338
|
exports.handler = async (event) => {
|
|
@@ -2451,23 +2451,23 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
|
|
|
2451
2451
|
};`},Environment:i.environment?{Variables:i.environment}:void 0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}`)}]};if(s!=="edge")u.VpcConfig={SubnetIds:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],SecurityGroupIds:[e.ref("AppSecurityGroup")]};if(n.addResource(o,"AWS::Lambda::Function",u,{dependsOn:c}),n.addResource(`${o}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/aws/lambda/\${AWS::StackName}-${i.name}`),RetentionInDays:14}),i.events)i.events.forEach((d,p)=>{Qr(n,o,d,p)});n.addOutputs({[`${o}Arn`]:{Description:`${i.name} function ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-function-arn`)}}})}function Qr(n,i,s,o){let c=`${i}EventSource${o}`;switch(s.type){case"http":break;case"s3":if(s.bucket){let u=n.toLogicalId(`${s.bucket}-bucket`);n.addResource(`${c}Permission`,"AWS::Lambda::Permission",{FunctionName:e.ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:un.s3Bucket(e.ref(u))},{dependsOn:[i,u]})}break;case"sqs":if(s.queueName){let u=n.toLogicalId(`${s.queueName}-queue`);n.addResource(c,"AWS::Lambda::EventSourceMapping",{EventSourceArn:e.getAtt(u,"Arn"),FunctionName:e.ref(i),BatchSize:s.batchSize||10},{dependsOn:[i,u]})}break;case"kinesis":if(s.streamName){let u=n.toLogicalId(`${s.streamName}-stream`);n.addResource(c,"AWS::Lambda::EventSourceMapping",{EventSourceArn:e.getAtt(u,"Arn"),FunctionName:e.ref(i),BatchSize:s.batchSize||100,StartingPosition:s.startingPosition||"LATEST",ParallelizationFactor:s.parallelizationFactor||1},{dependsOn:[i,u]})}break;case"dynamodb-stream":if(s.tableName){let u=n.toLogicalId(`${s.tableName}-table`);n.addResource(c,"AWS::Lambda::EventSourceMapping",{EventSourceArn:e.getAtt(u,"StreamArn"),FunctionName:e.ref(i),BatchSize:s.batchSize||100,StartingPosition:s.startingPosition||"LATEST"},{dependsOn:[i,u]})}break;case"schedule":if(s.expression)n.addResource(`${c}Rule`,"AWS::Events::Rule",{ScheduleExpression:s.expression,State:"ENABLED",Targets:[{Arn:e.getAtt(i,"Arn"),Id:`${i}Target`}]},{dependsOn:i}),n.addResource(`${c}Permission`,"AWS::Lambda::Permission",{FunctionName:e.ref(i),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.getAtt(`${c}Rule`,"Arn")},{dependsOn:[i,`${c}Rule`]});break}}function Jr(n){let i=[];if(!n)return i;if(n.forEach((s)=>{switch(s.type){case"s3":i.push({Effect:"Allow",Action:["s3:GetObject","s3:GetObjectVersion"],Resource:s.bucket?`arn:aws:s3:::${s.bucket}/*`:"arn:aws:s3:::*/*"});break;case"sqs":i.push({Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes"],Resource:s.queueName?un.sqs(s.queueName):"arn:aws:sqs:*:*:*"});break;case"kinesis":i.push({Effect:"Allow",Action:["kinesis:GetRecords","kinesis:GetShardIterator","kinesis:DescribeStream","kinesis:ListStreams"],Resource:s.streamName?un.kinesis(s.streamName):"arn:aws:kinesis:*:*:stream/*"});break;case"dynamodb-stream":i.push({Effect:"Allow",Action:["dynamodb:GetRecords","dynamodb:GetShardIterator","dynamodb:DescribeStream","dynamodb:ListStreams"],Resource:s.tableName?e.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${s.tableName}/stream/*`):"arn:aws:dynamodb:*:*:table/*/stream/*"});break}}),i.length===0)i.push({Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:*"});return i}function wn(n,i){if(i.topics)i.topics.forEach((s)=>{Yr(n,s)})}function Yr(n,i){let s=n.toLogicalId(`${i.name}-topic`);if(n.addResource(s,"AWS::SNS::Topic",{TopicName:e.sub(`\${AWS::StackName}-${i.name}`),DisplayName:i.displayName||i.name,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}`)}]}),n.addResource(`${s}Policy`,"AWS::SNS::TopicPolicy",{Topics:[e.ref(s)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["events.amazonaws.com","cloudwatch.amazonaws.com","s3.amazonaws.com"]},Action:"sns:Publish",Resource:e.ref(s)},{Effect:"Allow",Principal:{AWS:e.sub("arn:aws:iam::${AWS::AccountId}:root")},Action:["sns:Subscribe","sns:Publish","sns:Receive"],Resource:e.ref(s)}]}},{dependsOn:s}),i.subscriptions)i.subscriptions.forEach((o,c)=>{let u=`${s}Subscription${c+1}`,d={Protocol:o.protocol,TopicArn:e.ref(s),Endpoint:o.endpoint};if(o.filterPolicy)d.FilterPolicy=o.filterPolicy;if(o.protocol==="sqs"){let p=n.toLogicalId(`${o.endpoint}-queue`);d.Endpoint=e.getAtt(p,"Arn")}if(o.protocol==="lambda"){let p=n.toLogicalId(o.endpoint);d.Endpoint=e.getAtt(p,"Arn"),n.addResource(`${u}Permission`,"AWS::Lambda::Permission",{FunctionName:e.ref(p),Action:"lambda:InvokeFunction",Principal:"sns.amazonaws.com",SourceArn:e.ref(s)},{dependsOn:[p,s]})}n.addResource(u,"AWS::SNS::Subscription",d,{dependsOn:s})});n.addOutputs({[`${s}Arn`]:{Description:`${i.name} topic ARN`,Value:e.ref(s),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-topic-arn`)}}})}function In(n,i){if(i.alarms&&i.alarms.length>0)n.addResource("AlarmTopic","AWS::SNS::Topic",{TopicName:e.sub("${AWS::StackName}-alarms"),DisplayName:"CloudWatch Alarms",Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alarms")}]}),i.alarms.forEach((s,o)=>{Zr(n,s,o)});if(i.dashboard)Xr(n,i.dashboard);if(i.logs?.groups)i.logs.groups.forEach((s)=>{ei(n,s,i.logs?.retention)})}function Zr(n,i,s){let o=n.toLogicalId(`alarm-${i.name||i.metric}-${s}`),c={AlarmName:i.name||e.sub(`\${AWS::StackName}-${i.metric}`),AlarmDescription:`Alarm for ${i.metric}`,MetricName:i.metric,Namespace:i.namespace||Et(i.metric,i.service),Statistic:i.statistic||"Average",Period:i.period||300,EvaluationPeriods:i.evaluationPeriods||1,Threshold:i.threshold,ComparisonOperator:i.comparisonOperator||"GreaterThanThreshold",TreatMissingData:i.treatMissingData||"notBreaching",AlarmActions:[e.ref("AlarmTopic")],OKActions:[e.ref("AlarmTopic")]};if(i.dimensions)c.Dimensions=Object.entries(i.dimensions).map(([u,d])=>({Name:u,Value:d}));else if(i.service)c.Dimensions=ti(i.service);n.addResource(o,"AWS::CloudWatch::Alarm",c,{dependsOn:"AlarmTopic"})}function Xr(n,i){if(!i)return;let s=[],o=0,c=0;i.widgets?.forEach((u)=>{let d=u.width||12,p=u.height||6;if(u.type==="metric"&&u.metrics){let y=u.metrics.map((h)=>{if(typeof h==="string")return[Et(h),h];else return[Et(h.metric,h.service),h.metric]});s.push({type:"metric",x:o,y:c,width:d,height:p,properties:{metrics:y,period:300,stat:"Average",region:e.ref("AWS::Region"),title:u.metrics.length>1?"Multiple Metrics":typeof u.metrics[0]==="string"?u.metrics[0]:u.metrics[0].metric}})}else if(u.type==="log"&&u.logGroup)s.push({type:"log",x:o,y:c,width:d,height:p,properties:{query:`SOURCE '${u.logGroup}'
|
|
2452
2452
|
| fields @timestamp, @message
|
|
2453
2453
|
| sort @timestamp desc
|
|
2454
|
-
| limit 20`,region:e.ref("AWS::Region"),title:`Logs: ${u.logGroup}`}});else if(u.type==="text"&&u.text)s.push({type:"text",x:o,y:c,width:d,height:p,properties:{markdown:u.text}});if(o+=d,o>=24)o=0,c+=p}),n.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:e.sub(`\${AWS::StackName}-${i.name}`),DashboardBody:JSON.stringify({widgets:s})}),n.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:e.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function ei(n,i,s){let o=n.toLogicalId(`${i}-log-group`);n.addResource(o,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/aws/\${AWS::StackName}/${i}`),RetentionInDays:s||14,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]})}function Et(n,i){if(i)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"}[i.toLowerCase()]||"AWS/CloudWatch";let s=n.toLowerCase();if(s.includes("cpu")||s.includes("memory")||s.includes("network"))return"AWS/EC2";if(s.includes("lambda")||s.includes("invocation")||s.includes("duration"))return"AWS/Lambda";if(s.includes("request")||s.includes("latency")||s.includes("target"))return"AWS/ApplicationELB";if(s.includes("database")||s.includes("connection"))return"AWS/RDS";if(s.includes("read")||s.includes("write")||s.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function ti(n){return{ec2:[{Name:"InstanceId",Value:e.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:e.ref("ECSCluster")},{Name:"ServiceName",Value:e.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:e.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:e.ref("Database")}],dynamodb:[{Name:"TableName",Value:e.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:e.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:e.ref("HttpApi")}]}[n.toLowerCase()]||[]}function Dn(n,i){if(!i.vpc)return;let{cidr:s="10.0.0.0/16",availabilityZones:o=2,natGateways:c=1,enableDnsHostnames:u=!0,enableDnsSupport:d=!0}=i.vpc;n.addResource("VPC","AWS::EC2::VPC",{CidrBlock:s,EnableDnsHostnames:u,EnableDnsSupport:d,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-vpc")}]}),n.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-igw")}]}),n.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:e.ref("VPC"),InternetGatewayId:e.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let p=[];for(let v=0;v<o;v++){let A=`PublicSubnet${v+1}`;p.push(A),n.addResource(A,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(v,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(v,e.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-public-${v+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let y=[];for(let v=0;v<o;v++){let A=`PrivateSubnet${v+1}`;y.push(A),n.addResource(A,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(v+o,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(v,e.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-${v+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let h=[];for(let v=0;v<c;v++){let A=`NatEIP${v+1}`;h.push(A),n.addResource(A,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-eip-${v+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let b=[];for(let v=0;v<c;v++){let A=`NatGateway${v+1}`;b.push(A);let T=v%o;n.addResource(A,"AWS::EC2::NatGateway",{AllocationId:e.getAtt(h[v],"AllocationId"),SubnetId:e.ref(p[T]),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-${v+1}`)}]},{dependsOn:[h[v],p[T]]})}n.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),n.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:e.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:e.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),p.forEach((v,A)=>{n.addResource(`PublicSubnetRouteTableAssociation${A+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(v),RouteTableId:e.ref("PublicRouteTable")},{dependsOn:[v,"PublicRouteTable"]})}),y.forEach((v,A)=>{let T=`PrivateRouteTable${A+1}`,R=A%c;n.addResource(T,"AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-rt-${A+1}`)}]},{dependsOn:"VPC"}),n.addResource(`PrivateRoute${A+1}`,"AWS::EC2::Route",{RouteTableId:e.ref(T),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:e.ref(b[R])},{dependsOn:[T,b[R]]}),n.addResource(`PrivateSubnetRouteTableAssociation${A+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(v),RouteTableId:e.ref(T)},{dependsOn:[v,T]})}),n.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:e.ref("VPC"),ServiceName:e.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[e.ref("PublicRouteTable"),...Array.from({length:o},(v,A)=>e.ref(`PrivateRouteTable${A+1}`))]},{dependsOn:"VPC"}),n.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),n.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addOutputs({VPCId:{Description:"VPC ID",Value:e.ref("VPC"),Export:{Name:e.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:e.join(",",p.map((v)=>e.ref(v))),Export:{Name:e.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:e.join(",",y.map((v)=>e.ref(v))),Export:{Name:e.sub("${AWS::StackName}-PrivateSubnets")}}})}function Nn(n,i){for(let[s,o]of Object.entries(i))ni(n,s,o)}function ni(n,i,s){let o=n.toLogicalId(`${i}-queue`),c=s.fifo||!1,u;if(s.deadLetterQueue){let p=`${o}DLQ`;n.addResource(p,"AWS::SQS::Queue",{QueueName:c?e.sub(`\${AWS::StackName}-${i}-dlq.fifo`):e.sub(`\${AWS::StackName}-${i}-dlq`),FifoQueue:c,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),u=e.getAtt(p,"Arn")}let d={QueueName:c?e.sub(`\${AWS::StackName}-${i}.fifo`):e.sub(`\${AWS::StackName}-${i}`),FifoQueue:c,VisibilityTimeout:s.visibilityTimeout||30,MessageRetentionPeriod:s.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:s.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(c&&s.contentBasedDeduplication)d.ContentBasedDeduplication=!0;if(s.deadLetterQueue&&u)d.RedrivePolicy={deadLetterTargetArn:u,maxReceiveCount:s.maxReceiveCount||3};if(n.addResource(o,"AWS::SQS::Queue",d,{dependsOn:s.deadLetterQueue?`${o}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),n.addResource(`${o}Policy`,"AWS::SQS::QueuePolicy",{Queues:[e.ref(o)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:e.getAtt(o,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":e.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:o}),n.addOutputs({[`${o}Url`]:{Description:`${i} queue URL`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-url`)}},[`${o}Arn`]:{Description:`${i} queue ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-arn`)}}}),s.deadLetterQueue)n.addOutputs({[`${o}DLQUrl`]:{Description:`${i} dead letter queue URL`,Value:e.ref(`${o}DLQ`),Export:{Name:e.sub(`\${AWS::StackName}-${i}-dlq-url`)}}})}function xn(n,i){if(i.certificate)ri(n,i.certificate);if(i.waf?.enabled)ii(n,i.waf);if(i.securityGroups)for(let[s,o]of Object.entries(i.securityGroups))ai(n,s,o)}function ri(n,i){if(!i)return;let s=[i.domain];if(i.subdomains)s.push(...i.subdomains);n.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:i.domain,SubjectAlternativeNames:i.subdomains,ValidationMethod:i.validationMethod||"DNS",DomainValidationOptions:s.map((o)=>({DomainName:o,HostedZoneId:e.ref("HostedZone")})),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-certificate")}]}),n.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:e.ref("Certificate"),Export:{Name:e.sub("${AWS::StackName}-certificate-arn")}}})}function ii(n,i){if(!i)return;let s=[],o=i.rules||["rateLimit","sqlInjection","xss"];if(o.includes("rateLimit"))s.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:i.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let c=s.length+1;if(o.includes("sqlInjection"))s.push({Name:"AWSManagedRulesSQLi",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(o.includes("xss"))s.push({Name:"AWSManagedRulesXSS",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(o.includes("knownBadInputs"))s.push({Name:"AWSManagedRulesKnownBadInputs",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(o.includes("coreRuleSet"))s.push({Name:"AWSManagedRulesCoreRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(o.includes("linuxRuleSet"))s.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(o.includes("apiProtection"))s.push({Name:"AWSManagedRulesAPIProtection",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(o.includes("geoBlock"))s.push({Name:"GeoBlockRule",Priority:c++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(o.includes("connectionLimit"))s.push({Name:"ConnectionLimitRule",Priority:c++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(n.addResource("WebACL","AWS::WAFv2::WebACL",{Name:e.sub("${AWS::StackName}-waf"),Scope:i.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:e.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-waf")}]}),n.hasResource("LoadBalancer"))n.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:e.ref("LoadBalancer"),WebACLArn:e.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});n.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:e.ref("WebACL"),Export:{Name:e.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:e.getAtt("WebACL","Arn"),Export:{Name:e.sub("${AWS::StackName}-waf-arn")}}})}function ai(n,i,s){if(!s)return;let o=n.toLogicalId(`${i}-security-group`),c=s.ingress?.map((d)=>({IpProtocol:d.protocol,FromPort:d.port,ToPort:d.port,CidrIp:d.cidr,SourceSecurityGroupId:d.source?e.ref(d.source):void 0}))||[],u=s.egress?.map((d)=>({IpProtocol:d.protocol,FromPort:d.port,ToPort:d.port,CidrIp:d.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];n.addResource(o,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${i}`,VpcId:e.ref("VPC"),SecurityGroupIngress:c,SecurityGroupEgress:u,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-sg`)}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} security group ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-sg-id`)}}})}function kn(n,i){for(let[s,o]of Object.entries(i)){if(o.type==="efs"){oi(n,s,o);continue}si(n,s,o)}}function si(n,i,s){let o=n.toLogicalId(`${i}-bucket`),c={BucketName:e.sub(`\${AWS::StackName}-${i}`),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.versioning)c.VersioningConfiguration={Status:"Enabled"};if(s.encryption)c.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!s.public)c.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(s.website)c.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(s.cors&&s.cors.length>0)c.CorsConfiguration={CorsRules:s.cors.map((u)=>({AllowedOrigins:u.allowedOrigins,AllowedMethods:u.allowedMethods,AllowedHeaders:u.allowedHeaders||["*"],MaxAge:u.maxAge||3600}))};if(s.lifecycleRules&&s.lifecycleRules.length>0)c.LifecycleConfiguration={Rules:s.lifecycleRules.map((u)=>({Id:u.id,Status:u.enabled?"Enabled":"Disabled",ExpirationInDays:u.expirationDays,Transitions:u.transitions?.map((d)=>({TransitionInDays:d.days,StorageClass:d.storageClass}))}))};if(s.intelligentTiering)c.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(n.addResource(o,"AWS::S3::Bucket",c,{deletionPolicy:s.versioning?"Retain":"Delete"}),s.public)n.addResource(`${o}Policy`,"AWS::S3::BucketPolicy",{Bucket:e.ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:e.join("",[un.s3Bucket(e.ref(o)),"/*"])}]}},{dependsOn:o});if(n.addOutputs({[`${o}Name`]:{Description:`${i} bucket name`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket`)}},[`${o}Arn`]:{Description:`${i} bucket ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket-arn`)}}}),s.website)n.addOutputs({[`${o}WebsiteURL`]:{Description:`${i} website URL`,Value:e.getAtt(o,"WebsiteURL")}})}function oi(n,i,s){let o=n.toLogicalId(`${i}-efs`),c={Encrypted:s.encryption!==!1,PerformanceMode:s.performanceMode||"generalPurpose",ThroughputMode:s.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.lifecyclePolicy){if(c.LifecyclePolicies=[],s.lifecyclePolicy.transitionToIA)c.LifecyclePolicies.push({TransitionToIA:`AFTER_${s.lifecyclePolicy.transitionToIA}_DAYS`});if(s.lifecyclePolicy.transitionToPrimaryStorageClass)c.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}n.addResource(o,"AWS::EFS::FileSystem",c,{deletionPolicy:"Retain"});let u=2;for(let d=0;d<u;d++)n.addResource(`${o}MountTarget${d+1}`,"AWS::EFS::MountTarget",{FileSystemId:e.ref(o),SubnetId:e.ref(`PrivateSubnet${d+1}`),SecurityGroups:[e.ref("EFSSecurityGroup")]},{dependsOn:[o,`PrivateSubnet${d+1}`]});n.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:e.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} EFS file system ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-efs`)}}})}class Bm{template;config;resourceDependencies;constructor(n){this.config=n,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${n.project.name} (${n.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:e.equals(e.ref("Environment"),"production"),HasDomain:e.not([e.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:n}=this.config;if(!n)return;if(n.network)this.addNetworkResources(n.network);if(n.storage)this.addStorageResources(n.storage);if(n.compute)this.addComputeResources(n.compute);if(n.databases)this.addDatabaseResources(n.databases);if(n.cache)this.addCacheResources(n.cache);if(n.cdn)this.addCDNResources(n.cdn);if(n.apiGateway)this.addApiGatewayResources(n.apiGateway);if(n.functions)this.addFunctionResources(n.functions);if(n.queues)this.addQueueResources(n.queues);if(n.messaging)this.addMessagingResources(n.messaging);if(n.monitoring)this.addMonitoringResources(n.monitoring);if(n.security)this.addSecurityResources(n.security)}initializeOutputs(){let n=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:e.ref("AWS::StackName"),Export:{Name:e.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:e.ref("AWS::Region"),Export:{Name:e.sub("${AWS::StackName}-Region")}},...n},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(n,i,s,o){let c={Type:i,Properties:s};if(o?.dependsOn)c.DependsOn=o.dependsOn,this.trackDependency(n,o.dependsOn);if(o?.condition)c.Condition=o.condition;if(o?.deletionPolicy)c.DeletionPolicy=o.deletionPolicy;if(o?.updateReplacePolicy)c.UpdateReplacePolicy=o.updateReplacePolicy;this.template.Resources[n]=c}addOutputs(n){this.template.Outputs={...this.template.Outputs,...n}}getOutputs(){return this.template.Outputs||{}}hasResource(n){return n in this.template.Resources}getResource(n){return this.template.Resources[n]}trackDependency(n,i){if(!this.resourceDependencies.has(n))this.resourceDependencies.set(n,new Set);(Array.isArray(i)?i:[i]).forEach((o)=>this.resourceDependencies.get(n).add(o))}resolveDependencies(){let n=new Set,i=new Set,s=(o)=>{if(i.has(o))throw Error(`Circular dependency detected involving resource: ${o}`);if(n.has(o))return!0;n.add(o),i.add(o);let c=this.resourceDependencies.get(o);if(c)for(let u of c)s(u);return i.delete(o),!0};for(let o of this.resourceDependencies.keys())s(o)}toLogicalId(n){return n.split(/[-_\s]/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1).toLowerCase()).join("")}addNetworkResources(n){Dn(this,n)}addStorageResources(n){kn(this,n)}addComputeResources(n){Tn(this,n)}addDatabaseResources(n){Pn(this,n)}addFunctionResources(n){En(this,n)}addCacheResources(n){An(this,n)}addQueueResources(n){Nn(this,n)}addMessagingResources(n){wn(this,n)}addCDNResources(n){Cn(this,n)}addApiGatewayResources(n){Sn(this,n)}addMonitoringResources(n){In(this,n)}addSecurityResources(n){xn(this,n)}}function fl(n){return new Bm(n).build()}function XI(n){let{name:i,slug:s,domain:o,subdomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:c&&o?`${c}.${o}`:o}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:o?{domain:c&&o?`${c}.${o}`:o,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 YI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small",minInstances:u=2,maxInstances:d=10}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-key`,autoScaling:{min:u,max:d,desired:u,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:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function ZI(n){let{name:i,slug:s,domain:o,taskCpu:c="256",taskMemory:u="512",desiredCount:d=2}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:c,memory:u,containerDefinitions:[{name:"app",image:`${s}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:d,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:d,max:d*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${s}-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:`${s}-queue`}]}},security:{certificate:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function eb(n){let{name:i,slug:s,entry:o,domain:c,runtime:u="nodejs20.x",memory:d=1024,build:p,deploy:y,assets:h,queues:b=!0,scheduler:v="on",region:A="us-east-1"}=n;return{project:{name:i,slug:s,region:A},mode:"serverless",environments:{production:{type:"production",domain:c,app:{kind:"node",runtime:u,entry:o,memory:d,build:p,deploy:y,assets:h,queues:b,scheduler:v,domain:c}}}}}function hl(n){let i=n.database!==!1,s=n.cache!==!1,o=n.queue!==!1;return{project:{name:n.name,slug:n.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:n.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:n.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:e.ref("AWS::Region")},...i?[{name:"DB_HOST",value:e.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:e.getAtt("PostgresDb","Endpoint.Port")}]:[],...s?[{name:"REDIS_HOST",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...o?[{name:"QUEUE_URL",value:e.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:i?[{name:"DB_USERNAME",valueFrom:e.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:e.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:n.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:n.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...n.certificateArn?{customDomain:{domain:n.domain,certificateArn:n.certificateArn}}:{},...n.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:n.originVerifySecret}}:{}}}},...i?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...s?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...o?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function tb(n){let{name:i,slug:s,domain:o,apiSubdomain:c="api"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},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:o,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:`${s}-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:`${c}.${o}`,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:o,subdomains:[`*.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function rb(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:o?{domain:o,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:{[`${s}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${s}-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:o?{domain:o,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 nb(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-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:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:o,subdomains:[`www.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function ib(n){let{name:i,slug:s,domain:o,apiDomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},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:o,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},...c?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:c?{type:"HTTP",customDomain:{domain:c,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[o],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:o,subdomains:c?[c]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function sb(n){let{name:i,slug:s,domain:o,services:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:c.map((u)=>({name:u.name,type:"fargate",taskDefinition:{cpu:u.cpu||"256",memory:u.memory||"512",containerDefinitions:[{name:u.name,image:`${s}-${u.name}:latest`,portMappings:[{containerPort:u.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${u.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:u.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${s}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:c.map((u)=>({path:`/${u.name}/{proxy+}`,integration:{type:"vpc-link",service:u.name}}))},databases:{dynamodb:{tables:Object.fromEntries(c.map((u)=>[`${s}-${u.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:`${s}-events`,subscriptions:c.map((u)=>({protocol:"sqs",endpoint:`${s}-${u.name}-queue`,filterPolicy:{service:[u.name]}}))}}},monitoring:{dashboard:{name:`${s}-microservices`,widgets:c.map((u)=>({type:"metric",metrics:[{service:u.name,metric:"CPUUtilization"},{service:u.name,metric:"MemoryUtilization"},{service:u.name,metric:"RequestCount"}]}))},alarms:c.flatMap((u)=>[{name:`${u.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:u.name},{name:`${u.name}-errors`,metric:"Errors",threshold:10,service:u.name}])},security:{certificate:{domain:o,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function ob(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"websocket",customDomain:o?{domain:o,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:`${s}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${s}-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"}]},[`${s}-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"}]},[`${s}-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:`${s}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function ab(n){let{name:i,slug:s,retentionDays:o=7}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${s}-stream`,shardCount:2,retentionPeriod:o*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:`${s}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-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:`${s}_analytics`,workgroup:`${s}-workgroup`,outputBucket:`${s}-query-results`,tables:[{name:"raw_events",location:`s3://${s}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${s}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${s}-crawler`,databaseName:`${s}_analytics`,s3Targets:[`s3://${s}-raw/`,`s3://${s}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${s}-etl-job`,scriptLocation:`s3://${s}-scripts/etl.py`,role:`${s}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${s}-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:`${s}-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:`${s}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function cb(n){let{name:i,slug:s,domain:o,modelS3Path:c=`s3://${s}-models/`,instanceType:u="ml.t3.medium"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},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:`${s}-inference`,modelS3Path:c,instanceType:u,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${s}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:o?{domain:o,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:`${s}-inference`,MODEL_BUCKET:`${s}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-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:{[`${s}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${s}-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:`${s}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function db(n){let{name:i,slug:s,domain:o,instanceType:c="t3.medium",minInstances:u=2,maxInstances:d=10,databaseEngine:p="mysql",sessionStore:y="redis"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",autoScaling:{min:u,max:d,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:e.ref("AWS::Region"),title:`Logs: ${u.logGroup}`}});else if(u.type==="text"&&u.text)s.push({type:"text",x:o,y:c,width:d,height:p,properties:{markdown:u.text}});if(o+=d,o>=24)o=0,c+=p}),n.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:e.sub(`\${AWS::StackName}-${i.name}`),DashboardBody:JSON.stringify({widgets:s})}),n.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:e.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function ei(n,i,s){let o=n.toLogicalId(`${i}-log-group`);n.addResource(o,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/aws/\${AWS::StackName}/${i}`),RetentionInDays:s||14,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]})}function Et(n,i){if(i)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"}[i.toLowerCase()]||"AWS/CloudWatch";let s=n.toLowerCase();if(s.includes("cpu")||s.includes("memory")||s.includes("network"))return"AWS/EC2";if(s.includes("lambda")||s.includes("invocation")||s.includes("duration"))return"AWS/Lambda";if(s.includes("request")||s.includes("latency")||s.includes("target"))return"AWS/ApplicationELB";if(s.includes("database")||s.includes("connection"))return"AWS/RDS";if(s.includes("read")||s.includes("write")||s.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function ti(n){return{ec2:[{Name:"InstanceId",Value:e.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:e.ref("ECSCluster")},{Name:"ServiceName",Value:e.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:e.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:e.ref("Database")}],dynamodb:[{Name:"TableName",Value:e.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:e.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:e.ref("HttpApi")}]}[n.toLowerCase()]||[]}function Dn(n,i){if(!i.vpc)return;let{cidr:s="10.0.0.0/16",availabilityZones:o=2,natGateways:c=1,enableDnsHostnames:u=!0,enableDnsSupport:d=!0}=i.vpc;n.addResource("VPC","AWS::EC2::VPC",{CidrBlock:s,EnableDnsHostnames:u,EnableDnsSupport:d,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-vpc")}]}),n.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-igw")}]}),n.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:e.ref("VPC"),InternetGatewayId:e.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let p=[];for(let v=0;v<o;v++){let A=`PublicSubnet${v+1}`;p.push(A),n.addResource(A,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(v,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(v,e.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-public-${v+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let y=[];for(let v=0;v<o;v++){let A=`PrivateSubnet${v+1}`;y.push(A),n.addResource(A,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(v+o,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(v,e.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-${v+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let h=[];for(let v=0;v<c;v++){let A=`NatEIP${v+1}`;h.push(A),n.addResource(A,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-eip-${v+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let b=[];for(let v=0;v<c;v++){let A=`NatGateway${v+1}`;b.push(A);let T=v%o;n.addResource(A,"AWS::EC2::NatGateway",{AllocationId:e.getAtt(h[v],"AllocationId"),SubnetId:e.ref(p[T]),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-${v+1}`)}]},{dependsOn:[h[v],p[T]]})}n.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),n.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:e.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:e.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),p.forEach((v,A)=>{n.addResource(`PublicSubnetRouteTableAssociation${A+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(v),RouteTableId:e.ref("PublicRouteTable")},{dependsOn:[v,"PublicRouteTable"]})}),y.forEach((v,A)=>{let T=`PrivateRouteTable${A+1}`,R=A%c;n.addResource(T,"AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-rt-${A+1}`)}]},{dependsOn:"VPC"}),n.addResource(`PrivateRoute${A+1}`,"AWS::EC2::Route",{RouteTableId:e.ref(T),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:e.ref(b[R])},{dependsOn:[T,b[R]]}),n.addResource(`PrivateSubnetRouteTableAssociation${A+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(v),RouteTableId:e.ref(T)},{dependsOn:[v,T]})}),n.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:e.ref("VPC"),ServiceName:e.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[e.ref("PublicRouteTable"),...Array.from({length:o},(v,A)=>e.ref(`PrivateRouteTable${A+1}`))]},{dependsOn:"VPC"}),n.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),n.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addOutputs({VPCId:{Description:"VPC ID",Value:e.ref("VPC"),Export:{Name:e.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:e.join(",",p.map((v)=>e.ref(v))),Export:{Name:e.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:e.join(",",y.map((v)=>e.ref(v))),Export:{Name:e.sub("${AWS::StackName}-PrivateSubnets")}}})}function Nn(n,i){for(let[s,o]of Object.entries(i))ni(n,s,o)}function ni(n,i,s){let o=n.toLogicalId(`${i}-queue`),c=s.fifo||!1,u;if(s.deadLetterQueue){let p=`${o}DLQ`;n.addResource(p,"AWS::SQS::Queue",{QueueName:c?e.sub(`\${AWS::StackName}-${i}-dlq.fifo`):e.sub(`\${AWS::StackName}-${i}-dlq`),FifoQueue:c,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),u=e.getAtt(p,"Arn")}let d={QueueName:c?e.sub(`\${AWS::StackName}-${i}.fifo`):e.sub(`\${AWS::StackName}-${i}`),FifoQueue:c,VisibilityTimeout:s.visibilityTimeout||30,MessageRetentionPeriod:s.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:s.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(c&&s.contentBasedDeduplication)d.ContentBasedDeduplication=!0;if(s.deadLetterQueue&&u)d.RedrivePolicy={deadLetterTargetArn:u,maxReceiveCount:s.maxReceiveCount||3};if(n.addResource(o,"AWS::SQS::Queue",d,{dependsOn:s.deadLetterQueue?`${o}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),n.addResource(`${o}Policy`,"AWS::SQS::QueuePolicy",{Queues:[e.ref(o)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:e.getAtt(o,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":e.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:o}),n.addOutputs({[`${o}Url`]:{Description:`${i} queue URL`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-url`)}},[`${o}Arn`]:{Description:`${i} queue ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-arn`)}}}),s.deadLetterQueue)n.addOutputs({[`${o}DLQUrl`]:{Description:`${i} dead letter queue URL`,Value:e.ref(`${o}DLQ`),Export:{Name:e.sub(`\${AWS::StackName}-${i}-dlq-url`)}}})}function xn(n,i){if(i.certificate)ri(n,i.certificate);if(i.waf?.enabled)ii(n,i.waf);if(i.securityGroups)for(let[s,o]of Object.entries(i.securityGroups))si(n,s,o)}function ri(n,i){if(!i)return;let s=[i.domain];if(i.subdomains)s.push(...i.subdomains);n.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:i.domain,SubjectAlternativeNames:i.subdomains,ValidationMethod:i.validationMethod||"DNS",DomainValidationOptions:s.map((o)=>({DomainName:o,HostedZoneId:e.ref("HostedZone")})),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-certificate")}]}),n.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:e.ref("Certificate"),Export:{Name:e.sub("${AWS::StackName}-certificate-arn")}}})}function ii(n,i){if(!i)return;let s=[],o=i.rules||["rateLimit","sqlInjection","xss"];if(o.includes("rateLimit"))s.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:i.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let c=s.length+1;if(o.includes("sqlInjection"))s.push({Name:"AWSManagedRulesSQLi",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(o.includes("xss"))s.push({Name:"AWSManagedRulesXSS",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(o.includes("knownBadInputs"))s.push({Name:"AWSManagedRulesKnownBadInputs",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(o.includes("coreRuleSet"))s.push({Name:"AWSManagedRulesCoreRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(o.includes("linuxRuleSet"))s.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(o.includes("apiProtection"))s.push({Name:"AWSManagedRulesAPIProtection",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(o.includes("geoBlock"))s.push({Name:"GeoBlockRule",Priority:c++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(o.includes("connectionLimit"))s.push({Name:"ConnectionLimitRule",Priority:c++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(n.addResource("WebACL","AWS::WAFv2::WebACL",{Name:e.sub("${AWS::StackName}-waf"),Scope:i.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:e.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-waf")}]}),n.hasResource("LoadBalancer"))n.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:e.ref("LoadBalancer"),WebACLArn:e.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});n.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:e.ref("WebACL"),Export:{Name:e.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:e.getAtt("WebACL","Arn"),Export:{Name:e.sub("${AWS::StackName}-waf-arn")}}})}function si(n,i,s){if(!s)return;let o=n.toLogicalId(`${i}-security-group`),c=s.ingress?.map((d)=>({IpProtocol:d.protocol,FromPort:d.port,ToPort:d.port,CidrIp:d.cidr,SourceSecurityGroupId:d.source?e.ref(d.source):void 0}))||[],u=s.egress?.map((d)=>({IpProtocol:d.protocol,FromPort:d.port,ToPort:d.port,CidrIp:d.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];n.addResource(o,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${i}`,VpcId:e.ref("VPC"),SecurityGroupIngress:c,SecurityGroupEgress:u,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-sg`)}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} security group ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-sg-id`)}}})}function kn(n,i){for(let[s,o]of Object.entries(i)){if(o.type==="efs"){oi(n,s,o);continue}ai(n,s,o)}}function ai(n,i,s){let o=n.toLogicalId(`${i}-bucket`),c={BucketName:e.sub(`\${AWS::StackName}-${i}`),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.versioning)c.VersioningConfiguration={Status:"Enabled"};if(s.encryption)c.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!s.public)c.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(s.website)c.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(s.cors&&s.cors.length>0)c.CorsConfiguration={CorsRules:s.cors.map((u)=>({AllowedOrigins:u.allowedOrigins,AllowedMethods:u.allowedMethods,AllowedHeaders:u.allowedHeaders||["*"],MaxAge:u.maxAge||3600}))};if(s.lifecycleRules&&s.lifecycleRules.length>0)c.LifecycleConfiguration={Rules:s.lifecycleRules.map((u)=>({Id:u.id,Status:u.enabled?"Enabled":"Disabled",ExpirationInDays:u.expirationDays,Transitions:u.transitions?.map((d)=>({TransitionInDays:d.days,StorageClass:d.storageClass}))}))};if(s.intelligentTiering)c.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(n.addResource(o,"AWS::S3::Bucket",c,{deletionPolicy:s.versioning?"Retain":"Delete"}),s.public)n.addResource(`${o}Policy`,"AWS::S3::BucketPolicy",{Bucket:e.ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:e.join("",[un.s3Bucket(e.ref(o)),"/*"])}]}},{dependsOn:o});if(n.addOutputs({[`${o}Name`]:{Description:`${i} bucket name`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket`)}},[`${o}Arn`]:{Description:`${i} bucket ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket-arn`)}}}),s.website)n.addOutputs({[`${o}WebsiteURL`]:{Description:`${i} website URL`,Value:e.getAtt(o,"WebsiteURL")}})}function oi(n,i,s){let o=n.toLogicalId(`${i}-efs`),c={Encrypted:s.encryption!==!1,PerformanceMode:s.performanceMode||"generalPurpose",ThroughputMode:s.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.lifecyclePolicy){if(c.LifecyclePolicies=[],s.lifecyclePolicy.transitionToIA)c.LifecyclePolicies.push({TransitionToIA:`AFTER_${s.lifecyclePolicy.transitionToIA}_DAYS`});if(s.lifecyclePolicy.transitionToPrimaryStorageClass)c.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}n.addResource(o,"AWS::EFS::FileSystem",c,{deletionPolicy:"Retain"});let u=2;for(let d=0;d<u;d++)n.addResource(`${o}MountTarget${d+1}`,"AWS::EFS::MountTarget",{FileSystemId:e.ref(o),SubnetId:e.ref(`PrivateSubnet${d+1}`),SecurityGroups:[e.ref("EFSSecurityGroup")]},{dependsOn:[o,`PrivateSubnet${d+1}`]});n.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:e.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} EFS file system ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-efs`)}}})}class Bm{template;config;resourceDependencies;constructor(n){this.config=n,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${n.project.name} (${n.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:e.equals(e.ref("Environment"),"production"),HasDomain:e.not([e.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:n}=this.config;if(!n)return;if(n.network)this.addNetworkResources(n.network);if(n.storage)this.addStorageResources(n.storage);if(n.compute)this.addComputeResources(n.compute);if(n.databases)this.addDatabaseResources(n.databases);if(n.cache)this.addCacheResources(n.cache);if(n.cdn)this.addCDNResources(n.cdn);if(n.apiGateway)this.addApiGatewayResources(n.apiGateway);if(n.functions)this.addFunctionResources(n.functions);if(n.queues)this.addQueueResources(n.queues);if(n.messaging)this.addMessagingResources(n.messaging);if(n.monitoring)this.addMonitoringResources(n.monitoring);if(n.security)this.addSecurityResources(n.security)}initializeOutputs(){let n=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:e.ref("AWS::StackName"),Export:{Name:e.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:e.ref("AWS::Region"),Export:{Name:e.sub("${AWS::StackName}-Region")}},...n},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(n,i,s,o){let c={Type:i,Properties:s};if(o?.dependsOn)c.DependsOn=o.dependsOn,this.trackDependency(n,o.dependsOn);if(o?.condition)c.Condition=o.condition;if(o?.deletionPolicy)c.DeletionPolicy=o.deletionPolicy;if(o?.updateReplacePolicy)c.UpdateReplacePolicy=o.updateReplacePolicy;this.template.Resources[n]=c}addOutputs(n){this.template.Outputs={...this.template.Outputs,...n}}getOutputs(){return this.template.Outputs||{}}hasResource(n){return n in this.template.Resources}getResource(n){return this.template.Resources[n]}trackDependency(n,i){if(!this.resourceDependencies.has(n))this.resourceDependencies.set(n,new Set);(Array.isArray(i)?i:[i]).forEach((o)=>this.resourceDependencies.get(n).add(o))}resolveDependencies(){let n=new Set,i=new Set,s=(o)=>{if(i.has(o))throw Error(`Circular dependency detected involving resource: ${o}`);if(n.has(o))return!0;n.add(o),i.add(o);let c=this.resourceDependencies.get(o);if(c)for(let u of c)s(u);return i.delete(o),!0};for(let o of this.resourceDependencies.keys())s(o)}toLogicalId(n){return n.split(/[-_\s]/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1).toLowerCase()).join("")}addNetworkResources(n){Dn(this,n)}addStorageResources(n){kn(this,n)}addComputeResources(n){Tn(this,n)}addDatabaseResources(n){Pn(this,n)}addFunctionResources(n){En(this,n)}addCacheResources(n){An(this,n)}addQueueResources(n){Nn(this,n)}addMessagingResources(n){wn(this,n)}addCDNResources(n){Cn(this,n)}addApiGatewayResources(n){Sn(this,n)}addMonitoringResources(n){In(this,n)}addSecurityResources(n){xn(this,n)}}function fl(n){return new Bm(n).build()}function XI(n){let{name:i,slug:s,domain:o,subdomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:c&&o?`${c}.${o}`:o}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:o?{domain:c&&o?`${c}.${o}`:o,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 YI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small",minInstances:u=2,maxInstances:d=10}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-key`,autoScaling:{min:u,max:d,desired:u,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:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function ZI(n){let{name:i,slug:s,domain:o,taskCpu:c="256",taskMemory:u="512",desiredCount:d=2}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:c,memory:u,containerDefinitions:[{name:"app",image:`${s}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:d,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:d,max:d*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${s}-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:`${s}-queue`}]}},security:{certificate:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function eb(n){let{name:i,slug:s,entry:o,domain:c,runtime:u="nodejs20.x",memory:d=1024,build:p,deploy:y,assets:h,queues:b=!0,scheduler:v="on",region:A="us-east-1"}=n;return{project:{name:i,slug:s,region:A},mode:"serverless",environments:{production:{type:"production",domain:c,app:{kind:"node",runtime:u,entry:o,memory:d,build:p,deploy:y,assets:h,queues:b,scheduler:v,domain:c}}}}}function hl(n){let i=n.database!==!1,s=n.cache!==!1,o=n.queue!==!1;return{project:{name:n.name,slug:n.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:n.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:n.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:e.ref("AWS::Region")},...i?[{name:"DB_HOST",value:e.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:e.getAtt("PostgresDb","Endpoint.Port")}]:[],...s?[{name:"REDIS_HOST",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...o?[{name:"QUEUE_URL",value:e.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:i?[{name:"DB_USERNAME",valueFrom:e.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:e.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:n.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:n.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...n.certificateArn?{customDomain:{domain:n.domain,certificateArn:n.certificateArn}}:{},...n.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:n.originVerifySecret}}:{}}}},...i?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...s?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...o?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function tb(n){let{name:i,slug:s,domain:o,apiSubdomain:c="api"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},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:o,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:`${s}-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:`${c}.${o}`,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:o,subdomains:[`*.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function rb(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:o?{domain:o,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:{[`${s}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${s}-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:o?{domain:o,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 nb(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-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:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:o,subdomains:[`www.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function ib(n){let{name:i,slug:s,domain:o,apiDomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},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:o,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},...c?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:c?{type:"HTTP",customDomain:{domain:c,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[o],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:o,subdomains:c?[c]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function sb(n){let{name:i,slug:s,domain:o,services:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:c.map((u)=>({name:u.name,type:"fargate",taskDefinition:{cpu:u.cpu||"256",memory:u.memory||"512",containerDefinitions:[{name:u.name,image:`${s}-${u.name}:latest`,portMappings:[{containerPort:u.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${u.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:u.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${s}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:c.map((u)=>({path:`/${u.name}/{proxy+}`,integration:{type:"vpc-link",service:u.name}}))},databases:{dynamodb:{tables:Object.fromEntries(c.map((u)=>[`${s}-${u.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:`${s}-events`,subscriptions:c.map((u)=>({protocol:"sqs",endpoint:`${s}-${u.name}-queue`,filterPolicy:{service:[u.name]}}))}}},monitoring:{dashboard:{name:`${s}-microservices`,widgets:c.map((u)=>({type:"metric",metrics:[{service:u.name,metric:"CPUUtilization"},{service:u.name,metric:"MemoryUtilization"},{service:u.name,metric:"RequestCount"}]}))},alarms:c.flatMap((u)=>[{name:`${u.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:u.name},{name:`${u.name}-errors`,metric:"Errors",threshold:10,service:u.name}])},security:{certificate:{domain:o,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function ob(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"websocket",customDomain:o?{domain:o,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:`${s}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${s}-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"}]},[`${s}-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"}]},[`${s}-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:`${s}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function ab(n){let{name:i,slug:s,retentionDays:o=7}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${s}-stream`,shardCount:2,retentionPeriod:o*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:`${s}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-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:`${s}_analytics`,workgroup:`${s}-workgroup`,outputBucket:`${s}-query-results`,tables:[{name:"raw_events",location:`s3://${s}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${s}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${s}-crawler`,databaseName:`${s}_analytics`,s3Targets:[`s3://${s}-raw/`,`s3://${s}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${s}-etl-job`,scriptLocation:`s3://${s}-scripts/etl.py`,role:`${s}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${s}-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:`${s}-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:`${s}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function cb(n){let{name:i,slug:s,domain:o,modelS3Path:c=`s3://${s}-models/`,instanceType:u="ml.t3.medium"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},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:`${s}-inference`,modelS3Path:c,instanceType:u,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${s}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:o?{domain:o,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:`${s}-inference`,MODEL_BUCKET:`${s}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-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:{[`${s}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${s}-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:`${s}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function db(n){let{name:i,slug:s,domain:o,instanceType:c="t3.medium",minInstances:u=2,maxInstances:d=10,databaseEngine:p="mysql",sessionStore:y="redis"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",autoScaling:{min:u,max:d,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:[o||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${s}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:p==="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:y==="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:`${s}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${s}-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:`${s}-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:[`${s}-app`,`${s}-nginx`,`${s}-workers`]}},security:{certificate:o?{domain:o,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:p==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...y==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function lb(n){let{name:i,slug:s,domain:o,repository:c,phpVersion:u="8.3",size:d="small",database:p=s.replace(/-/g,"_"),databasePassword:y,sslEmail:h,deployStrategy:b="push",provider:v="hetzner"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",cloud:{provider:v},environments:{production:{type:"production",domain:o}},infrastructure:{compute:{mode:"server",size:d,runtime:"php",webServer:"nginx",php:{versions:[u],default:u},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:p,username:p,password:y}},sites:{main:{root:".",type:"laravel",domain:o,phpVersion:u,repository:{...c,strategy:b},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:h}}}}}function ub(n){let{name:i,slug:s,domain:o,layers:c,phpVersion:u="8.3",architecture:d="x86_64",memory:p=1024,build:y,deploy:h=["migrate --force"],cache:b="dynamodb",scheduler:v="on",region:A="us-east-1"}=n;return{project:{name:i,slug:s,region:A},mode:"serverless",environments:{production:{type:"production",domain:o,app:{kind:"php",runtime:"provided.al2023",phpVersion:u,architecture:d,layers:c,memory:p,build:y,deploy:h,assets:"public",queues:!0,scheduler:v,cache:{driver:b},domain:o}}}}}function gb(n){return{root:n.root??"packages/ui/dist",deploy:"server",type:"static",domain:n.domain,build:n.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:n.username??"admin",password:n.password}}}var cy=rl,dy="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function ci(n){let i=n.split(".").filter(Boolean);return i.length<=2?n:i.slice(-2).join(".")}function li(n){let i=2166136261;for(let s=0;s<n.length;s++)i^=n.charCodeAt(s),i=Math.imul(i,16777619);return i>>>0}var ly=20000,uy=12000;function gy(n){return ly+li(n)%uy}function Mn(n,i){let s=ci(n);if(s===n)return`dashboard.${s}`;for(let o of i)if(o===s)return`dashboard.${s}`;return`dashboard.${n}`}function Ln(n,i){let s=[],o=n.infrastructure?.dns?.domain;if(o&&!n.cloud?.attachTo)s.push(o);if(i&&n.environments?.[i]?.domain)s.push(n.environments[i].domain);for(let c of Object.values(n.sites??{})){let u=c;if(!u||u.redirect)continue;let d=u.domain;if(typeof d==="string")s.push(d);else if(Array.isArray(d))s.push(...d.filter((p)=>typeof p==="string"))}return s.filter((c)=>c&&!c.startsWith("dashboard."))}function py(n,i,s){if(s)return s;let o=Ln(n,i),c=o[0];if(!c)return null;return Mn(c,o)}function my(n,i,s){if(s)return[s];let o=Ln(n,i),c=[];for(let u of o){let d=Mn(u,o);if(!c.includes(d))c.push(d)}return c}function
|
|
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:[o||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${s}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:p==="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:y==="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:`${s}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${s}-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:`${s}-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:[`${s}-app`,`${s}-nginx`,`${s}-workers`]}},security:{certificate:o?{domain:o,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:p==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...y==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function lb(n){let{name:i,slug:s,domain:o,repository:c,phpVersion:u="8.3",size:d="small",database:p=s.replace(/-/g,"_"),databasePassword:y,sslEmail:h,deployStrategy:b="push",provider:v="hetzner"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",cloud:{provider:v},environments:{production:{type:"production",domain:o}},infrastructure:{compute:{mode:"server",size:d,runtime:"php",webServer:"nginx",php:{versions:[u],default:u},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:p,username:p,password:y}},sites:{main:{root:".",type:"laravel",domain:o,phpVersion:u,repository:{...c,strategy:b},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:h}}}}}function ub(n){let{name:i,slug:s,domain:o,layers:c,phpVersion:u="8.3",architecture:d="x86_64",memory:p=1024,build:y,deploy:h=["migrate --force"],cache:b="dynamodb",scheduler:v="on",region:A="us-east-1"}=n;return{project:{name:i,slug:s,region:A},mode:"serverless",environments:{production:{type:"production",domain:o,app:{kind:"php",runtime:"provided.al2023",phpVersion:u,architecture:d,layers:c,memory:p,build:y,deploy:h,assets:"public",queues:!0,scheduler:v,cache:{driver:b},domain:o}}}}}function gb(n){return{root:n.root??"packages/ui/dist",deploy:"server",type:"static",domain:n.domain,build:n.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:n.username??"admin",password:n.password}}}var cy=rl,dy="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function ci(n){let i=n.split(".").filter(Boolean);return i.length<=2?n:i.slice(-2).join(".")}function li(n){let i=2166136261;for(let s=0;s<n.length;s++)i^=n.charCodeAt(s),i=Math.imul(i,16777619);return i>>>0}var ly=20000,uy=12000;function gy(n){return ly+li(n)%uy}function Mn(n,i){let s=ci(n);if(s===n)return`dashboard.${s}`;for(let o of i)if(o===s)return`dashboard.${s}`;return`dashboard.${n}`}function Ln(n,i){let s=[],o=n.infrastructure?.dns?.domain;if(o&&!n.cloud?.attachTo)s.push(o);if(i&&n.environments?.[i]?.domain)s.push(n.environments[i].domain);for(let c of Object.values(n.sites??{})){let u=c;if(!u||u.redirect)continue;let d=u.domain;if(typeof d==="string")s.push(d);else if(Array.isArray(d))s.push(...d.filter((p)=>typeof p==="string"))}return s.filter((c)=>c&&!c.startsWith("dashboard."))}function py(n,i,s){if(s)return s;let o=Ln(n,i),c=o[0];if(!c)return null;return Mn(c,o)}function my(n,i,s){if(s)return[s];let o=Ln(n,i),c=[];for(let u of o){let d=Mn(u,o);if(!c.includes(d))c.push(d)}return c}function pr(n){return Object.entries(n.sites??{}).some(([i,s])=>{if(!s)return!1;let o=s.root??"";return mr(i)||o==="ui/dist"||o.endsWith("/ui/dist")||o.endsWith("/dist/ui")})}var xm="dashboard-";function Om(n){return xm+n.replace(/^dashboard\./,"").replace(/\./g,"-")}function mr(n){return n==="dashboard"||n.startsWith(xm)}function Zi(n,i,s){if(pr(n))return[];if(n.cloud?.attachTo)return[];let o=s.password?{auth:{username:s.username||"admin",password:s.password,realm:s.realm}}:{},c=s.build===!1||s.build===void 0?{}:{build:s.build};if(s.live!==!1){let d=py(n,i,s.domain);if(!d)return[];let p=s.port??gy(d),y=n.infrastructure?.appDatabase??n.infrastructure?.compute?.database,h={root:s.uiRoot,deploy:"server",domain:d,preStart:["bun install --production --no-save"],start:`bun ${dy} --box --host 127.0.0.1 --port ${p}`,port:p,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...y?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:y.password}:{}},zeroDowntime:!1,sharedPaths:[cy],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Om(d),site:h}]}return my(n,i,s.domain).map((d)=>({name:Om(d),site:{root:s.uiRoot,deploy:"server",type:"static",domain:d,ssl:{provider:"letsencrypt"},...c,...o}}))}function pb(n,i,s){return Zi(n,i,s)[0]??null}function wt(n,i){let s={...n};for(let o in i){let c=i[o],u=s[o];if(c===void 0)continue;if(Array.isArray(c)&&Array.isArray(u))s[o]=[...u,...c];else if(typeof c==="object"&&c!==null&&!Array.isArray(c)&&typeof u==="object"&&u!==null&&!Array.isArray(u))s[o]=wt(u,c);else s[o]=c}return s}function _m(n,i){return wt(n,i)}function mb(...n){return n.reduce((i,s)=>wt(i,s),{})}function fb(n,i){return(s)=>{let o=n(s);if(typeof i==="function")return _m(o,i(o,s));return _m(o,i)}}function gn(n){return{infrastructure:n}}function hb(n){return gn({monitoring:n})}function Ab(n){return gn({security:n})}function yb(n){return gn({databases:n})}function Sb(n){return gn({cache:n})}function Ib(n){return gn({cdn:n})}function bb(n){return gn({queues:n})}import{existsSync as On,readFileSync as It}from"node:fs";import{homedir as $n}from"node:os";import{join as Bn}from"node:path";function fy(){let n=process.env.AWS_ACCESS_KEY_ID,i=process.env.AWS_SECRET_ACCESS_KEY;if(!n||!i)return null;return{accessKeyId:n,secretAccessKey:i,sessionToken:process.env.AWS_SESSION_TOKEN}}function hy(n){let i=n?.profile||process.env.AWS_PROFILE||"default",s=n?.credentialsFile||Bn($n(),".aws","credentials");if(!On(s))return null;try{let o=It(s,"utf-8");return ui(o,i)}catch{return null}}function ui(n,i){let s=n.split(`
|
|
2459
2459
|
`),o=null,c,u,d;for(let p of s){let y=p.trim();if(!y||y.startsWith("#")||y.startsWith(";"))continue;let h=y.match(/^\[([^\]]+)\]$/);if(h){if(o===i&&c&&u)return{accessKeyId:c,secretAccessKey:u,sessionToken:d};o=h[1],c=void 0,u=void 0,d=void 0;continue}if(o===i){let[b,...v]=y.split("="),A=v.join("=").trim();switch(b.trim().toLowerCase()){case"aws_access_key_id":c=A;break;case"aws_secret_access_key":u=A;break;case"aws_session_token":d=A;break}}}if(o===i&&c&&u)return{accessKeyId:c,secretAccessKey:u,sessionToken:d};return null}async function Ay(n){let i=n?.timeout??1000,s="http://169.254.169.254";try{let o=await ze("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},i);if(!o.ok)return null;let c=await o.text(),u=await ze("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":c}},i);if(!u.ok)return null;let d=(await u.text()).trim(),p=await ze(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${d}`,{headers:{"X-aws-ec2-metadata-token":c}},i);if(!p.ok)return null;let y=await p.json();return{accessKeyId:y.AccessKeyId,secretAccessKey:y.SecretAccessKey,sessionToken:y.Token,expiration:new Date(y.Expiration)}}catch{return null}}async function yy(n){let i=n?.timeout??1000,s=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,o=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,c=null;if(s)c=`http://169.254.170.2${s}`;else if(o)c=o;if(!c)return null;try{let u={},d=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(d)u.Authorization=d;let p=await ze(c,{headers:u},i);if(!p.ok)return null;let y=await p.json();return{accessKeyId:y.AccessKeyId,secretAccessKey:y.SecretAccessKey,sessionToken:y.Token,expiration:new Date(y.Expiration)}}catch{return null}}async function Sy(n){let i=n?.timeout??5000,s=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,o=process.env.AWS_ROLE_ARN,c=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!s||!o)return null;try{let u=It(s,"utf-8").trim(),d=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",p=d.startsWith("us-gov")?`https://sts.${d}.amazonaws.com`:d==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${d}.amazonaws.com`,y=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:o,RoleSessionName:c,WebIdentityToken:u}),h=await ze(`${p}/?${y.toString()}`,{method:"POST"},i);if(!h.ok)return null;let b=await h.text(),v=qe(b,"AccessKeyId"),A=qe(b,"SecretAccessKey"),T=qe(b,"SessionToken"),R=qe(b,"Expiration");if(!v||!A)return null;return{accessKeyId:v,secretAccessKey:A,sessionToken:T??void 0,expiration:R?new Date(R):void 0}}catch{return null}}async function es(n){let i=fy();if(i)return i;let s=hy(n);if(s)return s;let o=await Sy(n);if(o)return o;let c=await yy(n);if(c)return c;let u=await Ay(n);if(u)return u;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 Cb(n){let i=null,s=null;return async()=>{if(i){if(!i.expiration)return i;let o=300000;if(i.expiration.getTime()-Date.now()>o)return i}if(s)return s;return s=es(n).then((o)=>(i=o,s=null,o)).catch((o)=>{throw s=null,o}),s}}async function ze(n,i,s){let o=new AbortController,c=setTimeout(()=>o.abort(),s);try{let u=await fetch(n,{...i,signal:o.signal});return clearTimeout(c),u}catch(u){throw clearTimeout(c),u}}function qe(n,i){let s=new RegExp(`<${i}>([^<]+)</${i}>`),o=n.match(s);return o?o[1]:null}async function jo(n){return es({profile:n})}function Iy(n){let i=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(i)return i;let s=Bn($n(),".aws","config");if(On(s))try{let o=It(s,"utf-8"),c=n||process.env.AWS_PROFILE||"default",u=c==="default"?"[default]":`[profile ${c}]`,d=o.split(`
|
|
2460
|
-
`),p=!1;for(let y of d){let h=y.trim();if(h.startsWith("[")){p=h===u;continue}if(p&&h.startsWith("region")){let[,b]=h.split("=");if(b)return b.trim()}}}catch{}return"us-east-1"}async function Lm(n){let i=n||await es(),s=Iy(),{signRequest:o}=await import("./chunk-ecnzvq90.js"),c=s.startsWith("us-gov")?`https://sts.${s}.amazonaws.com`:s==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${s}.amazonaws.com`,u="Action=GetCallerIdentity&Version=2011-06-15",d=o({method:"POST",url:c,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...i,service:"sts",region:s}),p=await fetch(d.url,{method:d.method,headers:d.headers,body:d.body});if(!p.ok)throw Error(`Failed to get account ID: ${await p.text()}`);let y=await p.text(),h=qe(y,"Account");if(!h)throw Error("Failed to parse account ID from response");return h}var mi=5242880,xt=5242880;var pi=5242880;class Mt{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(n={}){this.region=n.region||process.env.AWS_REGION||"us-east-1",this.endpoint=n.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=n.forcePathStyle||!1,this.credentials=n.credentials,this.credentialOptions=n.credentialOptions,this.retryOptions=n.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return es(this.credentialOptions)}buildUrl(n,i){let s=i?encodeURIComponent(i).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return i?`${this.endpoint}/${n}/${s}`:`${this.endpoint}/${n}`;let o=new URL(this.endpoint);return o.hostname=`${n}.${o.hostname}`,i?`${o.origin}/${s}`:o.origin}async get(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i),u={};if(s.range)u.Range=s.range;if(s.ifModifiedSince)u["If-Modified-Since"]=s.ifModifiedSince.toUTCString();if(s.ifMatch)u["If-Match"]=s.ifMatch;if(s.ifNoneMatch)u["If-None-Match"]=s.ifNoneMatch;let d=new URL(c);if(s.responseContentType)d.searchParams.set("response-content-type",s.responseContentType);if(s.responseContentDisposition)d.searchParams.set("response-content-disposition",s.responseContentDisposition);let p=k({method:"GET",url:d.toString(),headers:u,...o,service:"s3",region:this.region}),y=await fetch(p.url,{method:p.method,headers:p.headers});if(!y.ok&&y.status!==304){let h=await y.text();throw new V(`Failed to get object: ${h}`,y.status,n,i)}return y}async getText(n,i,s={}){return(await this.get(n,i,s)).text()}async getJSON(n,i,s={}){return(await this.get(n,i,s)).json()}async getBuffer(n,i,s={}){return(await this.get(n,i,s)).arrayBuffer()}async put(n,i,s,o={}){let c,u;if(typeof s==="string")c=new TextEncoder().encode(s).length,u=s;else if(s instanceof ArrayBuffer)c=s.byteLength,u=s;else if(s instanceof Uint8Array)c=s.byteLength,u=s;else if(s instanceof Blob)c=s.size,u=s;else return this.uploadMultipart(n,i,s,{...o,partSize:xt});if(c>pi){let d=fi(u).stream();return this.uploadMultipart(n,i,d,{...o,partSize:xt})}return this.putSimple(n,i,u,c,o)}async putSimple(n,i,s,o,c){let u=await this.getCredentials(),d=this.buildUrl(n,i),p={"Content-Length":String(o),"Content-Type":c.contentType||Fn(i)};if(c.contentEncoding)p["Content-Encoding"]=c.contentEncoding;if(c.cacheControl)p["Cache-Control"]=c.cacheControl;if(c.contentDisposition)p["Content-Disposition"]=c.contentDisposition;if(c.storageClass)p["x-amz-storage-class"]=c.storageClass;if(c.serverSideEncryption)p["x-amz-server-side-encryption"]=c.serverSideEncryption;if(c.acl)p["x-amz-acl"]=c.acl;if(c.tagging)p["x-amz-tagging"]=c.tagging;if(c.metadata)for(let[A,T]of Object.entries(c.metadata))p[`x-amz-meta-${A.toLowerCase()}`]=T;let y;if(typeof s==="string")y=s;else if(s instanceof Blob)y=await s.text();else y=new TextDecoder().decode(s instanceof ArrayBuffer?new Uint8Array(s):s);let h=k({method:"PUT",url:d,headers:p,body:y,...u,service:"s3",region:this.region}),b=await fetch(h.url,{method:h.method,headers:h.headers,body:s});if(!b.ok){let A=await b.text();throw new V(`Failed to put object: ${A}`,b.status,n,i)}return{etag:(b.headers.get("ETag")||"").replace(/"/g,"")}}async delete(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=k({method:"DELETE",url:o,...s,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers});if(!u.ok&&u.status!==204){let d=await u.text();throw new V(`Failed to delete object: ${d}`,u.status,n,i)}}async deleteMany(n,i){let s=await this.getCredentials(),o=`${this.buildUrl(n)}?delete`,u=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${i.map((R)=>`<Object><Key>${yi(R)}</Key></Object>`).join("")}</Delete>`,d=k({method:"POST",url:o,headers:{"Content-Type":"application/xml"},body:u,...s,service:"s3",region:this.region}),p=await fetch(d.url,{method:d.method,headers:d.headers,body:u});if(!p.ok){let R=await p.text();throw new V(`Failed to delete objects: ${R}`,p.status,n)}let y=await p.text(),h=[],b=[],v=/<Deleted><Key>([^<]+)<\/Key>/g,A;while((A=v.exec(y))!==null)h.push(A[1]);let T=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((A=T.exec(y))!==null)b.push({key:A[1],error:`${A[2]}: ${A[3]}`});return{deleted:h,errors:b}}async list(n,i={}){let s=await this.getCredentials(),o=new URL(this.buildUrl(n));if(o.searchParams.set("list-type","2"),i.prefix)o.searchParams.set("prefix",i.prefix);if(i.delimiter)o.searchParams.set("delimiter",i.delimiter);if(i.maxKeys)o.searchParams.set("max-keys",String(i.maxKeys));if(i.continuationToken)o.searchParams.set("continuation-token",i.continuationToken);if(i.startAfter)o.searchParams.set("start-after",i.startAfter);let c=k({method:"GET",url:o.toString(),...s,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers});if(!u.ok){let p=await u.text();throw new V(`Failed to list objects: ${p}`,u.status,n)}let d=await u.text();return gi(d)}async*listAll(n,i={}){let s;do{let o=await this.list(n,{...i,continuationToken:s});for(let c of o.contents)yield c;s=o.nextContinuationToken}while(s)}async head(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=k({method:"HEAD",url:o,...s,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers});if(u.status===404)return null;if(!u.ok){let p=await u.text();throw new V(`Failed to head object: ${p}`,u.status,n,i)}let d={};return u.headers.forEach((p,y)=>{if(y.toLowerCase().startsWith("x-amz-meta-"))d[y.slice(11)]=p}),{contentLength:Number(u.headers.get("Content-Length")||0),contentType:u.headers.get("Content-Type")||"application/octet-stream",etag:(u.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(u.headers.get("Last-Modified")||0),metadata:d,storageClass:u.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:u.headers.get("x-amz-server-side-encryption")||void 0}}async exists(n,i){return await this.head(n,i)!==null}async copy(n,i,s,o,c={}){let u=await this.getCredentials(),d=this.buildUrl(s,o),p={"x-amz-copy-source":`/${n}/${encodeURIComponent(i)}`};if(c.metadataDirective)p["x-amz-metadata-directive"]=c.metadataDirective;if(c.contentType)p["Content-Type"]=c.contentType;if(c.storageClass)p["x-amz-storage-class"]=c.storageClass;if(c.acl)p["x-amz-acl"]=c.acl;if(c.metadata)for(let[T,R]of Object.entries(c.metadata))p[`x-amz-meta-${T.toLowerCase()}`]=R;let y=k({method:"PUT",url:d,headers:p,...u,service:"s3",region:this.region}),h=await fetch(y.url,{method:y.method,headers:y.headers});if(!h.ok){let T=await h.text();throw new V(`Failed to copy object: ${T}`,h.status,s,o)}let v=(await h.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:v?v[1]:""}}async getPresignedUrl(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i);return ra({url:c,method:s.method||"GET",expiresIn:s.expiresIn||3600,...o,service:"s3",region:this.region})}async uploadMultipart(n,i,s,o={}){let c=await this.getCredentials(),u=Math.max(o.partSize||xt,mi),d,p;if(s instanceof ReadableStream)d=s;else if(s instanceof Blob)d=s.stream(),p=s.size;else{let b=new Blob([s]);d=b.stream(),p=b.size}let{uploadId:y,baseUrl:h}=await this.initiateMultipartUpload(n,i,o);try{let b=await this.uploadParts(n,i,h,y,d,u,c,p,o.concurrency||4,o.onProgress);return await this.completeMultipartUpload(n,i,h,y,b)}catch(b){throw await this.abortMultipartUpload(n,i,y,h).catch(()=>{}),b}}async initiateMultipartUpload(n,i,s){let o=await this.getCredentials(),c=this.buildUrl(n,i),u=`${c}?uploads`,d={"Content-Type":s.contentType||Fn(i)};if(s.storageClass)d["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)d["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)d["x-amz-acl"]=s.acl;if(s.metadata)for(let[A,T]of Object.entries(s.metadata))d[`x-amz-meta-${A.toLowerCase()}`]=T;let p=k({method:"POST",url:u,headers:d,...o,service:"s3",region:this.region}),y=await fetch(p.url,{method:p.method,headers:p.headers});if(!y.ok){let A=await y.text();throw new V(`Failed to initiate multipart upload: ${A}`,y.status,n,i)}let b=(await y.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!b)throw new V("Failed to parse upload ID from response",0,n,i);let v=c;if(y.url)try{let A=new URL(y.url);A.search="",v=A.toString()}catch{}return{uploadId:b[1],baseUrl:v}}async uploadParts(n,i,s,o,c,u,d,p,y,h){let b=[],v=c.getReader(),A=1,T=new Uint8Array(0),R=0,P=p?Math.ceil(p/u):void 0,I=new Map,M=async(N,O)=>{let B=`${s}?partNumber=${O}&uploadId=${encodeURIComponent(o)}`,F={"Content-Length":String(N.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},U=k({method:"PUT",url:B,headers:F,...d,service:"s3",region:this.region}),j=await fetch(U.url,{method:U.method,headers:U.headers,body:N,redirect:"error"});if(!j.ok){let z=await j.text();throw new V(`Failed to upload part ${O}: ${z}`,j.status,n,i)}let H=(j.headers.get("ETag")||"").replace(/"/g,"");if(!H)throw new V(`Missing ETag for part ${O}`,j.status,n,i);return{partNumber:O,etag:H}},L=async()=>{let N=await Promise.race(I.values());I.delete(N.partNumber),b.push(N)};while(!0){let{done:N,value:O}=await v.read();if(O){let B=new Uint8Array(T.length+O.length);B.set(T),B.set(O,T.length),T=B}while(T.length>=u||N&&T.length>0){let B=T.slice(0,u);T=T.slice(u);let F=A++;if(I.size>=y)await L();if(I.set(F,M(B,F)),R+=B.byteLength,h)h({loaded:R,total:p||R,part:F,totalParts:P||F})}if(N)break}while(I.size>0)await L();return b.sort((N,O)=>N.partNumber-O.partNumber),b}async completeMultipartUpload(n,i,s,o,c){let u=await this.getCredentials(),d=`${s}?uploadId=${encodeURIComponent(o)}`,y=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${c.map((R)=>`<Part><PartNumber>${R.partNumber}</PartNumber><ETag>"${R.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,h=k({method:"POST",url:d,headers:{"Content-Type":"application/xml"},body:y,...u,service:"s3",region:this.region}),b=await fetch(h.url,{method:h.method,headers:h.headers,body:y});if(!b.ok){let R=await b.text();throw new V(`Failed to complete multipart upload: ${R}`,b.status,n,i)}let A=(await b.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:A?A[1]:""}}async abortMultipartUpload(n,i,s,o){let c=await this.getCredentials(),u=`${o??this.buildUrl(n,i)}?uploadId=${encodeURIComponent(s)}`,d=k({method:"DELETE",url:u,...c,service:"s3",region:this.region});await fetch(d.url,{method:d.method,headers:d.headers})}async emptyAndDeleteBucket(n){let s=[];for await(let d of this.listAll(n,{}))if(s.push(d.key),s.length>=1000)await this.deleteMany(n,s),s=[];if(s.length>0)await this.deleteMany(n,s);let o=await this.getCredentials(),c=this.buildUrl(n),u=k({method:"DELETE",url:c,...o,service:"s3",region:this.region});await fetch(u.url,{method:u.method,headers:u.headers})}}class V extends Error{statusCode;bucket;key;constructor(n,i,s,o){super(n);this.statusCode=i;this.bucket=s;this.key=o;this.name="S3Error"}}function gi(n){let i=[],s=[],o=/<Contents>([\s\S]*?)<\/Contents>/g,c;while((c=o.exec(n))!==null){let d=c[1];i.push({key:ue(d,"Key")||"",lastModified:new Date(ue(d,"LastModified")||0),etag:(ue(d,"ETag")||"").replace(/"/g,""),size:Number(ue(d,"Size")||0),storageClass:ue(d,"StorageClass")||"STANDARD"})}let u=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((c=u.exec(n))!==null)s.push(c[1]);return{contents:i,commonPrefixes:s,isTruncated:ue(n,"IsTruncated")==="true",continuationToken:ue(n,"ContinuationToken")||void 0,nextContinuationToken:ue(n,"NextContinuationToken")||void 0,keyCount:Number(ue(n,"KeyCount")||0),maxKeys:Number(ue(n,"MaxKeys")||1000),prefix:ue(n,"Prefix")||void 0,delimiter:ue(n,"Delimiter")||void 0}}function ue(n,i){let s=new RegExp(`<${i}>([^<]*)</${i}>`),o=n.match(s);return o?o[1]:null}function yi(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Fn(n){let i=n.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"}[i||""]||"application/octet-stream"}function fi(n){if(n instanceof Blob)return n;if(typeof n==="string")return new Blob([n],{type:"text/plain"});return new Blob([n])}function by(n){return new Mt(n)}class tt extends Error{code;solution;details;constructor(n,i,s,o){super(n);this.code=i;this.solution=s;this.details=o;this.name="CloudError",Error.captureStackTrace?.(this,tt)}toString(){let n=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)n+=`
|
|
2460
|
+
`),p=!1;for(let y of d){let h=y.trim();if(h.startsWith("[")){p=h===u;continue}if(p&&h.startsWith("region")){let[,b]=h.split("=");if(b)return b.trim()}}}catch{}return"us-east-1"}async function Lm(n){let i=n||await es(),s=Iy(),{signRequest:o}=await import("./chunk-ecnzvq90.js"),c=s.startsWith("us-gov")?`https://sts.${s}.amazonaws.com`:s==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${s}.amazonaws.com`,u="Action=GetCallerIdentity&Version=2011-06-15",d=o({method:"POST",url:c,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...i,service:"sts",region:s}),p=await fetch(d.url,{method:d.method,headers:d.headers,body:d.body});if(!p.ok)throw Error(`Failed to get account ID: ${await p.text()}`);let y=await p.text(),h=qe(y,"Account");if(!h)throw Error("Failed to parse account ID from response");return h}var mi=5242880,Dt=5242880;var pi=5242880;class Mt{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(n={}){this.region=n.region||process.env.AWS_REGION||"us-east-1",this.endpoint=n.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=n.forcePathStyle||!1,this.credentials=n.credentials,this.credentialOptions=n.credentialOptions,this.retryOptions=n.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return es(this.credentialOptions)}buildUrl(n,i){let s=i?encodeURIComponent(i).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return i?`${this.endpoint}/${n}/${s}`:`${this.endpoint}/${n}`;let o=new URL(this.endpoint);return o.hostname=`${n}.${o.hostname}`,i?`${o.origin}/${s}`:o.origin}async get(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i),u={};if(s.range)u.Range=s.range;if(s.ifModifiedSince)u["If-Modified-Since"]=s.ifModifiedSince.toUTCString();if(s.ifMatch)u["If-Match"]=s.ifMatch;if(s.ifNoneMatch)u["If-None-Match"]=s.ifNoneMatch;let d=new URL(c);if(s.responseContentType)d.searchParams.set("response-content-type",s.responseContentType);if(s.responseContentDisposition)d.searchParams.set("response-content-disposition",s.responseContentDisposition);let p=k({method:"GET",url:d.toString(),headers:u,...o,service:"s3",region:this.region}),y=await fetch(p.url,{method:p.method,headers:p.headers});if(!y.ok&&y.status!==304){let h=await y.text();throw new V(`Failed to get object: ${h}`,y.status,n,i)}return y}async getText(n,i,s={}){return(await this.get(n,i,s)).text()}async getJSON(n,i,s={}){return(await this.get(n,i,s)).json()}async getBuffer(n,i,s={}){return(await this.get(n,i,s)).arrayBuffer()}async put(n,i,s,o={}){let c,u;if(typeof s==="string")c=new TextEncoder().encode(s).length,u=s;else if(s instanceof ArrayBuffer)c=s.byteLength,u=s;else if(s instanceof Uint8Array)c=s.byteLength,u=s;else if(s instanceof Blob)c=s.size,u=s;else return this.uploadMultipart(n,i,s,{...o,partSize:Dt});if(c>pi){let d=fi(u).stream();return this.uploadMultipart(n,i,d,{...o,partSize:Dt})}return this.putSimple(n,i,u,c,o)}async putSimple(n,i,s,o,c){let u=await this.getCredentials(),d=this.buildUrl(n,i),p={"Content-Length":String(o),"Content-Type":c.contentType||Fn(i)};if(c.contentEncoding)p["Content-Encoding"]=c.contentEncoding;if(c.cacheControl)p["Cache-Control"]=c.cacheControl;if(c.contentDisposition)p["Content-Disposition"]=c.contentDisposition;if(c.storageClass)p["x-amz-storage-class"]=c.storageClass;if(c.serverSideEncryption)p["x-amz-server-side-encryption"]=c.serverSideEncryption;if(c.acl)p["x-amz-acl"]=c.acl;if(c.tagging)p["x-amz-tagging"]=c.tagging;if(c.metadata)for(let[A,T]of Object.entries(c.metadata))p[`x-amz-meta-${A.toLowerCase()}`]=T;let y;if(typeof s==="string")y=s;else if(s instanceof Blob)y=await s.text();else y=new TextDecoder().decode(s instanceof ArrayBuffer?new Uint8Array(s):s);let h=k({method:"PUT",url:d,headers:p,body:y,...u,service:"s3",region:this.region}),b=await fetch(h.url,{method:h.method,headers:h.headers,body:s});if(!b.ok){let A=await b.text();throw new V(`Failed to put object: ${A}`,b.status,n,i)}return{etag:(b.headers.get("ETag")||"").replace(/"/g,"")}}async delete(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=k({method:"DELETE",url:o,...s,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers});if(!u.ok&&u.status!==204){let d=await u.text();throw new V(`Failed to delete object: ${d}`,u.status,n,i)}}async deleteMany(n,i){let s=await this.getCredentials(),o=`${this.buildUrl(n)}?delete`,u=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${i.map((R)=>`<Object><Key>${yi(R)}</Key></Object>`).join("")}</Delete>`,d=k({method:"POST",url:o,headers:{"Content-Type":"application/xml"},body:u,...s,service:"s3",region:this.region}),p=await fetch(d.url,{method:d.method,headers:d.headers,body:u});if(!p.ok){let R=await p.text();throw new V(`Failed to delete objects: ${R}`,p.status,n)}let y=await p.text(),h=[],b=[],v=/<Deleted><Key>([^<]+)<\/Key>/g,A;while((A=v.exec(y))!==null)h.push(A[1]);let T=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((A=T.exec(y))!==null)b.push({key:A[1],error:`${A[2]}: ${A[3]}`});return{deleted:h,errors:b}}async list(n,i={}){let s=await this.getCredentials(),o=new URL(this.buildUrl(n));if(o.searchParams.set("list-type","2"),i.prefix)o.searchParams.set("prefix",i.prefix);if(i.delimiter)o.searchParams.set("delimiter",i.delimiter);if(i.maxKeys)o.searchParams.set("max-keys",String(i.maxKeys));if(i.continuationToken)o.searchParams.set("continuation-token",i.continuationToken);if(i.startAfter)o.searchParams.set("start-after",i.startAfter);let c=k({method:"GET",url:o.toString(),...s,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers});if(!u.ok){let p=await u.text();throw new V(`Failed to list objects: ${p}`,u.status,n)}let d=await u.text();return gi(d)}async*listAll(n,i={}){let s;do{let o=await this.list(n,{...i,continuationToken:s});for(let c of o.contents)yield c;s=o.nextContinuationToken}while(s)}async head(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=k({method:"HEAD",url:o,...s,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers});if(u.status===404)return null;if(!u.ok){let p=await u.text();throw new V(`Failed to head object: ${p}`,u.status,n,i)}let d={};return u.headers.forEach((p,y)=>{if(y.toLowerCase().startsWith("x-amz-meta-"))d[y.slice(11)]=p}),{contentLength:Number(u.headers.get("Content-Length")||0),contentType:u.headers.get("Content-Type")||"application/octet-stream",etag:(u.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(u.headers.get("Last-Modified")||0),metadata:d,storageClass:u.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:u.headers.get("x-amz-server-side-encryption")||void 0}}async exists(n,i){return await this.head(n,i)!==null}async copy(n,i,s,o,c={}){let u=await this.getCredentials(),d=this.buildUrl(s,o),p={"x-amz-copy-source":`/${n}/${encodeURIComponent(i)}`};if(c.metadataDirective)p["x-amz-metadata-directive"]=c.metadataDirective;if(c.contentType)p["Content-Type"]=c.contentType;if(c.storageClass)p["x-amz-storage-class"]=c.storageClass;if(c.acl)p["x-amz-acl"]=c.acl;if(c.metadata)for(let[T,R]of Object.entries(c.metadata))p[`x-amz-meta-${T.toLowerCase()}`]=R;let y=k({method:"PUT",url:d,headers:p,...u,service:"s3",region:this.region}),h=await fetch(y.url,{method:y.method,headers:y.headers});if(!h.ok){let T=await h.text();throw new V(`Failed to copy object: ${T}`,h.status,s,o)}let v=(await h.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:v?v[1]:""}}async getPresignedUrl(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i);return ra({url:c,method:s.method||"GET",expiresIn:s.expiresIn||3600,...o,service:"s3",region:this.region})}async uploadMultipart(n,i,s,o={}){let c=await this.getCredentials(),u=Math.max(o.partSize||Dt,mi),d,p;if(s instanceof ReadableStream)d=s;else if(s instanceof Blob)d=s.stream(),p=s.size;else{let b=new Blob([s]);d=b.stream(),p=b.size}let{uploadId:y,baseUrl:h}=await this.initiateMultipartUpload(n,i,o);try{let b=await this.uploadParts(n,i,h,y,d,u,c,p,o.concurrency||4,o.onProgress);return await this.completeMultipartUpload(n,i,h,y,b)}catch(b){throw await this.abortMultipartUpload(n,i,y,h).catch(()=>{}),b}}async initiateMultipartUpload(n,i,s){let o=await this.getCredentials(),c=this.buildUrl(n,i),u=`${c}?uploads`,d={"Content-Type":s.contentType||Fn(i)};if(s.storageClass)d["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)d["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)d["x-amz-acl"]=s.acl;if(s.metadata)for(let[A,T]of Object.entries(s.metadata))d[`x-amz-meta-${A.toLowerCase()}`]=T;let p=k({method:"POST",url:u,headers:d,...o,service:"s3",region:this.region}),y=await fetch(p.url,{method:p.method,headers:p.headers});if(!y.ok){let A=await y.text();throw new V(`Failed to initiate multipart upload: ${A}`,y.status,n,i)}let b=(await y.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!b)throw new V("Failed to parse upload ID from response",0,n,i);let v=c;if(y.url)try{let A=new URL(y.url);A.search="",v=A.toString()}catch{}return{uploadId:b[1],baseUrl:v}}async uploadParts(n,i,s,o,c,u,d,p,y,h){let b=[],v=c.getReader(),A=1,T=new Uint8Array(0),R=0,P=p?Math.ceil(p/u):void 0,I=new Map,M=async(N,O)=>{let B=`${s}?partNumber=${O}&uploadId=${encodeURIComponent(o)}`,F={"Content-Length":String(N.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},U=k({method:"PUT",url:B,headers:F,...d,service:"s3",region:this.region}),j=await fetch(U.url,{method:U.method,headers:U.headers,body:N,redirect:"error"});if(!j.ok){let z=await j.text();throw new V(`Failed to upload part ${O}: ${z}`,j.status,n,i)}let H=(j.headers.get("ETag")||"").replace(/"/g,"");if(!H)throw new V(`Missing ETag for part ${O}`,j.status,n,i);return{partNumber:O,etag:H}},L=async()=>{let N=await Promise.race(I.values());I.delete(N.partNumber),b.push(N)};while(!0){let{done:N,value:O}=await v.read();if(O){let B=new Uint8Array(T.length+O.length);B.set(T),B.set(O,T.length),T=B}while(T.length>=u||N&&T.length>0){let B=T.slice(0,u);T=T.slice(u);let F=A++;if(I.size>=y)await L();if(I.set(F,M(B,F)),R+=B.byteLength,h)h({loaded:R,total:p||R,part:F,totalParts:P||F})}if(N)break}while(I.size>0)await L();return b.sort((N,O)=>N.partNumber-O.partNumber),b}async completeMultipartUpload(n,i,s,o,c){let u=await this.getCredentials(),d=`${s}?uploadId=${encodeURIComponent(o)}`,y=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${c.map((R)=>`<Part><PartNumber>${R.partNumber}</PartNumber><ETag>"${R.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,h=k({method:"POST",url:d,headers:{"Content-Type":"application/xml"},body:y,...u,service:"s3",region:this.region}),b=await fetch(h.url,{method:h.method,headers:h.headers,body:y});if(!b.ok){let R=await b.text();throw new V(`Failed to complete multipart upload: ${R}`,b.status,n,i)}let A=(await b.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:A?A[1]:""}}async abortMultipartUpload(n,i,s,o){let c=await this.getCredentials(),u=`${o??this.buildUrl(n,i)}?uploadId=${encodeURIComponent(s)}`,d=k({method:"DELETE",url:u,...c,service:"s3",region:this.region});await fetch(d.url,{method:d.method,headers:d.headers})}async emptyAndDeleteBucket(n){let s=[];for await(let d of this.listAll(n,{}))if(s.push(d.key),s.length>=1000)await this.deleteMany(n,s),s=[];if(s.length>0)await this.deleteMany(n,s);let o=await this.getCredentials(),c=this.buildUrl(n),u=k({method:"DELETE",url:c,...o,service:"s3",region:this.region});await fetch(u.url,{method:u.method,headers:u.headers})}}class V extends Error{statusCode;bucket;key;constructor(n,i,s,o){super(n);this.statusCode=i;this.bucket=s;this.key=o;this.name="S3Error"}}function gi(n){let i=[],s=[],o=/<Contents>([\s\S]*?)<\/Contents>/g,c;while((c=o.exec(n))!==null){let d=c[1];i.push({key:ue(d,"Key")||"",lastModified:new Date(ue(d,"LastModified")||0),etag:(ue(d,"ETag")||"").replace(/"/g,""),size:Number(ue(d,"Size")||0),storageClass:ue(d,"StorageClass")||"STANDARD"})}let u=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((c=u.exec(n))!==null)s.push(c[1]);return{contents:i,commonPrefixes:s,isTruncated:ue(n,"IsTruncated")==="true",continuationToken:ue(n,"ContinuationToken")||void 0,nextContinuationToken:ue(n,"NextContinuationToken")||void 0,keyCount:Number(ue(n,"KeyCount")||0),maxKeys:Number(ue(n,"MaxKeys")||1000),prefix:ue(n,"Prefix")||void 0,delimiter:ue(n,"Delimiter")||void 0}}function ue(n,i){let s=new RegExp(`<${i}>([^<]*)</${i}>`),o=n.match(s);return o?o[1]:null}function yi(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Fn(n){let i=n.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"}[i||""]||"application/octet-stream"}function fi(n){if(n instanceof Blob)return n;if(typeof n==="string")return new Blob([n],{type:"text/plain"});return new Blob([n])}function by(n){return new Mt(n)}class rt extends Error{code;solution;details;constructor(n,i,s,o){super(n);this.code=i;this.solution=s;this.details=o;this.name="CloudError",Error.captureStackTrace?.(this,rt)}toString(){let n=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)n+=`
|
|
2461
2461
|
|
|
2462
2462
|
\uD83D\uDCA1 Solution: ${this.solution}`;if(this.details&&Object.keys(this.details).length>0){n+=`
|
|
2463
2463
|
|
|
2464
2464
|
Details:`;for(let[i,s]of Object.entries(this.details))n+=`
|
|
2465
|
-
${i}: ${JSON.stringify(s)}`}return n}}class zo extends
|
|
2465
|
+
${i}: ${JSON.stringify(s)}`}return n}}class zo extends rt{constructor(n,i,s){super(n,"CONFIG_ERROR",i,s);this.name="ConfigurationError"}}class xt extends rt{constructor(n,i,s){super(n,"CREDENTIAL_ERROR",i,s);this.name="CredentialError"}}class Cy extends rt{constructor(n,i,s){super(n,"DEPLOYMENT_ERROR",i,s);this.name="DeploymentError"}}class $m extends rt{constructor(n,i,s){super(n,"VALIDATION_ERROR",i,s);this.name="ValidationError"}}class Ey extends rt{statusCode;constructor(n,i,s,o){super(n,"AWS_API_ERROR",s,o);this.statusCode=i;this.name="AWSAPIError"}}var vy={NO_CREDENTIALS:{message:"AWS credentials not found",solution:`Configure AWS credentials using one of these methods:
|
|
2466
2466
|
1. Set environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
|
2467
2467
|
2. Create ~/.aws/credentials file with your credentials
|
|
2468
2468
|
3. Use an IAM role (for EC2 instances)
|
|
2469
|
-
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 Ty(n){return vy[n]}function Mm(n,i){let s=Ty(n);return new
|
|
2470
|
-
Stack trace:`),console.error(i.stack)}}static success(n){console.log(`✔ ${n}`)}}function Eb(n){if(!n)throw Mm("MISSING_CONFIG");if(!n.project)throw new zo("Missing required field: project","Add a project configuration with name, slug, and region",{field:"project"});if(!n.project.name)throw new zo("Missing required field: project.name","Add a project name to your configuration",{field:"project.name"});if(!n.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(n.project.slug))throw new $m("Invalid project slug format","Use only lowercase letters, numbers, and hyphens",{slug:n.project.slug});if(n.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(n.project.region))throw Mm("INVALID_REGION",{region:n.project.region})}q.success("Configuration validation passed")}function vb(n){let i=[];if(n.environments?.production&&n.infrastructure?.database){let s=n.infrastructure.database;if((s.postgres||s.mysql)&&!s.postgres?.multiAZ&&!s.mysql?.multiAZ)i.push("Production database should use Multi-AZ for high availability")}if(n.infrastructure?.storage){for(let[s,o]of Object.entries(n.infrastructure.storage))if(o.encryption===!1)i.push(`Storage "${s}" is not encrypted - consider enabling encryption for security`)}if(n.infrastructure?.storage){for(let[s,o]of Object.entries(n.infrastructure.storage))if(o.public===!0)i.push(`Storage "${s}" is publicly accessible - ensure this is intentional`)}if(n.infrastructure?.database){let s=n.infrastructure.database;if(s.postgres||s.mysql){let o=s.postgres?.backupRetentionDays||s.mysql?.backupRetentionDays;if(!o||o<7)i.push("Database backup retention is less than 7 days - consider increasing for production")}}if(!n.infrastructure?.monitoring)i.push("No monitoring configured - consider adding CloudWatch alarms");return i}async function Tb(n="default"){try{q.verbose("Resolving AWS credentials...");let i=await jo(n);if(!i.accessKeyId||!i.secretAccessKey)throw new
|
|
2469
|
+
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 Ty(n){return vy[n]}function Mm(n,i){let s=Ty(n);return new rt(s.message,n,s.solution,i)}class q{static verboseMode=!1;static debugMode=!1;static setVerbose(n){this.verboseMode=n}static setDebug(n){this.debugMode=n}static verbose(n,...i){if(this.verboseMode)console.log(`[VERBOSE] ${n}`,...i)}static debug(n,...i){if(this.debugMode)console.log(`[DEBUG] ${n}`,...i)}static info(n,...i){console.log(`ℹ ${n}`,...i)}static warn(n,...i){console.warn(`⚠ ${n}`,...i)}static error(n,i){if(console.error(`✖ ${n}`),i){if(i instanceof rt)console.error(i.toString());else console.error(i.message);if(this.debugMode&&i.stack)console.error(`
|
|
2470
|
+
Stack trace:`),console.error(i.stack)}}static success(n){console.log(`✔ ${n}`)}}function Eb(n){if(!n)throw Mm("MISSING_CONFIG");if(!n.project)throw new zo("Missing required field: project","Add a project configuration with name, slug, and region",{field:"project"});if(!n.project.name)throw new zo("Missing required field: project.name","Add a project name to your configuration",{field:"project.name"});if(!n.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(n.project.slug))throw new $m("Invalid project slug format","Use only lowercase letters, numbers, and hyphens",{slug:n.project.slug});if(n.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(n.project.region))throw Mm("INVALID_REGION",{region:n.project.region})}q.success("Configuration validation passed")}function vb(n){let i=[];if(n.environments?.production&&n.infrastructure?.database){let s=n.infrastructure.database;if((s.postgres||s.mysql)&&!s.postgres?.multiAZ&&!s.mysql?.multiAZ)i.push("Production database should use Multi-AZ for high availability")}if(n.infrastructure?.storage){for(let[s,o]of Object.entries(n.infrastructure.storage))if(o.encryption===!1)i.push(`Storage "${s}" is not encrypted - consider enabling encryption for security`)}if(n.infrastructure?.storage){for(let[s,o]of Object.entries(n.infrastructure.storage))if(o.public===!0)i.push(`Storage "${s}" is publicly accessible - ensure this is intentional`)}if(n.infrastructure?.database){let s=n.infrastructure.database;if(s.postgres||s.mysql){let o=s.postgres?.backupRetentionDays||s.mysql?.backupRetentionDays;if(!o||o<7)i.push("Database backup retention is less than 7 days - consider increasing for production")}}if(!n.infrastructure?.monitoring)i.push("No monitoring configured - consider adding CloudWatch alarms");return i}async function Tb(n="default"){try{q.verbose("Resolving AWS credentials...");let i=await jo(n);if(!i.accessKeyId||!i.secretAccessKey)throw new xt("AWS credentials are incomplete","Ensure both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set");q.verbose("Credentials resolved successfully"),q.debug("Access Key ID:",i.accessKeyId.substring(0,8)+"..."),q.verbose("Testing credentials with GetCallerIdentity...");let s;try{s=await Lm(i),q.verbose("Credentials are valid"),q.debug("Account ID:",s)}catch(o){if(o instanceof Error)if(o.message.includes("InvalidClientTokenId"))throw new xt("Invalid AWS access key ID","Check that your AWS_ACCESS_KEY_ID is correct");else if(o.message.includes("SignatureDoesNotMatch"))throw new xt("Invalid AWS secret access key","Check that your AWS_SECRET_ACCESS_KEY is correct");else if(o.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: ${o.message}`,"Verify your AWS credentials are correct and have the necessary permissions");throw o}return{valid:!0,accountId:s,region:i.region}}catch(i){if(i instanceof xt)throw i;return{valid:!1,error:i instanceof Error?i.message:"Unknown error"}}}async function wb(n,i){return{allowed:i,denied:[]}}function wy(n){let i=new Set(["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate","cloudformation:ListStacks"]);if(n.infrastructure){if(n.infrastructure.storage)i.add("s3:CreateBucket"),i.add("s3:DeleteBucket"),i.add("s3:PutBucketPolicy"),i.add("s3:PutBucketVersioning"),i.add("s3:PutBucketEncryption"),i.add("s3:PutObject"),i.add("s3:GetObject");if(n.infrastructure.compute){if(n.infrastructure.compute.server)i.add("ec2:RunInstances"),i.add("ec2:TerminateInstances"),i.add("ec2:DescribeInstances"),i.add("autoscaling:CreateAutoScalingGroup"),i.add("autoscaling:UpdateAutoScalingGroup"),i.add("autoscaling:DeleteAutoScalingGroup"),i.add("elasticloadbalancing:CreateLoadBalancer"),i.add("elasticloadbalancing:DeleteLoadBalancer");if(n.infrastructure.compute.fargate)i.add("ecs:CreateCluster"),i.add("ecs:DeleteCluster"),i.add("ecs:CreateService"),i.add("ecs:UpdateService"),i.add("ecs:DeleteService"),i.add("ecs:RegisterTaskDefinition")}if(n.infrastructure.database){if(n.infrastructure.database.postgres||n.infrastructure.database.mysql)i.add("rds:CreateDBInstance"),i.add("rds:DeleteDBInstance"),i.add("rds:ModifyDBInstance"),i.add("rds:DescribeDBInstances");if(n.infrastructure.database.dynamodb)i.add("dynamodb:CreateTable"),i.add("dynamodb:DeleteTable"),i.add("dynamodb:UpdateTable"),i.add("dynamodb:DescribeTable")}if(n.infrastructure.functions)i.add("lambda:CreateFunction"),i.add("lambda:DeleteFunction"),i.add("lambda:UpdateFunctionCode"),i.add("lambda:UpdateFunctionConfiguration"),i.add("lambda:AddPermission");if(n.infrastructure.cdn)i.add("cloudfront:CreateDistribution"),i.add("cloudfront:UpdateDistribution"),i.add("cloudfront:DeleteDistribution"),i.add("cloudfront:GetDistribution");if(n.infrastructure.network)i.add("ec2:CreateVpc"),i.add("ec2:DeleteVpc"),i.add("ec2:CreateSubnet"),i.add("ec2:DeleteSubnet"),i.add("ec2:CreateInternetGateway"),i.add("ec2:DeleteInternetGateway"),i.add("ec2:CreateNatGateway"),i.add("ec2:DeleteNatGateway"),i.add("ec2:CreateRouteTable"),i.add("ec2:DeleteRouteTable"),i.add("ec2:CreateSecurityGroup"),i.add("ec2:DeleteSecurityGroup")}return i.add("iam:CreateRole"),i.add("iam:DeleteRole"),i.add("iam:AttachRolePolicy"),i.add("iam:DetachRolePolicy"),i.add("iam:PutRolePolicy"),i.add("iam:GetRole"),i.add("iam:PassRole"),Array.from(i).sort()}function Rb(n){let i=wy(n);return JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:"*"}]},null,2)}var te={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 Db(n){let i=[];if(q.verbose("Checking AWS service quotas..."),n.infrastructure?.compute?.server){let o=n.infrastructure.compute.server.autoScaling?.max||1;i.push({service:"EC2",quotaName:"Running On-Demand Instances",currentValue:o,limit:te.ec2["Running On-Demand Instances"],percentage:o/te.ec2["Running On-Demand Instances"]*100,warning:o>te.ec2["Running On-Demand Instances"]*0.8})}if(n.infrastructure?.network?.vpc)i.push({service:"EC2",quotaName:"VPCs",currentValue:1,limit:te.ec2.VPCs,percentage:1/te.ec2.VPCs*100,warning:!1});if(n.infrastructure?.database?.postgres||n.infrastructure?.database?.mysql)i.push({service:"RDS",quotaName:"DB Instances",currentValue:1,limit:te.rds["DB Instances"],percentage:1/te.rds["DB Instances"]*100,warning:!1});if(n.infrastructure?.storage){let o=Object.keys(n.infrastructure.storage).length;i.push({service:"S3",quotaName:"Buckets",currentValue:o,limit:te.s3.Buckets,percentage:o/te.s3.Buckets*100,warning:o>te.s3.Buckets*0.8})}if(n.infrastructure?.functions){let o=0;for(let c of Object.values(n.infrastructure.functions))if(Array.isArray(c))o+=c.length;i.push({service:"Lambda",quotaName:"Functions (estimated)",currentValue:o,limit:1000,percentage:o/1000*100,warning:o>800})}if(n.infrastructure?.database?.dynamodb){let o=n.infrastructure.database.dynamodb.tables?.length||0;i.push({service:"DynamoDB",quotaName:"Tables",currentValue:o,limit:te.dynamodb.Tables,percentage:o/te.dynamodb.Tables*100,warning:o>te.dynamodb.Tables*0.8})}let s=i.filter((o)=>o.warning);if(s.length>0){q.warn("Service quota warnings detected:");for(let o of s)q.warn(` ${o.service} - ${o.quotaName}: ${o.currentValue}/${o.limit} (${o.percentage.toFixed(1)}%)`)}else q.verbose("All service quotas are within limits");return i}function Pb(n){if(n.length===0)return"No quotas to check";let i=`Service Quota Usage:
|
|
2471
2471
|
|
|
2472
2472
|
`,s=n.reduce((o,c)=>{if(!o[c.service])o[c.service]=[];return o[c.service].push(c),o},{});for(let[o,c]of Object.entries(s)){i+=`${o}:
|
|
2473
2473
|
`;for(let u of c){let d=u.warning?"⚠":"✓";i+=` ${d} ${u.quotaName}: ${u.currentValue}/${u.limit} (${u.percentage.toFixed(1)}%)
|
|
@@ -3562,7 +3562,7 @@ workflows:
|
|
|
3562
3562
|
requires:
|
|
3563
3563
|
- test
|
|
3564
3564
|
${c}
|
|
3565
|
-
`}class El{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(n){this.backupVaults.set(n.name,n)}getVault(n){return this.backupVaults.get(n)}createBackupPlan(n){let i=`backup-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.backupPlans.set(i,s),s}getBackupPlan(n){return this.backupPlans.get(n)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(n){let{dbInstanceArn:i,schedule:s="0 2 * * *",retentionDays:o=7,vaultName:c="default-vault"}=n;return this.createBackupPlan({name:"RDS Daily Backup",schedule:s,retentionDays:o,vaultName:c,resources:[{resourceArn:i,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:o}})}createDynamoDBBackupPlan(n){let{tableArn:i,schedule:s="0 3 * * *",retentionDays:o=35,crossRegionCopy:c}=n;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:s,retentionDays:o,vaultName:"dynamodb-vault",resources:[{resourceArn:i,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:o},tags:c?{CrossRegionCopy:c.join(",")}:void 0})}createEFSBackupPlan(n){let{fileSystemArn:i,schedule:s="0 1 * * *",retentionDays:o=30}=n;return this.createBackupPlan({name:"EFS Daily Backup",schedule:s,retentionDays:o,vaultName:"efs-vault",resources:[{resourceArn:i,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:o}})}enableContinuousBackup(n,i=35){let s=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,o={id:s,resourceId:n,enabled:!0,retentionDays:i};return this.continuousBackups.set(s,o),o}getContinuousBackup(n){return this.continuousBackups.get(n)}enablePointInTimeRecovery(n,i){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(n){let{backupId:i,resourceType:s,targetRegion:o}=n,c={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:i,resourceType:s,status:"pending",startTime:new Date,targetRegion:o};return this.restoreJobs.set(c.id,c),setTimeout(()=>{c.status="running"},100),setTimeout(()=>{c.status="completed",c.endTime=new Date},1000),c}async restoreToPointInTime(n){let{sourceResourceArn:i,targetResourceName:s,restoreTime:o,resourceType:c}=n,u={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${o.getTime()}`,resourceType:c,status:"pending",startTime:new Date};return this.restoreJobs.set(u.id,u),console.log(`Restoring ${c} from ${i} to ${s} at ${o.toISOString()}`),setTimeout(()=>{u.status="completed",u.endTime=new Date},2000),u}getRestoreJob(n){return this.restoreJobs.get(n)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(n){let{sourceVault:i,sourceRegion:s,targetRegions:o}=n;console.log("Setting up cross-region replication:"),console.log(` Source: ${i} in ${s}`),console.log(` Targets: ${o.join(", ")}`)}generateBackupVaultCF(n){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:n.name,...n.encryptionKeyArn&&{EncryptionKeyArn:n.encryptionKeyArn},...n.accessPolicy&&{AccessPolicy:n.accessPolicy}}}}generateBackupPlanCF(n){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:n.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:n.vaultName,ScheduleExpression:`cron(${n.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:n.lifecycle?{...n.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:n.lifecycle.moveTocoldStorageAfterDays},...n.lifecycle.deleteAfterDays&&{DeleteAfterDays:n.lifecycle.deleteAfterDays}}:void 0}]},...n.tags&&{BackupPlanTags:n.tags}}}}generateBackupSelectionCF(n){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${n.id}`},BackupSelection:{SelectionName:`${n.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:n.resources.map((i)=>i.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var zy=new El;class vl{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(n){let i=`dr-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.drPlans.set(i,s),s}createRDSDRPlan(n){let{primaryDbArn:i,secondaryDbArn:s,primaryRegion:o,secondaryRegion:c,rto:u=60,rpo:d=5}=n;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:o,secondaryRegion:c,rto:u,rpo:d,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:i,secondaryArn:s,replicationEnabled:!0}],runbook:this.generateRDSRunbook(o,c),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(n){let{tableArn:i,regions:s,rto:o=15,rpo:c=1}=n;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:s[0],secondaryRegion:s[1],rto:o,rpo:c,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:i,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(s)})}generateRDSRunbook(n,i){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 "+n,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 "+i,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(n){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(n,i=!1){let s=this.drPlans.get(n);if(!s)throw Error(`DR plan not found: ${n}`);let o=Date.now(),c=0;console.log(`${i?"[DRY RUN] ":""}Executing failover for plan: ${s.name}`),console.log(`Primary: ${s.primaryRegion} -> Secondary: ${s.secondaryRegion}`),console.log(`RTO: ${s.rto} minutes, RPO: ${s.rpo} minutes`),console.log("");for(let d of s.runbook.steps){if(console.log(`Step ${d.order}: ${d.name}`),console.log(` ${d.description}`),console.log(` Action: ${d.action}`),console.log(` Estimated: ${d.estimatedDuration} minutes`),i)console.log(" [SKIPPED - DRY RUN]");else if(d.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");c++,console.log("")}return{success:!0,duration:(Date.now()-o)/1000/60,completedSteps:c}}scheduleFailoverTest(n,i){let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"scheduled",startTime:i};return this.failoverTests.set(s.id,s),s}async runFailoverTest(n){let i=this.drPlans.get(n);if(!i)throw Error(`DR plan not found: ${n}`);let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"running",startTime:new Date,results:[]};this.failoverTests.set(s.id,s),console.log(`Running failover test for plan: ${i.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let o of i.runbook.steps){let c=Date.now();console.log(`Testing step ${o.order}: ${o.name}`);let u={step:o.name,status:"success",duration:(Date.now()-c)/1000,message:`Successfully validated step ${o.order}`};s.results.push(u)}return s.status="completed",s.endTime=new Date,s}getDRPlan(n){return this.drPlans.get(n)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(n){return this.failoverTests.get(n)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(n){let i=[],s=[];if(n.rto<n.rpo)s.push("RTO cannot be less than RPO");if(n.rto>240)i.push("RTO exceeds 4 hours - consider improving recovery time");if(n.rpo>60)i.push("RPO exceeds 1 hour - consider more frequent backups");if(n.resources.length===0)s.push("No resources defined in DR plan");for(let u of n.resources){if(!u.replicationEnabled)i.push(`Resource ${u.resourceId} does not have replication enabled`);if(!u.secondaryArn&&u.resourceType!=="dynamodb")i.push(`Resource ${u.resourceId} does not have secondary resource defined`)}if(n.runbook.steps.length===0)s.push("No recovery steps defined in runbook");let o=n.runbook.steps.reduce((u,d)=>u+d.estimatedDuration,0);if(o>n.rto)i.push(`Estimated recovery duration (${o}m) exceeds RTO (${n.rto}m)`);let c=n.runbook.steps.filter((u)=>!u.automatable);if(c.length>0)i.push(`${c.length} manual steps in runbook - consider automation`);return{valid:s.length===0,warnings:i,errors:s}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var Ky=new vl;class Tl{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(n){return this.configRecorders.set(n.name,n),n}createDeliveryChannel(n){return this.deliveryChannels.set(n.name,n),n}createConfigRule(n){let i=`config-rule-${Date.now()}-${this.ruleCounter++}`,s={id:i,...n};return this.configRules.set(i,s),s}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(n=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:n},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(n){return this.createConfigRule({name:n.name,description:n.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:n.lambdaFunctionArn,scope:n.resourceTypes?{complianceResourceTypes:n.resourceTypes}:void 0,maxExecutionFrequency:n.maxExecutionFrequency,inputParameters:n.inputParameters})}createCompliancePreset(n){let i=[];switch(n){case"hipaa":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":i.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return i}getConfigRule(n){return this.configRules.get(n)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(n){return this.configRecorders.get(n)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(n){return this.deliveryChannels.get(n)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(n){let i={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:n.name,Description:n.description,Source:{Owner:n.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(n.source==="AWS_MANAGED"&&n.identifier)i.Properties.Source.SourceIdentifier=n.identifier;if(n.source==="CUSTOM_LAMBDA"&&n.lambdaFunctionArn)i.Properties.Source.SourceIdentifier=n.lambdaFunctionArn,i.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(n.inputParameters)i.Properties.InputParameters=JSON.stringify(n.inputParameters);if(n.scope){if(i.Properties.Scope={},n.scope.complianceResourceTypes)i.Properties.Scope.ComplianceResourceTypes=n.scope.complianceResourceTypes;if(n.scope.tagKey)i.Properties.Scope.TagKey=n.scope.tagKey;if(n.scope.tagValue)i.Properties.Scope.TagValue=n.scope.tagValue}if(n.maxExecutionFrequency)i.Properties.MaximumExecutionFrequency=n.maxExecutionFrequency;return i}generateConfigRecorderCF(n){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:n.name,RoleArn:n.roleArn,RecordingGroup:n.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(n){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:n.name,S3BucketName:n.s3BucketName,...n.s3KeyPrefix&&{S3KeyPrefix:n.s3KeyPrefix},...n.snsTopicArn&&{SnsTopicARN:n.snsTopicArn},...n.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:n.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var Wy=new Tl;class wl{trails=new Map;trailCounter=0;createTrail(n){let i=`trail-${Date.now()}-${this.trailCounter++}`,s={id:i,...n};return this.trails.set(i,s),s}createOrganizationTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn})}createSecurityAuditTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(n){let i=[];if(n.s3DataBuckets&&n.s3DataBuckets.length>0)i.push({type:"AWS::S3::Object",values:n.s3DataBuckets.map((s)=>`arn:aws:s3:::${s}/*`)});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)i.push({type:"AWS::Lambda::Function",values:n.lambdaFunctions});return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:i}]})}createAdvancedTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:n.selectors})}createReadOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(n){return this.trails.get(n)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(n){let i={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:n.name,S3BucketName:n.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:n.includeGlobalServiceEvents??!0,IsMultiRegionTrail:n.isMultiRegionTrail??!0,EnableLogFileValidation:n.enableLogFileValidation??!0}};if(n.s3KeyPrefix)i.Properties.S3KeyPrefix=n.s3KeyPrefix;if(n.cloudWatchLogsLogGroupArn)i.Properties.CloudWatchLogsLogGroupArn=n.cloudWatchLogsLogGroupArn;if(n.cloudWatchLogsRoleArn)i.Properties.CloudWatchLogsRoleArn=n.cloudWatchLogsRoleArn;if(n.snsTopicName)i.Properties.SnsTopicName=n.snsTopicName;if(n.kmsKeyId)i.Properties.KMSKeyId=n.kmsKeyId;if(n.eventSelectors)i.Properties.EventSelectors=n.eventSelectors.map((s)=>({ReadWriteType:s.readWriteType,IncludeManagementEvents:s.includeManagementEvents??!0,...s.dataResources&&{DataResources:s.dataResources.map((o)=>({Type:o.type,Values:o.values}))},...s.excludeManagementEventSources&&{ExcludeManagementEventSources:s.excludeManagementEventSources}}));if(n.insightSelectors)i.Properties.InsightSelectors=n.insightSelectors.map((s)=>({InsightType:s.insightType}));if(n.advancedEventSelectors)i.Properties.AdvancedEventSelectors=n.advancedEventSelectors.map((s)=>({Name:s.name,FieldSelectors:s.fieldSelectors.map((o)=>({Field:o.field,...o.equals&&{Equals:o.equals},...o.startsWith&&{StartsWith:o.startsWith},...o.endsWith&&{EndsWith:o.endsWith},...o.notEquals&&{NotEquals:o.notEquals},...o.notStartsWith&&{NotStartsWith:o.notStartsWith},...o.notEndsWith&&{NotEndsWith:o.notEndsWith}}))}));return i}generateBucketPolicy(n,i){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${n}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:i.map((s)=>`arn:aws:s3:::${n}/AWSLogs/${s}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var Jy=new wl;class Rl{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(n){let i=`detector-${Date.now()}-${this.detectorCounter++}`,s={id:i,...n};return this.detectors.set(i,s),s}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(n){let i=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,s={id:i,...n};return this.threatIntelSets.set(i,s),s}createIPSet(n){let i=`ip-set-${Date.now()}-${this.ipSetCounter++}`,s={id:i,...n};return this.ipSets.set(i,s),s}createFindingFilter(n){let i=`filter-${Date.now()}-${this.filterCounter++}`,s={id:i,...n};return this.filters.set(i,s),s}createLowSeverityArchiveFilter(n){return this.createFindingFilter({detectorId:n,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(n,i,s){return this.createFindingFilter({detectorId:n,name:`filter-finding-types-${s.toLowerCase()}`,description:`${s==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:s,rank:2,findingCriteria:{criterion:{type:{eq:i}}}})}createTrustedIPFilter(n,i){return this.createFindingFilter({detectorId:n,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:i}}}})}getDetector(n){return this.detectors.get(n)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(n){return this.threatIntelSets.get(n)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(n){return this.ipSets.get(n)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(n){return this.filters.get(n)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(n){let i={Type:"AWS::GuardDuty::Detector",Properties:{Enable:n.enable}};if(n.findingPublishingFrequency)i.Properties.FindingPublishingFrequency=n.findingPublishingFrequency;if(n.dataSources){if(i.Properties.DataSources={},n.dataSources.s3Logs)i.Properties.DataSources.S3Logs={Enable:n.dataSources.s3Logs.enable};if(n.dataSources.kubernetes)i.Properties.DataSources.Kubernetes={AuditLogs:{Enable:n.dataSources.kubernetes.auditLogs.enable}};if(n.dataSources.malwareProtection)i.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:n.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(n.features)i.Properties.Features=n.features.map((s)=>({Name:s.name,Status:s.status,...s.additionalConfiguration&&{AdditionalConfiguration:s.additionalConfiguration}}));return i}generateThreatIntelSetCF(n){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateIPSetCF(n){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateFilterCF(n){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:n.detectorId,Name:n.name,Description:n.description,Action:n.action,Rank:n.rank,FindingCriteria:{Criterion:n.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 Xy=new Rl;class mr{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(n){let i=`hub-${Date.now()}-${this.hubCounter++}`,s={id:i,...n};return this.hubs.set(i,s),s}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...mr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...mr.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...mr.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...mr.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(n){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:n.map((i)=>({value:i,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(n,i){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${n}`,description:`Automatically suppress known false positives from ${n}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:n,comparison:"EQUALS"}],title:i.map((s)=>({value:s,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(n){return this.hubs.get(n)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(n){let i={Type:"AWS::SecurityHub::Hub",Properties:{}};if(n.controlFindingGenerator)i.Properties.ControlFindingGenerator=n.controlFindingGenerator;if(n.enableDefaultStandards!==void 0)i.Properties.EnableDefaultStandards=n.enableDefaultStandards;return i}generateStandardCF(n){let i={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:n.arn}};if(n.disabledControls&&n.disabledControls.length>0)i.Properties.DisabledStandardsControls=n.disabledControls.map((s)=>({StandardsControlArn:s,Reason:"Disabled by configuration"}));return i}generateAutomationRuleCF(n){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:n.ruleName,Description:n.description,Actions:n.actions.map((i)=>({Type:i.type,FindingFieldsUpdate:i.findingFieldsUpdate})),Criteria:n.criteria,RuleStatus:n.ruleStatus,RuleOrder:n.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var Yy=new mr;class Dl{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(n){let i=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createALBDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn,switchoverTimeSeconds:0},autoPromote:n.autoPromote,healthCheckConfig:n.healthCheckConfig})}createRoute53Deployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:n.hostedZoneId,switchoverTimeSeconds:n.switchoverTimeSeconds||60}})}createECSDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,taskDefinitionArn:n.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,taskDefinitionArn:n.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn},autoRollback:n.autoRollback??!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${i?"[DRY RUN] ":""}Starting blue/green deployment: ${s.name}`),console.log(` Active environment: ${s.activeEnvironment}`),console.log(` Routing type: ${s.routingConfig.type}`);let c=s.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${c}`),console.log(`\\n1. Deploying to ${c} environment`),!i)await new Promise((u)=>setTimeout(u,100));if(console.log(`\\n2. Running health checks on ${c} environment`),s.healthCheckConfig){let u=await this.runHealthChecks(s,c,i);if(o.healthChecksPassed=u,!u){if(o.errors?.push("Health checks failed"),o.endTime=new Date,s.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),o.rolledBackAt=new Date;return this.recordDeployment(n,o),o}}else o.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${c} environment`),!i)s.activeEnvironment=c,o.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${c} environment`),!i)await new Promise((u)=>setTimeout(u,100));return o.success=!0,o.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(n,o),o}async rollback(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${i.name}`);let o=i.activeEnvironment==="blue"?"green":"blue";return i.activeEnvironment=o,s.success=!0,s.rolledBackAt=new Date,s.endTime=new Date,console.log(` Switched back to: ${o}`),this.recordDeployment(n,s),s}async runHealthChecks(n,i,s){let o=n.healthCheckConfig;if(console.log(` Health check path: ${o.path||"/"}`),console.log(` Healthy threshold: ${o.healthyThreshold}`),console.log(` Interval: ${o.interval}s`),s)return console.log(" [SKIPPED - DRY RUN]"),!0;let c=0,u=o.healthyThreshold+2;for(let d=0;d<u;d++)if(await new Promise((y)=>setTimeout(y,50)),Math.random()>0.1){if(c++,console.log(` Check ${d+1}: ✓ Healthy (${c}/${o.healthyThreshold})`),c>=o.healthyThreshold)return!0}else c=0,console.log(` Check ${d+1}: ✗ Unhealthy`);return!1}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateALBListenerCF(n){let i=n.activeEnvironment==="blue"?n.blueEnvironment:n.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:n.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:i.targetGroupArn}]}}}generateRoute53RecordSetCF(n,i){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"blue",Weight:n.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"green",Weight:n.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var Zy=new Dl;class rs{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(n){let i=`canary-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createLambdaCanaryDeployment(n){let i=n.strategy||"BALANCED",s=rs.Strategies[i].map((o)=>({...o,alarmThresholds:{errorRate:n.errorRateThreshold||1,latencyP99:n.latencyThreshold||1000}}));return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",functionVersionArn:n.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:n.canaryVersionArn,weight:0},stages:s,currentStage:0,status:"pending",autoPromote:n.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(n){let i=n.strategy||"CONSERVATIVE",s=rs.Strategies[i];return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",taskDefinitionArn:n.baselineTaskDefinitionArn,targetGroupArn:n.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:n.canaryTaskDefinitionArn,targetGroupArn:n.canaryTargetGroupArn,weight:0},stages:s,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${i?"[DRY RUN] ":""}Starting canary deployment: ${s.name}`),console.log(` Strategy: ${s.stages.length} stages`),console.log(` Auto-promote: ${s.autoPromote}`),console.log(` Auto-rollback: ${s.autoRollback}`),console.log(""),s.status="in_progress";for(let c=0;c<s.stages.length;c++){let u=s.stages[c];if(s.currentStage=c,console.log(`Stage ${c+1}/${s.stages.length}: ${u.name}`),console.log(` Traffic: ${u.trafficPercentage}% canary, ${100-u.trafficPercentage}% baseline`),console.log(` Duration: ${u.durationMinutes} minutes`),!i)s.baselineVersion.weight=100-u.trafficPercentage,s.canaryVersion.weight=u.trafficPercentage;if(!await this.monitorStage(s,u,i)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),s.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(n,i),o.rolledBack=!0,o.reason="Metrics exceeded thresholds";return o.endTime=new Date,s.status="rolled_back",this.recordDeployment(n,o),o}console.log(" ✓ Stage completed successfully"),o.completedStages++,console.log("")}return s.status="completed",o.success=!0,o.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(n,o),o}async monitorStage(n,i,s){if(console.log(" Monitoring metrics..."),s)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((c)=>setTimeout(c,100));let o={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)*i.trafficPercentage/100)};if(n.metrics=o,console.log(` Baseline: ${o.baselineErrorRate.toFixed(2)}% errors, ${o.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${o.canaryErrorRate.toFixed(2)}% errors, ${o.canaryLatencyP99.toFixed(0)}ms P99`),i.alarmThresholds){let{errorRate:c,latencyP99:u}=i.alarmThresholds;if(c&&o.canaryErrorRate>c)return console.log(` ⚠ Error rate exceeded threshold: ${o.canaryErrorRate.toFixed(2)}% > ${c}%`),!1;if(u&&o.canaryLatencyP99>u)return console.log(` ⚠ Latency P99 exceeded threshold: ${o.canaryLatencyP99.toFixed(0)}ms > ${u}ms`),!1}return!0}async rollback(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);if(console.log(`${i?"[DRY RUN] ":""}Rolling back canary deployment: ${s.name}`),!i)s.baselineVersion.weight=100,s.canaryVersion.weight=0,s.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);console.log(`Promoting canary to baseline: ${i.name}`);let s=i.baselineVersion;i.baselineVersion=i.canaryVersion,i.canaryVersion=s,i.baselineVersion.weight=100,i.canaryVersion.weight=0,i.status="completed",console.log(" Canary promoted successfully")}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateLambdaAliasCF(n,i){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:i,FunctionVersion:n.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:n.baselineVersion.version,FunctionWeight:n.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:n.baselineVersion.targetGroupArn,Weight:n.baselineVersion.weight},{TargetGroupArn:n.canaryVersion.targetGroupArn,Weight:n.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var eS=new rs;class Pl{tests=new Map;testCounter=0;createTest(n){let i=`abtest-${Date.now()}-${this.testCounter++}`,s={id:i,...n};return this.tests.set(i,s),s}createSimpleABTest(n){let i=n.variantTrafficPercentage||50;return this.createTest({name:n.name,description:n.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-i,targetGroupArn:n.controlTargetGroupArn,weight:100-i},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:i,targetGroupArn:n.variantTargetGroupArn,weight:i}],routingStrategy:{type:n.stickySession?"cookie":"random",cookieName:n.stickySession?"ab_variant":void 0,stickySession:n.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(n){let i=n.variants.reduce((s,o)=>s+o.trafficPercentage,0);if(i!==100)throw Error(`Traffic percentages must sum to 100, got ${i}`);return this.createTest({name:n.name,description:n.description,variants:n.variants.map((s,o)=>({id:`variant-${o}`,name:s.name,description:s.description,trafficPercentage:s.trafficPercentage,targetGroupArn:s.targetGroupArn,weight:s.trafficPercentage})),routingStrategy:n.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(n){return this.createTest({name:n.name,description:`Route based on ${n.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:n.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(n){return this.createTest({name:n.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${n.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(i.status!=="draft"&&i.status!=="paused")throw Error(`Cannot start test in ${i.status} status`);i.status="active",i.startTime=new Date,console.log(`Started A/B test: ${i.name}`),console.log(` Variants: ${i.variants.length}`),i.variants.forEach((s)=>{console.log(` - ${s.name}: ${s.trafficPercentage}%`)})}pauseTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);i.status="paused",console.log(`Paused A/B test: ${i.name}`)}updateTrafficSplit(n,i,s){let o=this.tests.get(n);if(!o)throw Error(`Test not found: ${n}`);let c=o.variants.find((d)=>d.id===i);if(!c)throw Error(`Variant not found: ${i}`);let u=c.trafficPercentage;c.trafficPercentage=s,c.weight=s,console.log(`Updated ${c.name} traffic: ${u}% → ${s}%`)}analyzeResults(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(!i.metrics)i.metrics=this.collectMetrics(i);let s=i.variants[0],o=0;for(let h of i.variants){let b=i.metrics.variants[h.id];if(b&&b.conversionRate>o)o=b.conversionRate,s=h}let c=i.metrics.variants.control||i.metrics.variants[i.variants[0].id],u=i.metrics.variants[s.id],d=(u.conversionRate-c.conversionRate)/c.conversionRate*100,p=100,y=u.requests>p&&c.requests>p&&Math.abs(d)>10;return{testId:n,winningVariant:s.name,confidence:y?95:75,improvement:d,statisticalSignificance:y,metrics:i.metrics,recommendation:this.generateRecommendation(d,y,s.name)}}declareWinner(n,i){let s=this.tests.get(n);if(!s)throw Error(`Test not found: ${n}`);let o=s.variants.find((c)=>c.id===i);if(!o)throw Error(`Variant not found: ${i}`);s.variants.forEach((c)=>{if(c.id===i)c.trafficPercentage=100,c.weight=100;else c.trafficPercentage=0,c.weight=0}),s.status="completed",s.endTime=new Date,s.winner=i,console.log(`Declared winner: ${o.name}`),console.log(` All traffic now routed to ${o.name}`)}collectMetrics(n){let i={},s=0;for(let o of n.variants){let c=Math.floor(Math.random()*1000)+500,u=Math.floor(c*(Math.random()*0.1+0.05)),d=u/c*100;i[o.id]={requests:c,conversions:u,conversionRate:d,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:u*(Math.random()*50+100)},s+=c}return{variants:i,totalRequests:s,startTime:n.startTime,lastUpdated:new Date}}generateRecommendation(n,i,s){if(!i)return"Continue test - sample size too small or no significant difference detected";if(n>20)return`Strong winner detected - ${s} shows ${n.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(n>10)return`Moderate improvement - ${s} shows ${n.toFixed(1)}% improvement. Consider deploying.`;if(n>0)return`Minor improvement - ${s} shows ${n.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(n){return this.tests.get(n)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:n.variants.map((i)=>({TargetGroupArn:i.targetGroupArn,Weight:i.weight})),TargetGroupStickinessConfig:{Enabled:n.routingStrategy.stickySession||!1,DurationSeconds:n.routingStrategy.sessionDuration?n.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(n){return`'use strict';
|
|
3565
|
+
`}class El{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(n){this.backupVaults.set(n.name,n)}getVault(n){return this.backupVaults.get(n)}createBackupPlan(n){let i=`backup-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.backupPlans.set(i,s),s}getBackupPlan(n){return this.backupPlans.get(n)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(n){let{dbInstanceArn:i,schedule:s="0 2 * * *",retentionDays:o=7,vaultName:c="default-vault"}=n;return this.createBackupPlan({name:"RDS Daily Backup",schedule:s,retentionDays:o,vaultName:c,resources:[{resourceArn:i,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:o}})}createDynamoDBBackupPlan(n){let{tableArn:i,schedule:s="0 3 * * *",retentionDays:o=35,crossRegionCopy:c}=n;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:s,retentionDays:o,vaultName:"dynamodb-vault",resources:[{resourceArn:i,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:o},tags:c?{CrossRegionCopy:c.join(",")}:void 0})}createEFSBackupPlan(n){let{fileSystemArn:i,schedule:s="0 1 * * *",retentionDays:o=30}=n;return this.createBackupPlan({name:"EFS Daily Backup",schedule:s,retentionDays:o,vaultName:"efs-vault",resources:[{resourceArn:i,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:o}})}enableContinuousBackup(n,i=35){let s=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,o={id:s,resourceId:n,enabled:!0,retentionDays:i};return this.continuousBackups.set(s,o),o}getContinuousBackup(n){return this.continuousBackups.get(n)}enablePointInTimeRecovery(n,i){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(n){let{backupId:i,resourceType:s,targetRegion:o}=n,c={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:i,resourceType:s,status:"pending",startTime:new Date,targetRegion:o};return this.restoreJobs.set(c.id,c),setTimeout(()=>{c.status="running"},100),setTimeout(()=>{c.status="completed",c.endTime=new Date},1000),c}async restoreToPointInTime(n){let{sourceResourceArn:i,targetResourceName:s,restoreTime:o,resourceType:c}=n,u={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${o.getTime()}`,resourceType:c,status:"pending",startTime:new Date};return this.restoreJobs.set(u.id,u),console.log(`Restoring ${c} from ${i} to ${s} at ${o.toISOString()}`),setTimeout(()=>{u.status="completed",u.endTime=new Date},2000),u}getRestoreJob(n){return this.restoreJobs.get(n)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(n){let{sourceVault:i,sourceRegion:s,targetRegions:o}=n;console.log("Setting up cross-region replication:"),console.log(` Source: ${i} in ${s}`),console.log(` Targets: ${o.join(", ")}`)}generateBackupVaultCF(n){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:n.name,...n.encryptionKeyArn&&{EncryptionKeyArn:n.encryptionKeyArn},...n.accessPolicy&&{AccessPolicy:n.accessPolicy}}}}generateBackupPlanCF(n){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:n.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:n.vaultName,ScheduleExpression:`cron(${n.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:n.lifecycle?{...n.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:n.lifecycle.moveTocoldStorageAfterDays},...n.lifecycle.deleteAfterDays&&{DeleteAfterDays:n.lifecycle.deleteAfterDays}}:void 0}]},...n.tags&&{BackupPlanTags:n.tags}}}}generateBackupSelectionCF(n){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${n.id}`},BackupSelection:{SelectionName:`${n.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:n.resources.map((i)=>i.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var zy=new El;class vl{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(n){let i=`dr-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.drPlans.set(i,s),s}createRDSDRPlan(n){let{primaryDbArn:i,secondaryDbArn:s,primaryRegion:o,secondaryRegion:c,rto:u=60,rpo:d=5}=n;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:o,secondaryRegion:c,rto:u,rpo:d,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:i,secondaryArn:s,replicationEnabled:!0}],runbook:this.generateRDSRunbook(o,c),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(n){let{tableArn:i,regions:s,rto:o=15,rpo:c=1}=n;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:s[0],secondaryRegion:s[1],rto:o,rpo:c,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:i,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(s)})}generateRDSRunbook(n,i){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 "+n,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 "+i,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(n){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(n,i=!1){let s=this.drPlans.get(n);if(!s)throw Error(`DR plan not found: ${n}`);let o=Date.now(),c=0;console.log(`${i?"[DRY RUN] ":""}Executing failover for plan: ${s.name}`),console.log(`Primary: ${s.primaryRegion} -> Secondary: ${s.secondaryRegion}`),console.log(`RTO: ${s.rto} minutes, RPO: ${s.rpo} minutes`),console.log("");for(let d of s.runbook.steps){if(console.log(`Step ${d.order}: ${d.name}`),console.log(` ${d.description}`),console.log(` Action: ${d.action}`),console.log(` Estimated: ${d.estimatedDuration} minutes`),i)console.log(" [SKIPPED - DRY RUN]");else if(d.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");c++,console.log("")}return{success:!0,duration:(Date.now()-o)/1000/60,completedSteps:c}}scheduleFailoverTest(n,i){let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"scheduled",startTime:i};return this.failoverTests.set(s.id,s),s}async runFailoverTest(n){let i=this.drPlans.get(n);if(!i)throw Error(`DR plan not found: ${n}`);let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"running",startTime:new Date,results:[]};this.failoverTests.set(s.id,s),console.log(`Running failover test for plan: ${i.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let o of i.runbook.steps){let c=Date.now();console.log(`Testing step ${o.order}: ${o.name}`);let u={step:o.name,status:"success",duration:(Date.now()-c)/1000,message:`Successfully validated step ${o.order}`};s.results.push(u)}return s.status="completed",s.endTime=new Date,s}getDRPlan(n){return this.drPlans.get(n)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(n){return this.failoverTests.get(n)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(n){let i=[],s=[];if(n.rto<n.rpo)s.push("RTO cannot be less than RPO");if(n.rto>240)i.push("RTO exceeds 4 hours - consider improving recovery time");if(n.rpo>60)i.push("RPO exceeds 1 hour - consider more frequent backups");if(n.resources.length===0)s.push("No resources defined in DR plan");for(let u of n.resources){if(!u.replicationEnabled)i.push(`Resource ${u.resourceId} does not have replication enabled`);if(!u.secondaryArn&&u.resourceType!=="dynamodb")i.push(`Resource ${u.resourceId} does not have secondary resource defined`)}if(n.runbook.steps.length===0)s.push("No recovery steps defined in runbook");let o=n.runbook.steps.reduce((u,d)=>u+d.estimatedDuration,0);if(o>n.rto)i.push(`Estimated recovery duration (${o}m) exceeds RTO (${n.rto}m)`);let c=n.runbook.steps.filter((u)=>!u.automatable);if(c.length>0)i.push(`${c.length} manual steps in runbook - consider automation`);return{valid:s.length===0,warnings:i,errors:s}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var Ky=new vl;class Tl{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(n){return this.configRecorders.set(n.name,n),n}createDeliveryChannel(n){return this.deliveryChannels.set(n.name,n),n}createConfigRule(n){let i=`config-rule-${Date.now()}-${this.ruleCounter++}`,s={id:i,...n};return this.configRules.set(i,s),s}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(n=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:n},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(n){return this.createConfigRule({name:n.name,description:n.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:n.lambdaFunctionArn,scope:n.resourceTypes?{complianceResourceTypes:n.resourceTypes}:void 0,maxExecutionFrequency:n.maxExecutionFrequency,inputParameters:n.inputParameters})}createCompliancePreset(n){let i=[];switch(n){case"hipaa":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":i.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return i}getConfigRule(n){return this.configRules.get(n)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(n){return this.configRecorders.get(n)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(n){return this.deliveryChannels.get(n)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(n){let i={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:n.name,Description:n.description,Source:{Owner:n.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(n.source==="AWS_MANAGED"&&n.identifier)i.Properties.Source.SourceIdentifier=n.identifier;if(n.source==="CUSTOM_LAMBDA"&&n.lambdaFunctionArn)i.Properties.Source.SourceIdentifier=n.lambdaFunctionArn,i.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(n.inputParameters)i.Properties.InputParameters=JSON.stringify(n.inputParameters);if(n.scope){if(i.Properties.Scope={},n.scope.complianceResourceTypes)i.Properties.Scope.ComplianceResourceTypes=n.scope.complianceResourceTypes;if(n.scope.tagKey)i.Properties.Scope.TagKey=n.scope.tagKey;if(n.scope.tagValue)i.Properties.Scope.TagValue=n.scope.tagValue}if(n.maxExecutionFrequency)i.Properties.MaximumExecutionFrequency=n.maxExecutionFrequency;return i}generateConfigRecorderCF(n){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:n.name,RoleArn:n.roleArn,RecordingGroup:n.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(n){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:n.name,S3BucketName:n.s3BucketName,...n.s3KeyPrefix&&{S3KeyPrefix:n.s3KeyPrefix},...n.snsTopicArn&&{SnsTopicARN:n.snsTopicArn},...n.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:n.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var Wy=new Tl;class wl{trails=new Map;trailCounter=0;createTrail(n){let i=`trail-${Date.now()}-${this.trailCounter++}`,s={id:i,...n};return this.trails.set(i,s),s}createOrganizationTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn})}createSecurityAuditTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(n){let i=[];if(n.s3DataBuckets&&n.s3DataBuckets.length>0)i.push({type:"AWS::S3::Object",values:n.s3DataBuckets.map((s)=>`arn:aws:s3:::${s}/*`)});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)i.push({type:"AWS::Lambda::Function",values:n.lambdaFunctions});return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:i}]})}createAdvancedTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:n.selectors})}createReadOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(n){return this.trails.get(n)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(n){let i={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:n.name,S3BucketName:n.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:n.includeGlobalServiceEvents??!0,IsMultiRegionTrail:n.isMultiRegionTrail??!0,EnableLogFileValidation:n.enableLogFileValidation??!0}};if(n.s3KeyPrefix)i.Properties.S3KeyPrefix=n.s3KeyPrefix;if(n.cloudWatchLogsLogGroupArn)i.Properties.CloudWatchLogsLogGroupArn=n.cloudWatchLogsLogGroupArn;if(n.cloudWatchLogsRoleArn)i.Properties.CloudWatchLogsRoleArn=n.cloudWatchLogsRoleArn;if(n.snsTopicName)i.Properties.SnsTopicName=n.snsTopicName;if(n.kmsKeyId)i.Properties.KMSKeyId=n.kmsKeyId;if(n.eventSelectors)i.Properties.EventSelectors=n.eventSelectors.map((s)=>({ReadWriteType:s.readWriteType,IncludeManagementEvents:s.includeManagementEvents??!0,...s.dataResources&&{DataResources:s.dataResources.map((o)=>({Type:o.type,Values:o.values}))},...s.excludeManagementEventSources&&{ExcludeManagementEventSources:s.excludeManagementEventSources}}));if(n.insightSelectors)i.Properties.InsightSelectors=n.insightSelectors.map((s)=>({InsightType:s.insightType}));if(n.advancedEventSelectors)i.Properties.AdvancedEventSelectors=n.advancedEventSelectors.map((s)=>({Name:s.name,FieldSelectors:s.fieldSelectors.map((o)=>({Field:o.field,...o.equals&&{Equals:o.equals},...o.startsWith&&{StartsWith:o.startsWith},...o.endsWith&&{EndsWith:o.endsWith},...o.notEquals&&{NotEquals:o.notEquals},...o.notStartsWith&&{NotStartsWith:o.notStartsWith},...o.notEndsWith&&{NotEndsWith:o.notEndsWith}}))}));return i}generateBucketPolicy(n,i){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${n}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:i.map((s)=>`arn:aws:s3:::${n}/AWSLogs/${s}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var Jy=new wl;class Rl{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(n){let i=`detector-${Date.now()}-${this.detectorCounter++}`,s={id:i,...n};return this.detectors.set(i,s),s}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(n){let i=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,s={id:i,...n};return this.threatIntelSets.set(i,s),s}createIPSet(n){let i=`ip-set-${Date.now()}-${this.ipSetCounter++}`,s={id:i,...n};return this.ipSets.set(i,s),s}createFindingFilter(n){let i=`filter-${Date.now()}-${this.filterCounter++}`,s={id:i,...n};return this.filters.set(i,s),s}createLowSeverityArchiveFilter(n){return this.createFindingFilter({detectorId:n,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(n,i,s){return this.createFindingFilter({detectorId:n,name:`filter-finding-types-${s.toLowerCase()}`,description:`${s==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:s,rank:2,findingCriteria:{criterion:{type:{eq:i}}}})}createTrustedIPFilter(n,i){return this.createFindingFilter({detectorId:n,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:i}}}})}getDetector(n){return this.detectors.get(n)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(n){return this.threatIntelSets.get(n)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(n){return this.ipSets.get(n)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(n){return this.filters.get(n)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(n){let i={Type:"AWS::GuardDuty::Detector",Properties:{Enable:n.enable}};if(n.findingPublishingFrequency)i.Properties.FindingPublishingFrequency=n.findingPublishingFrequency;if(n.dataSources){if(i.Properties.DataSources={},n.dataSources.s3Logs)i.Properties.DataSources.S3Logs={Enable:n.dataSources.s3Logs.enable};if(n.dataSources.kubernetes)i.Properties.DataSources.Kubernetes={AuditLogs:{Enable:n.dataSources.kubernetes.auditLogs.enable}};if(n.dataSources.malwareProtection)i.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:n.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(n.features)i.Properties.Features=n.features.map((s)=>({Name:s.name,Status:s.status,...s.additionalConfiguration&&{AdditionalConfiguration:s.additionalConfiguration}}));return i}generateThreatIntelSetCF(n){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateIPSetCF(n){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateFilterCF(n){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:n.detectorId,Name:n.name,Description:n.description,Action:n.action,Rank:n.rank,FindingCriteria:{Criterion:n.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 Xy=new Rl;class fr{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(n){let i=`hub-${Date.now()}-${this.hubCounter++}`,s={id:i,...n};return this.hubs.set(i,s),s}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...fr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...fr.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...fr.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...fr.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(n){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:n.map((i)=>({value:i,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(n,i){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${n}`,description:`Automatically suppress known false positives from ${n}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:n,comparison:"EQUALS"}],title:i.map((s)=>({value:s,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(n){return this.hubs.get(n)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(n){let i={Type:"AWS::SecurityHub::Hub",Properties:{}};if(n.controlFindingGenerator)i.Properties.ControlFindingGenerator=n.controlFindingGenerator;if(n.enableDefaultStandards!==void 0)i.Properties.EnableDefaultStandards=n.enableDefaultStandards;return i}generateStandardCF(n){let i={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:n.arn}};if(n.disabledControls&&n.disabledControls.length>0)i.Properties.DisabledStandardsControls=n.disabledControls.map((s)=>({StandardsControlArn:s,Reason:"Disabled by configuration"}));return i}generateAutomationRuleCF(n){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:n.ruleName,Description:n.description,Actions:n.actions.map((i)=>({Type:i.type,FindingFieldsUpdate:i.findingFieldsUpdate})),Criteria:n.criteria,RuleStatus:n.ruleStatus,RuleOrder:n.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var Yy=new fr;class Dl{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(n){let i=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createALBDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn,switchoverTimeSeconds:0},autoPromote:n.autoPromote,healthCheckConfig:n.healthCheckConfig})}createRoute53Deployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:n.hostedZoneId,switchoverTimeSeconds:n.switchoverTimeSeconds||60}})}createECSDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,taskDefinitionArn:n.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,taskDefinitionArn:n.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn},autoRollback:n.autoRollback??!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${i?"[DRY RUN] ":""}Starting blue/green deployment: ${s.name}`),console.log(` Active environment: ${s.activeEnvironment}`),console.log(` Routing type: ${s.routingConfig.type}`);let c=s.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${c}`),console.log(`\\n1. Deploying to ${c} environment`),!i)await new Promise((u)=>setTimeout(u,100));if(console.log(`\\n2. Running health checks on ${c} environment`),s.healthCheckConfig){let u=await this.runHealthChecks(s,c,i);if(o.healthChecksPassed=u,!u){if(o.errors?.push("Health checks failed"),o.endTime=new Date,s.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),o.rolledBackAt=new Date;return this.recordDeployment(n,o),o}}else o.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${c} environment`),!i)s.activeEnvironment=c,o.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${c} environment`),!i)await new Promise((u)=>setTimeout(u,100));return o.success=!0,o.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(n,o),o}async rollback(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${i.name}`);let o=i.activeEnvironment==="blue"?"green":"blue";return i.activeEnvironment=o,s.success=!0,s.rolledBackAt=new Date,s.endTime=new Date,console.log(` Switched back to: ${o}`),this.recordDeployment(n,s),s}async runHealthChecks(n,i,s){let o=n.healthCheckConfig;if(console.log(` Health check path: ${o.path||"/"}`),console.log(` Healthy threshold: ${o.healthyThreshold}`),console.log(` Interval: ${o.interval}s`),s)return console.log(" [SKIPPED - DRY RUN]"),!0;let c=0,u=o.healthyThreshold+2;for(let d=0;d<u;d++)if(await new Promise((y)=>setTimeout(y,50)),Math.random()>0.1){if(c++,console.log(` Check ${d+1}: ✓ Healthy (${c}/${o.healthyThreshold})`),c>=o.healthyThreshold)return!0}else c=0,console.log(` Check ${d+1}: ✗ Unhealthy`);return!1}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateALBListenerCF(n){let i=n.activeEnvironment==="blue"?n.blueEnvironment:n.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:n.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:i.targetGroupArn}]}}}generateRoute53RecordSetCF(n,i){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"blue",Weight:n.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"green",Weight:n.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var Zy=new Dl;class rs{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(n){let i=`canary-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createLambdaCanaryDeployment(n){let i=n.strategy||"BALANCED",s=rs.Strategies[i].map((o)=>({...o,alarmThresholds:{errorRate:n.errorRateThreshold||1,latencyP99:n.latencyThreshold||1000}}));return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",functionVersionArn:n.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:n.canaryVersionArn,weight:0},stages:s,currentStage:0,status:"pending",autoPromote:n.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(n){let i=n.strategy||"CONSERVATIVE",s=rs.Strategies[i];return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",taskDefinitionArn:n.baselineTaskDefinitionArn,targetGroupArn:n.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:n.canaryTaskDefinitionArn,targetGroupArn:n.canaryTargetGroupArn,weight:0},stages:s,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${i?"[DRY RUN] ":""}Starting canary deployment: ${s.name}`),console.log(` Strategy: ${s.stages.length} stages`),console.log(` Auto-promote: ${s.autoPromote}`),console.log(` Auto-rollback: ${s.autoRollback}`),console.log(""),s.status="in_progress";for(let c=0;c<s.stages.length;c++){let u=s.stages[c];if(s.currentStage=c,console.log(`Stage ${c+1}/${s.stages.length}: ${u.name}`),console.log(` Traffic: ${u.trafficPercentage}% canary, ${100-u.trafficPercentage}% baseline`),console.log(` Duration: ${u.durationMinutes} minutes`),!i)s.baselineVersion.weight=100-u.trafficPercentage,s.canaryVersion.weight=u.trafficPercentage;if(!await this.monitorStage(s,u,i)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),s.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(n,i),o.rolledBack=!0,o.reason="Metrics exceeded thresholds";return o.endTime=new Date,s.status="rolled_back",this.recordDeployment(n,o),o}console.log(" ✓ Stage completed successfully"),o.completedStages++,console.log("")}return s.status="completed",o.success=!0,o.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(n,o),o}async monitorStage(n,i,s){if(console.log(" Monitoring metrics..."),s)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((c)=>setTimeout(c,100));let o={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)*i.trafficPercentage/100)};if(n.metrics=o,console.log(` Baseline: ${o.baselineErrorRate.toFixed(2)}% errors, ${o.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${o.canaryErrorRate.toFixed(2)}% errors, ${o.canaryLatencyP99.toFixed(0)}ms P99`),i.alarmThresholds){let{errorRate:c,latencyP99:u}=i.alarmThresholds;if(c&&o.canaryErrorRate>c)return console.log(` ⚠ Error rate exceeded threshold: ${o.canaryErrorRate.toFixed(2)}% > ${c}%`),!1;if(u&&o.canaryLatencyP99>u)return console.log(` ⚠ Latency P99 exceeded threshold: ${o.canaryLatencyP99.toFixed(0)}ms > ${u}ms`),!1}return!0}async rollback(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);if(console.log(`${i?"[DRY RUN] ":""}Rolling back canary deployment: ${s.name}`),!i)s.baselineVersion.weight=100,s.canaryVersion.weight=0,s.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);console.log(`Promoting canary to baseline: ${i.name}`);let s=i.baselineVersion;i.baselineVersion=i.canaryVersion,i.canaryVersion=s,i.baselineVersion.weight=100,i.canaryVersion.weight=0,i.status="completed",console.log(" Canary promoted successfully")}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateLambdaAliasCF(n,i){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:i,FunctionVersion:n.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:n.baselineVersion.version,FunctionWeight:n.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:n.baselineVersion.targetGroupArn,Weight:n.baselineVersion.weight},{TargetGroupArn:n.canaryVersion.targetGroupArn,Weight:n.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var eS=new rs;class Pl{tests=new Map;testCounter=0;createTest(n){let i=`abtest-${Date.now()}-${this.testCounter++}`,s={id:i,...n};return this.tests.set(i,s),s}createSimpleABTest(n){let i=n.variantTrafficPercentage||50;return this.createTest({name:n.name,description:n.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-i,targetGroupArn:n.controlTargetGroupArn,weight:100-i},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:i,targetGroupArn:n.variantTargetGroupArn,weight:i}],routingStrategy:{type:n.stickySession?"cookie":"random",cookieName:n.stickySession?"ab_variant":void 0,stickySession:n.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(n){let i=n.variants.reduce((s,o)=>s+o.trafficPercentage,0);if(i!==100)throw Error(`Traffic percentages must sum to 100, got ${i}`);return this.createTest({name:n.name,description:n.description,variants:n.variants.map((s,o)=>({id:`variant-${o}`,name:s.name,description:s.description,trafficPercentage:s.trafficPercentage,targetGroupArn:s.targetGroupArn,weight:s.trafficPercentage})),routingStrategy:n.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(n){return this.createTest({name:n.name,description:`Route based on ${n.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:n.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(n){return this.createTest({name:n.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${n.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(i.status!=="draft"&&i.status!=="paused")throw Error(`Cannot start test in ${i.status} status`);i.status="active",i.startTime=new Date,console.log(`Started A/B test: ${i.name}`),console.log(` Variants: ${i.variants.length}`),i.variants.forEach((s)=>{console.log(` - ${s.name}: ${s.trafficPercentage}%`)})}pauseTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);i.status="paused",console.log(`Paused A/B test: ${i.name}`)}updateTrafficSplit(n,i,s){let o=this.tests.get(n);if(!o)throw Error(`Test not found: ${n}`);let c=o.variants.find((d)=>d.id===i);if(!c)throw Error(`Variant not found: ${i}`);let u=c.trafficPercentage;c.trafficPercentage=s,c.weight=s,console.log(`Updated ${c.name} traffic: ${u}% → ${s}%`)}analyzeResults(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(!i.metrics)i.metrics=this.collectMetrics(i);let s=i.variants[0],o=0;for(let h of i.variants){let b=i.metrics.variants[h.id];if(b&&b.conversionRate>o)o=b.conversionRate,s=h}let c=i.metrics.variants.control||i.metrics.variants[i.variants[0].id],u=i.metrics.variants[s.id],d=(u.conversionRate-c.conversionRate)/c.conversionRate*100,p=100,y=u.requests>p&&c.requests>p&&Math.abs(d)>10;return{testId:n,winningVariant:s.name,confidence:y?95:75,improvement:d,statisticalSignificance:y,metrics:i.metrics,recommendation:this.generateRecommendation(d,y,s.name)}}declareWinner(n,i){let s=this.tests.get(n);if(!s)throw Error(`Test not found: ${n}`);let o=s.variants.find((c)=>c.id===i);if(!o)throw Error(`Variant not found: ${i}`);s.variants.forEach((c)=>{if(c.id===i)c.trafficPercentage=100,c.weight=100;else c.trafficPercentage=0,c.weight=0}),s.status="completed",s.endTime=new Date,s.winner=i,console.log(`Declared winner: ${o.name}`),console.log(` All traffic now routed to ${o.name}`)}collectMetrics(n){let i={},s=0;for(let o of n.variants){let c=Math.floor(Math.random()*1000)+500,u=Math.floor(c*(Math.random()*0.1+0.05)),d=u/c*100;i[o.id]={requests:c,conversions:u,conversionRate:d,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:u*(Math.random()*50+100)},s+=c}return{variants:i,totalRequests:s,startTime:n.startTime,lastUpdated:new Date}}generateRecommendation(n,i,s){if(!i)return"Continue test - sample size too small or no significant difference detected";if(n>20)return`Strong winner detected - ${s} shows ${n.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(n>10)return`Moderate improvement - ${s} shows ${n.toFixed(1)}% improvement. Consider deploying.`;if(n>0)return`Minor improvement - ${s} shows ${n.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(n){return this.tests.get(n)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:n.variants.map((i)=>({TargetGroupArn:i.targetGroupArn,Weight:i.weight})),TargetGroupStickinessConfig:{Enabled:n.routingStrategy.stickySession||!1,DurationSeconds:n.routingStrategy.sessionDuration?n.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(n){return`'use strict';
|
|
3566
3566
|
|
|
3567
3567
|
exports.handler = (event, _context, _callback) => {
|
|
3568
3568
|
const request = event.Records[0].cf.request;
|
|
@@ -3619,7 +3619,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3619
3619
|
| filter @message like /ERROR/
|
|
3620
3620
|
| stats count() as error_count by @message
|
|
3621
3621
|
| sort error_count desc
|
|
3622
|
-
| limit 20`,logGroupNames:n})}getLogGroup(n){return this.logGroups.get(n)}listLogGroups(){return Array.from(this.logGroups.values())}getInsightsQuery(n){return this.insightsQueries.get(n)}listInsightsQueries(){return Array.from(this.insightsQueries.values())}generateLogGroupCF(n){return{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:n.name,...n.retentionDays&&{RetentionInDays:n.retentionDays},...n.kmsKeyId&&{KmsKeyId:n.kmsKeyId}}}}generateMetricFilterCF(n,i){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:i.name,FilterPattern:i.filterPattern,LogGroupName:n.name,MetricTransformations:i.metricTransformations.map((s)=>({MetricName:s.metricName,MetricNamespace:s.metricNamespace,MetricValue:s.metricValue,...s.defaultValue!==void 0&&{DefaultValue:s.defaultValue},...s.unit&&{Unit:s.unit},...s.dimensions&&{Dimensions:s.dimensions}}))}}}generateSubscriptionFilterCF(n){return{Type:"AWS::Logs::SubscriptionFilter",Properties:{FilterName:n.name,FilterPattern:n.filterPattern,LogGroupName:n.logGroupName,DestinationArn:n.destinationArn,...n.roleArn&&{RoleArn:n.roleArn},...n.distribution&&{Distribution:n.distribution}}}}generateQueryDefinitionCF(n){return{Type:"AWS::Logs::QueryDefinition",Properties:{Name:n.name,QueryString:n.query,LogGroupNames:n.logGroupNames}}}createLogAggregation(n,i,s=7){let o=`aggregation-${Date.now()}-${this.logGroupCounter++}`,c=this.createLogGroup({name:n,retentionDays:s});return i.forEach((u)=>{this.createMetricFilter(c.id,{name:u.metric,filterPattern:u.pattern,metricTransformations:[{metricName:u.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:o,logGroup:n,filters:i,retention:s}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var nS=new Nl;class
|
|
3622
|
+
| limit 20`,logGroupNames:n})}getLogGroup(n){return this.logGroups.get(n)}listLogGroups(){return Array.from(this.logGroups.values())}getInsightsQuery(n){return this.insightsQueries.get(n)}listInsightsQueries(){return Array.from(this.insightsQueries.values())}generateLogGroupCF(n){return{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:n.name,...n.retentionDays&&{RetentionInDays:n.retentionDays},...n.kmsKeyId&&{KmsKeyId:n.kmsKeyId}}}}generateMetricFilterCF(n,i){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:i.name,FilterPattern:i.filterPattern,LogGroupName:n.name,MetricTransformations:i.metricTransformations.map((s)=>({MetricName:s.metricName,MetricNamespace:s.metricNamespace,MetricValue:s.metricValue,...s.defaultValue!==void 0&&{DefaultValue:s.defaultValue},...s.unit&&{Unit:s.unit},...s.dimensions&&{Dimensions:s.dimensions}}))}}}generateSubscriptionFilterCF(n){return{Type:"AWS::Logs::SubscriptionFilter",Properties:{FilterName:n.name,FilterPattern:n.filterPattern,LogGroupName:n.logGroupName,DestinationArn:n.destinationArn,...n.roleArn&&{RoleArn:n.roleArn},...n.distribution&&{Distribution:n.distribution}}}}generateQueryDefinitionCF(n){return{Type:"AWS::Logs::QueryDefinition",Properties:{Name:n.name,QueryString:n.query,LogGroupNames:n.logGroupNames}}}createLogAggregation(n,i,s=7){let o=`aggregation-${Date.now()}-${this.logGroupCounter++}`,c=this.createLogGroup({name:n,retentionDays:s});return i.forEach((u)=>{this.createMetricFilter(c.id,{name:u.metric,filterPattern:u.pattern,metricTransformations:[{metricName:u.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:o,logGroup:n,filters:i,retention:s}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var nS=new Nl;class hr{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(n){let i=`canary-${Date.now()}-${this.canaryCounter++}`,s={id:i,...n};return this.canaries.set(i,s),s}createHeartbeatCanary(n){let i=`
|
|
3623
3623
|
const synthetics = require('Synthetics');
|
|
3624
3624
|
const log = require('SyntheticsLogger');
|
|
3625
3625
|
|
|
@@ -3639,7 +3639,7 @@ const heartbeat = async function () {
|
|
|
3639
3639
|
exports.handler = async () => {
|
|
3640
3640
|
return await heartbeat();
|
|
3641
3641
|
};
|
|
3642
|
-
`;return this.createCanary({name:n.name,description:`Heartbeat monitor for ${n.url}`,runtimeVersion:
|
|
3642
|
+
`;return this.createCanary({name:n.name,description:`Heartbeat monitor for ${n.url}`,runtimeVersion:hr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:i},schedule:{expression:`rate(${n.interval} minutes)`},runConfig:{timeoutInSeconds:60,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${n.s3Bucket}/canary-artifacts/${n.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createAPICanary(n){let s=`
|
|
3643
3643
|
const synthetics = require('Synthetics');
|
|
3644
3644
|
const log = require('SyntheticsLogger');
|
|
3645
3645
|
|
|
@@ -3668,7 +3668,7 @@ const apiCheck = async function () {
|
|
|
3668
3668
|
exports.handler = async () => {
|
|
3669
3669
|
return await apiCheck();
|
|
3670
3670
|
};
|
|
3671
|
-
`;return this.createCanary({name:n.name,description:`API monitor for ${n.baseUrl}`,runtimeVersion:
|
|
3671
|
+
`;return this.createCanary({name:n.name,description:`API monitor for ${n.baseUrl}`,runtimeVersion:hr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:s},schedule:{expression:`rate(${n.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${n.s3Bucket}/canary-artifacts/${n.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createVisualRegressionCanary(n){let i=`
|
|
3672
3672
|
const synthetics = require('Synthetics');
|
|
3673
3673
|
const log = require('SyntheticsLogger');
|
|
3674
3674
|
|
|
@@ -3688,7 +3688,7 @@ const visualCheck = async function () {
|
|
|
3688
3688
|
exports.handler = async () => {
|
|
3689
3689
|
return await visualCheck();
|
|
3690
3690
|
};
|
|
3691
|
-
`;return this.createCanary({name:n.name,description:`Visual regression monitor for ${n.url}`,runtimeVersion:
|
|
3691
|
+
`;return this.createCanary({name:n.name,description:`Visual regression monitor for ${n.url}`,runtimeVersion:hr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:i},schedule:{expression:`rate(${n.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${n.s3Bucket}/canary-artifacts/${n.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createWorkflowCanary(n){let s=`
|
|
3692
3692
|
const synthetics = require('Synthetics');
|
|
3693
3693
|
const log = require('SyntheticsLogger');
|
|
3694
3694
|
|
|
@@ -3710,7 +3710,7 @@ const workflowCheck = async function () {
|
|
|
3710
3710
|
exports.handler = async () => {
|
|
3711
3711
|
return await workflowCheck();
|
|
3712
3712
|
};
|
|
3713
|
-
`;return this.createCanary({name:n.name,description:n.description,runtimeVersion:
|
|
3713
|
+
`;return this.createCanary({name:n.name,description:n.description,runtimeVersion:hr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:s},schedule:{expression:`rate(${n.interval} minutes)`},runConfig:{timeoutInSeconds:180,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${n.s3Bucket}/canary-artifacts/${n.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}generateActionScript(n){switch(n.type){case"click":return`await page.click('${n.selector}');`;case"type":return`await page.type('${n.selector}', '${n.value}');`;case"wait":return`await page.waitForTimeout(${n.duration});`;case"waitForSelector":return`await page.waitForSelector('${n.selector}');`;default:return""}}createAlarm(n,i){let s=this.canaries.get(n);if(!s)throw Error(`Canary not found: ${n}`);let c={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...i};if(!s.alarms)s.alarms=[];return s.alarms.push(c),c}getCanary(n){return this.canaries.get(n)}listCanaries(){return Array.from(this.canaries.values())}generateCanaryCF(n){let i={Type:"AWS::Synthetics::Canary",Properties:{Name:n.name,RuntimeVersion:n.runtimeVersion,ExecutionRoleArn:{"Fn::GetAtt":["CanaryExecutionRole","Arn"]},Schedule:{Expression:n.schedule.expression,...n.schedule.durationInSeconds&&{DurationInSeconds:n.schedule.durationInSeconds}},ArtifactS3Location:n.artifactS3Location,StartCanaryAfterCreation:!0}};if(n.code.type==="script")i.Properties.Code={Handler:n.handler,Script:n.code.script};else i.Properties.Code={Handler:n.handler,S3Bucket:n.code.s3Bucket,S3Key:n.code.s3Key,...n.code.s3Version&&{S3ObjectVersion:n.code.s3Version}};if(n.runConfig)i.Properties.RunConfig={TimeoutInSeconds:n.runConfig.timeoutInSeconds,MemoryInMB:n.runConfig.memoryInMB,...n.runConfig.environmentVariables&&{EnvironmentVariables:n.runConfig.environmentVariables},...n.runConfig.activeTracing!==void 0&&{ActiveTracing:n.runConfig.activeTracing}};if(n.vpcConfig)i.Properties.VPCConfig={SubnetIds:n.vpcConfig.subnetIds,SecurityGroupIds:n.vpcConfig.securityGroupIds};if(n.successRetentionPeriod)i.Properties.SuccessRetentionPeriod=n.successRetentionPeriod;if(n.failureRetentionPeriod)i.Properties.FailureRetentionPeriod=n.failureRetentionPeriod;return i}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 iS=new hr;class tf{plans=new Map;migrations=new Map;planCounter=0;migrationCounter=0;createPlan(n){let i=`migration-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.plans.set(i,s),s}createMigration(n){let i=`migration-${Date.now()}-${this.migrationCounter++}`,s=this.generateChecksum(n.up+n.down),o={id:i,checksum:s,...n};return this.migrations.set(i,o),o}createSchemaMigration(n){let{up:i,down:s}=this.generateSchemaSQL(n.changes,n.tableName,n.engine);return this.createMigration({version:n.version,name:n.name,description:`Schema changes for ${n.tableName}`,up:i,down:s})}createDataMigration(n){return this.createMigration({version:n.version,name:n.name,description:n.description,up:n.upSQL,down:n.downSQL})}addMigrationToPlan(n,i){let s=this.plans.get(n);if(!s)throw Error(`Migration plan not found: ${n}`);s.migrations.push(i)}async executePlan(n,i=!1){let s=this.plans.get(n);if(!s)throw Error(`Migration plan not found: ${n}`);let o=Date.now(),c=[],u=[];if(console.log(`${i?"[DRY RUN] ":""}Executing migration plan: ${s.name}`),console.log(`Database: ${s.database.type} - ${s.database.identifier}`),console.log(`Migrations to apply: ${s.migrations.length}
|
|
3714
3714
|
`),s.backupBeforeMigration&&!i)console.log("Creating database backup before migration...");for(let p of s.migrations)try{if(console.log(`Applying migration: ${p.version} - ${p.name}`),!i){if(this.generateChecksum(p.up+p.down)!==p.checksum)throw Error("Migration checksum mismatch - migration has been modified");let h=Date.now();p.appliedAt=new Date,p.executionTimeMs=Date.now()-h,console.log(`✓ Applied in ${p.executionTimeMs}ms
|
|
3715
3715
|
`)}else console.log(`[SKIPPED - DRY RUN]
|
|
3716
3716
|
`);c.push(p.version)}catch(y){if(console.error(`✗ Failed: ${y instanceof Error?y.message:String(y)}
|
|
@@ -4127,7 +4127,7 @@ else {
|
|
|
4127
4127
|
|
|
4128
4128
|
return raw;
|
|
4129
4129
|
}
|
|
4130
|
-
`;static createSchedulerLambda(n){return{[`${n.slug}EmailSchedulerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:Wt.SchedulerLambdaCode},Environment:{Variables:{EMAIL_BUCKET:n.emailBucket}}}}}}static createSchedulerRule(n){return{[`${n.slug}EmailSchedulerRule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${n.slug}-email-scheduler`,Description:"Trigger email scheduler every minute",ScheduleExpression:n.scheduleExpression||"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:n.lambdaArn}]}},[`${n.slug}EmailSchedulerPermission`]:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:n.lambdaArn,Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:{"Fn::GetAtt":[`${n.slug}EmailSchedulerRule`,"Arn"]}}}}}static async scheduleEmail(n){let{s3Client:i,bucket:s,email:o,scheduledFor:c,timezone:u}=n,d=`sched-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,p={id:d,email:o,scheduledFor:typeof c==="string"?c:c.toISOString(),timezone:u,status:"pending",createdAt:new Date().toISOString()};return await i.send({Bucket:s,Key:`scheduled/${d}.json`,Body:JSON.stringify(p,null,2),ContentType:"application/json"}),p}static async cancelScheduledEmail(n){let{s3Client:i,bucket:s,id:o}=n;try{let c=await i.send({Bucket:s,Key:`scheduled/${o}.json`}),u=JSON.parse(c.Body);if(u.status!=="pending")return!1;return u.status="cancelled",await i.send({Bucket:s,Key:`scheduled/${o}.json`,Body:JSON.stringify(u,null,2),ContentType:"application/json"}),!0}catch{return!1}}static async listScheduledEmails(n){let{s3Client:i,bucket:s,status:o}=n,c=await i.send({Bucket:s,Prefix:"scheduled/"}),u=[];for(let d of c.Contents||[]){if(!d.Key.endsWith(".json"))continue;try{let p=await i.send({Bucket:s,Key:d.Key}),y=JSON.parse(p.Body);if(!o||y.status===o)u.push(y)}catch{}}return u.sort((d,p)=>new Date(d.scheduledFor).getTime()-new Date(p.scheduledFor).getTime()),u}}class
|
|
4130
|
+
`;static createSchedulerLambda(n){return{[`${n.slug}EmailSchedulerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:Wt.SchedulerLambdaCode},Environment:{Variables:{EMAIL_BUCKET:n.emailBucket}}}}}}static createSchedulerRule(n){return{[`${n.slug}EmailSchedulerRule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${n.slug}-email-scheduler`,Description:"Trigger email scheduler every minute",ScheduleExpression:n.scheduleExpression||"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:n.lambdaArn}]}},[`${n.slug}EmailSchedulerPermission`]:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:n.lambdaArn,Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:{"Fn::GetAtt":[`${n.slug}EmailSchedulerRule`,"Arn"]}}}}}static async scheduleEmail(n){let{s3Client:i,bucket:s,email:o,scheduledFor:c,timezone:u}=n,d=`sched-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,p={id:d,email:o,scheduledFor:typeof c==="string"?c:c.toISOString(),timezone:u,status:"pending",createdAt:new Date().toISOString()};return await i.send({Bucket:s,Key:`scheduled/${d}.json`,Body:JSON.stringify(p,null,2),ContentType:"application/json"}),p}static async cancelScheduledEmail(n){let{s3Client:i,bucket:s,id:o}=n;try{let c=await i.send({Bucket:s,Key:`scheduled/${o}.json`}),u=JSON.parse(c.Body);if(u.status!=="pending")return!1;return u.status="cancelled",await i.send({Bucket:s,Key:`scheduled/${o}.json`,Body:JSON.stringify(u,null,2),ContentType:"application/json"}),!0}catch{return!1}}static async listScheduledEmails(n){let{s3Client:i,bucket:s,status:o}=n,c=await i.send({Bucket:s,Prefix:"scheduled/"}),u=[];for(let d of c.Contents||[]){if(!d.Key.endsWith(".json"))continue;try{let p=await i.send({Bucket:s,Key:d.Key}),y=JSON.parse(p.Body);if(!o||y.status===o)u.push(y)}catch{}}return u.sort((d,p)=>new Date(d.scheduledFor).getTime()-new Date(p.scheduledFor).getTime()),u}}class Xe{static TrackingPixelLambdaCode=`
|
|
4131
4131
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
4132
4132
|
|
|
4133
4133
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -4330,7 +4330,7 @@ catch (error) {
|
|
|
4330
4330
|
|
|
4331
4331
|
return { statusCode: 200 };
|
|
4332
4332
|
};
|
|
4333
|
-
`;static createAnalyticsTable(n){return{[`${n.slug}EmailAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createTrackingPixelLambda(n){return{[`${n.slug}TrackingPixelLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-tracking-pixel`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:
|
|
4333
|
+
`;static createAnalyticsTable(n){return{[`${n.slug}EmailAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createTrackingPixelLambda(n){return{[`${n.slug}TrackingPixelLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-tracking-pixel`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:Xe.TrackingPixelLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:n.analyticsTable}}}}}}static createClickTrackingLambda(n){return{[`${n.slug}ClickTrackingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-click-tracking`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:Xe.ClickTrackingLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:n.analyticsTable}}}}}}static createSesEventProcessorLambda(n){return{[`${n.slug}SesEventProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-ses-event-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Xe.SesEventProcessorCode},Environment:{Variables:{ANALYTICS_TABLE:n.analyticsTable}}}}}}static injectTracking(n){let{html:i,messageId:s,trackingDomain:o}=n,c=`<img src="https://${o}/track/open/${s}" width="1" height="1" style="display:none" alt="" />`,u=i.replace("</body>",`${c}</body>`);return u=u.replace(/href="(https?:\/\/[^"]+)"/g,(d,p)=>{let y=encodeURIComponent(p);return`href="https://${o}/track/click/${s}?url=${y}"`}),u}static calculateMetrics(n){let i=n.filter((y)=>y.sent).length,s=n.filter((y)=>y.delivered).length,o=n.filter((y)=>y.opened).length,c=n.filter((y)=>y.clicked).length,u=n.filter((y)=>y.bounced).length,d=n.filter((y)=>y.complained).length,p=n.filter((y)=>y.unsubscribed).length;return{period:new Date().toISOString(),sent:i,delivered:s,opened:o,clicked:c,bounced:u,complained:d,unsubscribed:p,deliveryRate:i>0?s/i*100:0,openRate:s>0?o/s*100:0,clickRate:o>0?c/o*100:0,bounceRate:i>0?u/i*100:0,complaintRate:s>0?d/s*100:0}}}class ke{static TemplateRendererCode=`
|
|
4334
4334
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
4335
4335
|
|
|
4336
4336
|
const s3 = new S3Client({});
|
|
@@ -7226,7 +7226,7 @@ function unmarshallTest(item) {
|
|
|
7226
7226
|
|
|
7227
7227
|
return test;
|
|
7228
7228
|
}
|
|
7229
|
-
`;static createAbTestsTable(n){return{[`${n.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(n){return{[`${n.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ee.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:n.abTestsTable}}}}}}static selectVariant(n,i){let o=Ee.hashString(i+n.id)%100,c=0;for(let u=0;u<n.variants.length;u++)if(c+=n.trafficSplit[u],o<c)return n.variants[u];return n.variants[n.variants.length-1]}static determineWinner(n){if(n.variants.length===0)return null;let i=n.winningCriteria,s=n.variants[0],o=Ee.getMetricValue(s,i);for(let c of n.variants.slice(1)){let u=Ee.getMetricValue(c,i);if(u>o)o=u,s=c}return s}static calculateSignificance(n,i,s){let o=n.stats.sent,c=i.stats.sent;if(o<30||c<30)return 0;let u=Ee.getMetricValue(n,s)/100,d=Ee.getMetricValue(i,s)/100,p=(u*o+d*c)/(o+c),y=Math.sqrt(p*(1-p)*(1/o+1/c));if(y===0)return 0;let h=Math.abs(u-d)/y;if(h>=2.576)return 99;if(h>=1.96)return 95;if(h>=1.645)return 90;if(h>=1.28)return 80;return Math.round(h*30)}static getMetricValue(n,i){switch(i){case"delivery_rate":return n.stats.deliveryRate;case"click_rate":return n.stats.clickRate;case"reply_rate":return n.stats.replyRate;case"conversion_rate":return n.stats.conversionRate;default:return n.stats.deliveryRate}}static hashString(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i)}}class wf{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(n){let i=`fifo-queue-${Date.now()}-${this.queueCounter++}`,s=n.name.endsWith(".fifo")?n.name:`${n.name}.fifo`,{name:o,...c}=n,u={id:i,name:s,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${s}`,...c};return this.queues.set(i,u),this.createDeduplicationConfig({queueId:i,contentBasedDeduplication:n.contentBasedDeduplication,deduplicationInterval:300}),u}createHighThroughputFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(n){let s={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...n};return this.deduplicationConfigs.set(n.queueId,s),s}sendMessage(n){let i=this.queues.get(n.queueId);if(!i)throw Error(`Queue not found: ${n.queueId}`);let s=this.deduplicationConfigs.get(n.queueId);if(s){let d=n.messageDeduplicationId||(i.contentBasedDeduplication?this.generateHash(n.messageBody):void 0);if(d&&this.isDuplicate(s,d))return null;if(d)s.deduplicationHashes.set(d,new Date)}let o=`msg-${Date.now()}-${this.messageCounter++}`,c=this.generateSequenceNumber(),u={id:o,messageId:o,messageGroupId:n.messageGroupId,messageDeduplicationId:n.messageDeduplicationId,body:n.messageBody,attributes:n.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:c};return this.messages.set(o,u),this.updateMessageGroup(n.queueId,n.messageGroupId),u}isDuplicate(n,i){let s=n.deduplicationHashes.get(i);if(!s)return!1;if((Date.now()-s.getTime())/1000>n.deduplicationInterval)return n.deduplicationHashes.delete(i),!1;return!0}generateHash(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(n,i){let s=`${n}-${i}`,o=this.messageGroups.get(s);if(!o)o={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:i,queueId:n,messagesInFlight:0},this.messageGroups.set(s,o);o.messagesInFlight++,o.lastMessageTimestamp=new Date}getMessageGroups(n){return Array.from(this.messageGroups.values()).filter((i)=>i.queueId===n)}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getMessages(n,i){let s=Array.from(this.messages.values());if(i)s=s.filter((o)=>o.messageGroupId===i);return s.sort((o,c)=>o.sequenceNumber.localeCompare(c.sequenceNumber))}generateFIFOQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.name,FifoQueue:!0,ContentBasedDeduplication:n.contentBasedDeduplication,DeduplicationScope:n.deduplicationScope,FifoThroughputLimit:n.fifoThroughputLimit,MessageRetentionPeriod:n.messageRetentionPeriod,VisibilityTimeout:n.visibilityTimeout,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime,...n.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:n.deadLetterTargetArn,maxReceiveCount:n.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 vE=new wf;class Rf{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(n){let i=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,s={id:i,...n};return this.monitors.set(i,s),s}createAutomatedMonitor(n){return this.createDLQMonitor({name:n.name,queueUrl:n.queueUrl,sourceQueues:n.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:n.notificationTopicArn})}collectMetrics(n){let s={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,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)},o=this.metrics.get(n)||[];return o.push(s),this.metrics.set(n,o),this.checkForAlerts(n,s),s}checkForAlerts(n,i){let s=Array.from(this.monitors.values()).find((c)=>c.queueUrl===n);if(!s)return;if(i.approximateNumberOfMessages>=s.alarmThreshold)this.createAlert({monitorId:s.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${s.name} has ${i.approximateNumberOfMessages} messages (threshold: ${s.alarmThreshold})`});let o=3600;if(i.approximateAgeOfOldestMessage>o)this.createAlert({monitorId:s.id,alertType:"old_message",severity:"medium",message:`DLQ ${s.name} has messages older than ${o} seconds`})}createAlert(n){let i=`alert-${Date.now()}-${this.alertCounter++}`,s={id:i,timestamp:new Date,acknowledged:!1,...n};return this.alerts.set(i,s),s}acknowledgeAlert(n){let i=this.alerts.get(n);if(!i)throw Error(`Alert not found: ${n}`);return i.acknowledged=!0,i}createReprocessJob(n){let i=`reprocess-${Date.now()}-${this.jobCounter++}`,s={id:i,queueUrl:n.queueUrl,messageId:n.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(i,s),s}async executeReprocessJob(n){let i=this.reprocessJobs.get(n);if(!i)throw Error(`Reprocess job not found: ${n}`);i.status="processing",i.startedAt=new Date,i.attempts++,await new Promise((o)=>setTimeout(o,100));let s=Math.random()>0.3;if(i.status=s?"success":"failed",i.completedAt=new Date,!s)i.error="Reprocessing failed - original error still present";return i}async batchReprocess(n){let i=[];for(let s=0;s<n.maxMessages;s++){let o=this.createReprocessJob({queueUrl:n.queueUrl,messageId:`msg-${s}`});await this.executeReprocessJob(o.id),i.push(o)}return i}getDLQStatistics(n,i=24){let s=new Date(Date.now()-i*60*60*1000),o=(this.metrics.get(n)||[]).filter((b)=>b.timestamp>=s);if(o.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let c=o[o.length-1],u=o.reduce((b,v)=>b+v.messagesReceived,0),d=o.reduce((b,v)=>b+v.messagesDeleted,0),p=o.reduce((b,v)=>b+v.messagesReprocessed,0),y=o.reduce((b,v)=>b+v.approximateAgeOfOldestMessage,0)/o.length,h=p>0?d/p*100:0;return{totalMessages:c.approximateNumberOfMessages,avgAge:y,messagesReceived:u,messagesDeleted:d,messagesReprocessed:p,successRate:h}}getMonitor(n){return this.monitors.get(n)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(n,i){let s=Array.from(this.alerts.values());if(n)s=s.filter((o)=>o.monitorId===n);if(i!==void 0)s=s.filter((o)=>o.acknowledged===i);return s.sort((o,c)=>c.timestamp.getTime()-o.timestamp.getTime())}getReprocessJobs(n){let i=Array.from(this.reprocessJobs.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateDLQAlarmCF(n){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${n.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${n.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:n.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.queueUrl.split("/").pop()}],...n.notificationTopicArn&&{AlarmActions:[n.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 TE=new Rf;class Df{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(n){let i=`batch-config-${Date.now()}-${this.configCounter++}`,s={id:i,...n};return this.configs.set(i,s),s}createHighThroughputConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(n){let i=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(n.configId))throw Error(`Batch config not found: ${n.configId}`);let o=[];for(let u=0;u<n.messageCount;u++)o.push({id:`msg-${i}-${u}`,messageId:`${i}-${u}`,body:`Message ${u}`,receiptHandle:`receipt-${i}-${u}`,attributes:{},status:"pending"});let c={id:i,configId:n.configId,messages:o,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(i,c),c}async processBatchJob(n){let i=this.jobs.get(n);if(!i)throw Error(`Batch job not found: ${n}`);let s=this.configs.get(i.configId);if(!s)throw Error(`Batch config not found: ${i.configId}`);i.status="processing",i.startedAt=new Date;let o=this.chunkArray(i.messages,s.batchSize);for(let c of o)await this.processBatch(c,s);return i.processedCount=i.messages.filter((c)=>c.status==="success").length,i.failedCount=i.messages.filter((c)=>c.status==="failed").length,i.status=i.failedCount===0?"completed":"failed",i.completedAt=new Date,this.collectProcessorMetrics(s.id,i),i}async processBatch(n,i){let s=n.map((o)=>this.processMessage(o,i));await Promise.all(s)}async processMessage(n,i){n.status="processing";let s=Date.now();await new Promise((u)=>setTimeout(u,Math.random()*100));let o=Date.now()-s;if(n.processingTime=o,Math.random()>0.1)n.status="success";else n.status="failed",n.error="Processing error"}chunkArray(n,i){let s=[];for(let o=0;o<n.length;o+=i)s.push(n.slice(o,o+i));return s}collectProcessorMetrics(n,i){let s=`metrics-${Date.now()}-${this.metricsCounter++}`,c=i.messages.filter((v)=>v.status==="success").map((v)=>v.processingTime||0).filter((v)=>v>0),u=c.length>0?c.reduce((v,A)=>v+A,0)/c.length:0,d=i.completedAt&&i.startedAt?(i.completedAt.getTime()-i.startedAt.getTime())/1000:1,p=i.processedCount/d,y=i.messages.length>0?i.failedCount/i.messages.length*100:0,h={id:s,configId:n,timestamp:new Date,messagesProcessed:i.processedCount,averageProcessingTime:u,throughput:p,errorRate:y},b=this.metrics.get(n)||[];b.push(h),this.metrics.set(n,b)}getBatchStatistics(n){let i=this.metrics.get(n)||[];if(i.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let s=i.reduce((d,p)=>d+p.messagesProcessed,0),o=i.reduce((d,p)=>d+p.throughput,0)/i.length,c=i.reduce((d,p)=>d+p.errorRate,0)/i.length,u=i.reduce((d,p)=>d+p.averageProcessingTime,0)/i.length;return{totalJobsProcessed:i.length,totalMessagesProcessed:s,averageThroughput:o,averageErrorRate:c,averageProcessingTime:u}}optimizeBatchConfig(n){let i=this.configs.get(n);if(!i)throw Error(`Batch config not found: ${n}`);let s=this.getBatchStatistics(n);if(s.averageErrorRate<5&&i.batchSize<10)i.batchSize=Math.min(10,i.batchSize+1);if(s.averageErrorRate>20&&i.batchSize>1)i.batchSize=Math.max(1,i.batchSize-1);if(s.averageThroughput<5&&i.parallelProcessors<20)i.parallelProcessors++;return i}getConfig(n){return this.configs.get(n)}listConfigs(){return Array.from(this.configs.values())}getJob(n){return this.jobs.get(n)}listJobs(n){let i=Array.from(this.jobs.values());if(n)i=i.filter((s)=>s.configId===n);return i}generateBatchProcessorCF(n){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${n.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:n.batchSize,MaximumBatchingWindowInSeconds:n.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var wE=new Df;class Pf{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(n){let i=`queue-${Date.now()}-${this.queueCounter++}`,s={id:i,purgeInProgress:!1,...n};return this.queues.set(i,s),s}createStandardQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:(n.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:n.waitTimeSeconds||20})}createRetentionPolicy(n){let i=`retention-${Date.now()}-${this.retentionCounter++}`,s={id:i,...n};this.retentionPolicies.set(i,s);let o=this.queues.get(n.queueId);if(o)o.messageRetentionPeriod=n.retentionPeriod;return s}createShortRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:n.s3Bucket})}createDelayQueue(n){let i=`delay-${Date.now()}-${this.delayCounter++}`,s={id:i,...n};this.delayQueues.set(i,s);let o=Array.from(this.queues.values()).find((c)=>c.queueUrl===n.queueUrl);if(o)o.delaySeconds=n.defaultDelay;return s}createScheduledDelayQueue(n){return this.createDelayQueue({queueUrl:n.queueUrl,defaultDelay:n.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(n){let i=this.queues.get(n);if(!i)throw Error(`Queue not found: ${n}`);if(i.purgeInProgress)throw Error("Purge already in progress for this queue");let s=`purge-${Date.now()}-${this.purgeCounter++}`,o={id:s,queueUrl:i.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(s,o),i.purgeInProgress=!0,setTimeout(()=>{o.status="completed",o.completedAt=new Date,o.messagesPurged=Math.floor(Math.random()*1000),i.purgeInProgress=!1},100),o}collectQueueMetrics(n){let s={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,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)},o=this.metrics.get(n)||[];return o.push(s),this.metrics.set(n,o),s}getQueueHealth(n){let i=this.metrics.get(n)||[];if(i.length===0)return{status:"healthy",issues:[],recommendations:[]};let s=i[i.length-1],o=[],c=[],u="healthy";if(s.approximateNumberOfMessages>1e4)u="critical",o.push("Large message backlog detected"),c.push("Increase consumer capacity");else if(s.approximateNumberOfMessages>1000)u="warning",o.push("Growing message backlog"),c.push("Monitor consumer performance");if(s.oldestMessageAge&&s.oldestMessageAge>3600){if(u!=="critical")u="warning";o.push("Old messages in queue"),c.push("Review message processing")}if(s.approximateNumberOfMessagesDelayed>100){if(u!=="critical")u="warning";o.push("High number of delayed messages")}return{status:u,issues:o,recommendations:c}}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(n){return this.retentionPolicies.get(n)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(n){let i=Array.from(this.purgeOperations.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.queueName,MessageRetentionPeriod:n.messageRetentionPeriod,DelaySeconds:n.delaySeconds,MaximumMessageSize:n.maximumMessageSize,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime}}}generateCleanupRuleCF(n){return{Type:"AWS::Events::Rule",Properties:{Name:`${n.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:n.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:n.id,Input:JSON.stringify({queueId:n.queueId,archiveBucket:n.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 RE=new Pf;import{deflateRawSync as Mi}from"node:zlib";var Li=(()=>{let n=[];for(let i=0;i<256;i++){let s=i;for(let o=0;o<8;o++)s=s&1?3988292384^s>>>1:s>>>1;n[i]=s>>>0}return n})();function Oi(n){let i=4294967295;for(let s=0;s<n.length;s++)i=Li[(i^n[s])&255]^i>>>8;return(i^4294967295)>>>0}function $i(n){if(typeof n==="string")return Buffer.from(n,"utf-8");if(Buffer.isBuffer(n))return n;return Buffer.from(n)}function Bi(n){let i=Math.max(1980,n.getFullYear()),s=(n.getHours()<<11|n.getMinutes()<<5|n.getSeconds()>>1)&65535,o=(i-1980<<9|n.getMonth()+1<<5|n.getDate())&65535;return{time:s,date:o}}function rt(n){let i=[],s=[],o=0;for(let d of n){let p=$i(d.data),y=Mi(p),h=Oi(p),b=Buffer.from(d.name.replace(/\\/g,"/"),"utf-8"),{time:v,date:A}=Bi(d.date??new Date(0)),T=d.mode??420,R=Buffer.alloc(30+b.length);R.writeUInt32LE(67324752,0),R.writeUInt16LE(20,4),R.writeUInt16LE(0,6),R.writeUInt16LE(8,8),R.writeUInt16LE(v,10),R.writeUInt16LE(A,12),R.writeUInt32LE(h,14),R.writeUInt32LE(y.length,18),R.writeUInt32LE(p.length,22),R.writeUInt16LE(b.length,26),R.writeUInt16LE(0,28),b.copy(R,30);let P=Buffer.alloc(46+b.length);P.writeUInt32LE(33639248,0),P.writeUInt16LE(798,4),P.writeUInt16LE(20,6),P.writeUInt16LE(0,8),P.writeUInt16LE(8,10),P.writeUInt16LE(v,12),P.writeUInt16LE(A,14),P.writeUInt32LE(h,16),P.writeUInt32LE(y.length,20),P.writeUInt32LE(p.length,24),P.writeUInt16LE(b.length,28),P.writeUInt16LE(0,30),P.writeUInt16LE(0,32),P.writeUInt16LE(0,34),P.writeUInt16LE(0,36),P.writeUInt32LE((T&65535)<<16,38),P.writeUInt32LE(o,42),b.copy(P,46),i.push(R,y),s.push(P),o+=R.length+y.length}let c=Buffer.concat(s),u=Buffer.alloc(22);return u.writeUInt32LE(101010256,0),u.writeUInt16LE(0,4),u.writeUInt16LE(0,6),u.writeUInt16LE(n.length,8),u.writeUInt16LE(n.length,10),u.writeUInt32LE(c.length,12),u.writeUInt32LE(o,16),u.writeUInt16LE(0,20),Buffer.concat([...i,c,u])}function kf(n){let i=n.adapterImport??"./adapter",s=n.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7229
|
+
`;static createAbTestsTable(n){return{[`${n.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(n){return{[`${n.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ee.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:n.abTestsTable}}}}}}static selectVariant(n,i){let o=Ee.hashString(i+n.id)%100,c=0;for(let u=0;u<n.variants.length;u++)if(c+=n.trafficSplit[u],o<c)return n.variants[u];return n.variants[n.variants.length-1]}static determineWinner(n){if(n.variants.length===0)return null;let i=n.winningCriteria,s=n.variants[0],o=Ee.getMetricValue(s,i);for(let c of n.variants.slice(1)){let u=Ee.getMetricValue(c,i);if(u>o)o=u,s=c}return s}static calculateSignificance(n,i,s){let o=n.stats.sent,c=i.stats.sent;if(o<30||c<30)return 0;let u=Ee.getMetricValue(n,s)/100,d=Ee.getMetricValue(i,s)/100,p=(u*o+d*c)/(o+c),y=Math.sqrt(p*(1-p)*(1/o+1/c));if(y===0)return 0;let h=Math.abs(u-d)/y;if(h>=2.576)return 99;if(h>=1.96)return 95;if(h>=1.645)return 90;if(h>=1.28)return 80;return Math.round(h*30)}static getMetricValue(n,i){switch(i){case"delivery_rate":return n.stats.deliveryRate;case"click_rate":return n.stats.clickRate;case"reply_rate":return n.stats.replyRate;case"conversion_rate":return n.stats.conversionRate;default:return n.stats.deliveryRate}}static hashString(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i)}}class wf{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(n){let i=`fifo-queue-${Date.now()}-${this.queueCounter++}`,s=n.name.endsWith(".fifo")?n.name:`${n.name}.fifo`,{name:o,...c}=n,u={id:i,name:s,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${s}`,...c};return this.queues.set(i,u),this.createDeduplicationConfig({queueId:i,contentBasedDeduplication:n.contentBasedDeduplication,deduplicationInterval:300}),u}createHighThroughputFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(n){let s={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...n};return this.deduplicationConfigs.set(n.queueId,s),s}sendMessage(n){let i=this.queues.get(n.queueId);if(!i)throw Error(`Queue not found: ${n.queueId}`);let s=this.deduplicationConfigs.get(n.queueId);if(s){let d=n.messageDeduplicationId||(i.contentBasedDeduplication?this.generateHash(n.messageBody):void 0);if(d&&this.isDuplicate(s,d))return null;if(d)s.deduplicationHashes.set(d,new Date)}let o=`msg-${Date.now()}-${this.messageCounter++}`,c=this.generateSequenceNumber(),u={id:o,messageId:o,messageGroupId:n.messageGroupId,messageDeduplicationId:n.messageDeduplicationId,body:n.messageBody,attributes:n.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:c};return this.messages.set(o,u),this.updateMessageGroup(n.queueId,n.messageGroupId),u}isDuplicate(n,i){let s=n.deduplicationHashes.get(i);if(!s)return!1;if((Date.now()-s.getTime())/1000>n.deduplicationInterval)return n.deduplicationHashes.delete(i),!1;return!0}generateHash(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(n,i){let s=`${n}-${i}`,o=this.messageGroups.get(s);if(!o)o={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:i,queueId:n,messagesInFlight:0},this.messageGroups.set(s,o);o.messagesInFlight++,o.lastMessageTimestamp=new Date}getMessageGroups(n){return Array.from(this.messageGroups.values()).filter((i)=>i.queueId===n)}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getMessages(n,i){let s=Array.from(this.messages.values());if(i)s=s.filter((o)=>o.messageGroupId===i);return s.sort((o,c)=>o.sequenceNumber.localeCompare(c.sequenceNumber))}generateFIFOQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.name,FifoQueue:!0,ContentBasedDeduplication:n.contentBasedDeduplication,DeduplicationScope:n.deduplicationScope,FifoThroughputLimit:n.fifoThroughputLimit,MessageRetentionPeriod:n.messageRetentionPeriod,VisibilityTimeout:n.visibilityTimeout,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime,...n.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:n.deadLetterTargetArn,maxReceiveCount:n.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 vE=new wf;class Rf{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(n){let i=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,s={id:i,...n};return this.monitors.set(i,s),s}createAutomatedMonitor(n){return this.createDLQMonitor({name:n.name,queueUrl:n.queueUrl,sourceQueues:n.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:n.notificationTopicArn})}collectMetrics(n){let s={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,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)},o=this.metrics.get(n)||[];return o.push(s),this.metrics.set(n,o),this.checkForAlerts(n,s),s}checkForAlerts(n,i){let s=Array.from(this.monitors.values()).find((c)=>c.queueUrl===n);if(!s)return;if(i.approximateNumberOfMessages>=s.alarmThreshold)this.createAlert({monitorId:s.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${s.name} has ${i.approximateNumberOfMessages} messages (threshold: ${s.alarmThreshold})`});let o=3600;if(i.approximateAgeOfOldestMessage>o)this.createAlert({monitorId:s.id,alertType:"old_message",severity:"medium",message:`DLQ ${s.name} has messages older than ${o} seconds`})}createAlert(n){let i=`alert-${Date.now()}-${this.alertCounter++}`,s={id:i,timestamp:new Date,acknowledged:!1,...n};return this.alerts.set(i,s),s}acknowledgeAlert(n){let i=this.alerts.get(n);if(!i)throw Error(`Alert not found: ${n}`);return i.acknowledged=!0,i}createReprocessJob(n){let i=`reprocess-${Date.now()}-${this.jobCounter++}`,s={id:i,queueUrl:n.queueUrl,messageId:n.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(i,s),s}async executeReprocessJob(n){let i=this.reprocessJobs.get(n);if(!i)throw Error(`Reprocess job not found: ${n}`);i.status="processing",i.startedAt=new Date,i.attempts++,await new Promise((o)=>setTimeout(o,100));let s=Math.random()>0.3;if(i.status=s?"success":"failed",i.completedAt=new Date,!s)i.error="Reprocessing failed - original error still present";return i}async batchReprocess(n){let i=[];for(let s=0;s<n.maxMessages;s++){let o=this.createReprocessJob({queueUrl:n.queueUrl,messageId:`msg-${s}`});await this.executeReprocessJob(o.id),i.push(o)}return i}getDLQStatistics(n,i=24){let s=new Date(Date.now()-i*60*60*1000),o=(this.metrics.get(n)||[]).filter((b)=>b.timestamp>=s);if(o.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let c=o[o.length-1],u=o.reduce((b,v)=>b+v.messagesReceived,0),d=o.reduce((b,v)=>b+v.messagesDeleted,0),p=o.reduce((b,v)=>b+v.messagesReprocessed,0),y=o.reduce((b,v)=>b+v.approximateAgeOfOldestMessage,0)/o.length,h=p>0?d/p*100:0;return{totalMessages:c.approximateNumberOfMessages,avgAge:y,messagesReceived:u,messagesDeleted:d,messagesReprocessed:p,successRate:h}}getMonitor(n){return this.monitors.get(n)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(n,i){let s=Array.from(this.alerts.values());if(n)s=s.filter((o)=>o.monitorId===n);if(i!==void 0)s=s.filter((o)=>o.acknowledged===i);return s.sort((o,c)=>c.timestamp.getTime()-o.timestamp.getTime())}getReprocessJobs(n){let i=Array.from(this.reprocessJobs.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateDLQAlarmCF(n){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${n.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${n.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:n.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.queueUrl.split("/").pop()}],...n.notificationTopicArn&&{AlarmActions:[n.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 TE=new Rf;class Df{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(n){let i=`batch-config-${Date.now()}-${this.configCounter++}`,s={id:i,...n};return this.configs.set(i,s),s}createHighThroughputConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(n){let i=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(n.configId))throw Error(`Batch config not found: ${n.configId}`);let o=[];for(let u=0;u<n.messageCount;u++)o.push({id:`msg-${i}-${u}`,messageId:`${i}-${u}`,body:`Message ${u}`,receiptHandle:`receipt-${i}-${u}`,attributes:{},status:"pending"});let c={id:i,configId:n.configId,messages:o,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(i,c),c}async processBatchJob(n){let i=this.jobs.get(n);if(!i)throw Error(`Batch job not found: ${n}`);let s=this.configs.get(i.configId);if(!s)throw Error(`Batch config not found: ${i.configId}`);i.status="processing",i.startedAt=new Date;let o=this.chunkArray(i.messages,s.batchSize);for(let c of o)await this.processBatch(c,s);return i.processedCount=i.messages.filter((c)=>c.status==="success").length,i.failedCount=i.messages.filter((c)=>c.status==="failed").length,i.status=i.failedCount===0?"completed":"failed",i.completedAt=new Date,this.collectProcessorMetrics(s.id,i),i}async processBatch(n,i){let s=n.map((o)=>this.processMessage(o,i));await Promise.all(s)}async processMessage(n,i){n.status="processing";let s=Date.now();await new Promise((u)=>setTimeout(u,Math.random()*100));let o=Date.now()-s;if(n.processingTime=o,Math.random()>0.1)n.status="success";else n.status="failed",n.error="Processing error"}chunkArray(n,i){let s=[];for(let o=0;o<n.length;o+=i)s.push(n.slice(o,o+i));return s}collectProcessorMetrics(n,i){let s=`metrics-${Date.now()}-${this.metricsCounter++}`,c=i.messages.filter((v)=>v.status==="success").map((v)=>v.processingTime||0).filter((v)=>v>0),u=c.length>0?c.reduce((v,A)=>v+A,0)/c.length:0,d=i.completedAt&&i.startedAt?(i.completedAt.getTime()-i.startedAt.getTime())/1000:1,p=i.processedCount/d,y=i.messages.length>0?i.failedCount/i.messages.length*100:0,h={id:s,configId:n,timestamp:new Date,messagesProcessed:i.processedCount,averageProcessingTime:u,throughput:p,errorRate:y},b=this.metrics.get(n)||[];b.push(h),this.metrics.set(n,b)}getBatchStatistics(n){let i=this.metrics.get(n)||[];if(i.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let s=i.reduce((d,p)=>d+p.messagesProcessed,0),o=i.reduce((d,p)=>d+p.throughput,0)/i.length,c=i.reduce((d,p)=>d+p.errorRate,0)/i.length,u=i.reduce((d,p)=>d+p.averageProcessingTime,0)/i.length;return{totalJobsProcessed:i.length,totalMessagesProcessed:s,averageThroughput:o,averageErrorRate:c,averageProcessingTime:u}}optimizeBatchConfig(n){let i=this.configs.get(n);if(!i)throw Error(`Batch config not found: ${n}`);let s=this.getBatchStatistics(n);if(s.averageErrorRate<5&&i.batchSize<10)i.batchSize=Math.min(10,i.batchSize+1);if(s.averageErrorRate>20&&i.batchSize>1)i.batchSize=Math.max(1,i.batchSize-1);if(s.averageThroughput<5&&i.parallelProcessors<20)i.parallelProcessors++;return i}getConfig(n){return this.configs.get(n)}listConfigs(){return Array.from(this.configs.values())}getJob(n){return this.jobs.get(n)}listJobs(n){let i=Array.from(this.jobs.values());if(n)i=i.filter((s)=>s.configId===n);return i}generateBatchProcessorCF(n){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${n.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:n.batchSize,MaximumBatchingWindowInSeconds:n.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var wE=new Df;class Pf{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(n){let i=`queue-${Date.now()}-${this.queueCounter++}`,s={id:i,purgeInProgress:!1,...n};return this.queues.set(i,s),s}createStandardQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:(n.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:n.waitTimeSeconds||20})}createRetentionPolicy(n){let i=`retention-${Date.now()}-${this.retentionCounter++}`,s={id:i,...n};this.retentionPolicies.set(i,s);let o=this.queues.get(n.queueId);if(o)o.messageRetentionPeriod=n.retentionPeriod;return s}createShortRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:n.s3Bucket})}createDelayQueue(n){let i=`delay-${Date.now()}-${this.delayCounter++}`,s={id:i,...n};this.delayQueues.set(i,s);let o=Array.from(this.queues.values()).find((c)=>c.queueUrl===n.queueUrl);if(o)o.delaySeconds=n.defaultDelay;return s}createScheduledDelayQueue(n){return this.createDelayQueue({queueUrl:n.queueUrl,defaultDelay:n.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(n){let i=this.queues.get(n);if(!i)throw Error(`Queue not found: ${n}`);if(i.purgeInProgress)throw Error("Purge already in progress for this queue");let s=`purge-${Date.now()}-${this.purgeCounter++}`,o={id:s,queueUrl:i.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(s,o),i.purgeInProgress=!0,setTimeout(()=>{o.status="completed",o.completedAt=new Date,o.messagesPurged=Math.floor(Math.random()*1000),i.purgeInProgress=!1},100),o}collectQueueMetrics(n){let s={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,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)},o=this.metrics.get(n)||[];return o.push(s),this.metrics.set(n,o),s}getQueueHealth(n){let i=this.metrics.get(n)||[];if(i.length===0)return{status:"healthy",issues:[],recommendations:[]};let s=i[i.length-1],o=[],c=[],u="healthy";if(s.approximateNumberOfMessages>1e4)u="critical",o.push("Large message backlog detected"),c.push("Increase consumer capacity");else if(s.approximateNumberOfMessages>1000)u="warning",o.push("Growing message backlog"),c.push("Monitor consumer performance");if(s.oldestMessageAge&&s.oldestMessageAge>3600){if(u!=="critical")u="warning";o.push("Old messages in queue"),c.push("Review message processing")}if(s.approximateNumberOfMessagesDelayed>100){if(u!=="critical")u="warning";o.push("High number of delayed messages")}return{status:u,issues:o,recommendations:c}}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(n){return this.retentionPolicies.get(n)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(n){let i=Array.from(this.purgeOperations.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.queueName,MessageRetentionPeriod:n.messageRetentionPeriod,DelaySeconds:n.delaySeconds,MaximumMessageSize:n.maximumMessageSize,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime}}}generateCleanupRuleCF(n){return{Type:"AWS::Events::Rule",Properties:{Name:`${n.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:n.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:n.id,Input:JSON.stringify({queueId:n.queueId,archiveBucket:n.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 RE=new Pf;import{deflateRawSync as Mi}from"node:zlib";var Li=(()=>{let n=[];for(let i=0;i<256;i++){let s=i;for(let o=0;o<8;o++)s=s&1?3988292384^s>>>1:s>>>1;n[i]=s>>>0}return n})();function Oi(n){let i=4294967295;for(let s=0;s<n.length;s++)i=Li[(i^n[s])&255]^i>>>8;return(i^4294967295)>>>0}function $i(n){if(typeof n==="string")return Buffer.from(n,"utf-8");if(Buffer.isBuffer(n))return n;return Buffer.from(n)}function Bi(n){let i=Math.max(1980,n.getFullYear()),s=(n.getHours()<<11|n.getMinutes()<<5|n.getSeconds()>>1)&65535,o=(i-1980<<9|n.getMonth()+1<<5|n.getDate())&65535;return{time:s,date:o}}function nt(n){let i=[],s=[],o=0;for(let d of n){let p=$i(d.data),y=Mi(p),h=Oi(p),b=Buffer.from(d.name.replace(/\\/g,"/"),"utf-8"),{time:v,date:A}=Bi(d.date??new Date(0)),T=d.mode??420,R=Buffer.alloc(30+b.length);R.writeUInt32LE(67324752,0),R.writeUInt16LE(20,4),R.writeUInt16LE(0,6),R.writeUInt16LE(8,8),R.writeUInt16LE(v,10),R.writeUInt16LE(A,12),R.writeUInt32LE(h,14),R.writeUInt32LE(y.length,18),R.writeUInt32LE(p.length,22),R.writeUInt16LE(b.length,26),R.writeUInt16LE(0,28),b.copy(R,30);let P=Buffer.alloc(46+b.length);P.writeUInt32LE(33639248,0),P.writeUInt16LE(798,4),P.writeUInt16LE(20,6),P.writeUInt16LE(0,8),P.writeUInt16LE(8,10),P.writeUInt16LE(v,12),P.writeUInt16LE(A,14),P.writeUInt32LE(h,16),P.writeUInt32LE(y.length,20),P.writeUInt32LE(p.length,24),P.writeUInt16LE(b.length,28),P.writeUInt16LE(0,30),P.writeUInt16LE(0,32),P.writeUInt16LE(0,34),P.writeUInt16LE(0,36),P.writeUInt32LE((T&65535)<<16,38),P.writeUInt32LE(o,42),b.copy(P,46),i.push(R,y),s.push(P),o+=R.length+y.length}let c=Buffer.concat(s),u=Buffer.alloc(22);return u.writeUInt32LE(101010256,0),u.writeUInt16LE(0,4),u.writeUInt16LE(0,6),u.writeUInt16LE(n.length,8),u.writeUInt16LE(n.length,10),u.writeUInt32LE(c.length,12),u.writeUInt32LE(o,16),u.writeUInt16LE(0,20),Buffer.concat([...i,c,u])}function kf(n){let i=n.adapterImport??"./adapter",s=n.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7230
7230
|
import * as __userModule from ${JSON.stringify(s)}
|
|
7231
7231
|
import { resolveApp, createHandlers } from ${JSON.stringify(i)}
|
|
7232
7232
|
|
|
@@ -7236,9 +7236,9 @@ const __handlers = createHandlers(__app)
|
|
|
7236
7236
|
export const http = __handlers.http
|
|
7237
7237
|
export const queue = __handlers.queue
|
|
7238
7238
|
export const cli = __handlers.cli
|
|
7239
|
-
`}import{execSync as Fi}from"node:child_process";import{createHash as Gi}from"node:crypto";import{cpSync as _i,mkdtempSync as Wi,rmSync as Vi,writeFileSync as Ui}from"node:fs";import{tmpdir as Hi}from"node:os";import{dirname as ji,isAbsolute as Ki,join as Fe,resolve as qi}from"node:path";import{fileURLToPath as zi}from"node:url";var Qi=["adapter.ts","recursion.ts","auto-recursion.ts"];function
|
|
7239
|
+
`}import{execSync as Fi}from"node:child_process";import{createHash as Gi}from"node:crypto";import{cpSync as _i,mkdtempSync as Wi,rmSync as Vi,writeFileSync as Ui}from"node:fs";import{tmpdir as Hi}from"node:os";import{dirname as ji,isAbsolute as Ki,join as Fe,resolve as qi}from"node:path";import{fileURLToPath as zi}from"node:url";var Qi=["adapter.ts","recursion.ts","auto-recursion.ts"];function ss(){return Fe(ji(zi(import.meta.url)),"runtime")}function lS(n,i,s){for(let o of n??[])s?.(`build: ${o}`),Fi(o,{stdio:"inherit",cwd:i})}function Ko(n){return Gi("sha256").update(n).digest("hex")}function $l(n,i,s){return`deployments/${n}/${i}/${s}.zip`}async function pn(n){let i=qi(n.projectRoot??process.cwd()),{app:s}=n;if(!n.skipBuild)lS(s.build,i,n.onStep);let o=s.entry;if(!o)throw Error("serverless app: `entry` is required to package a Node/Bun application");let c=Ki(o)?o:Fe(i,o),u=Wi(Fe(Hi(),"tscloud-pkg-"));try{for(let A of Qi)_i(Fe(ss(),A),Fe(u,A));let d=Fe(u,"bootstrap.ts");Ui(d,kf({entryImport:c,adapterImport:"./adapter"})),n.onStep?.("bundling application");let p=await Bun.build({entrypoints:[d],target:s.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!p.success){let A=p.logs.map((T)=>String(T)).join(`
|
|
7240
7240
|
`);throw Error(`serverless app bundle failed:
|
|
7241
|
-
${A}`)}let y=p.outputs[0],h=Buffer.from(await y.arrayBuffer()),b="index",v=rt([{name:`${b}.mjs`,data:h}]);return{zip:v,bundle:h,sha256:Ko(v),handlerFile:b,handlers:{http:s.handlers?.http??`${b}.http`,queue:s.handlers?.queue??`${b}.queue`,cli:s.handlers?.cli??`${b}.cli`},bundleBytes:h.length}}finally{Vi(u,{recursive:!0,force:!0})}}var uS=["18","20","22"];function ia(n){if(!n)return"22";let i=String(n).match(/(\d+)/);return i?i[1]:"22"}function ns(n){let i=n.kind??"node";if(i==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:n.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(i==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:n.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let s=ia(n.runtimeVersion);if(n.runtime!=="provided.al2023"&&uS.includes(s))return{lambdaRuntime:n.runtime&&n.runtime.startsWith("nodejs")?n.runtime:`nodejs${s}.x`,kind:"node",version:s,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:s,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function hr(n,i,s){if(n.queues===!1)return[];if(n.queues===void 0||n.queues===!0)return[{name:`${i}-${s}-default`}];return n.queues.map((o)=>{if(typeof o==="string")return{name:`${i}-${s}-${o}`};let[c,u]=Object.entries(o)[0];return{name:`${i}-${s}-${c}`,concurrency:u}})}function Ml(n,i,s){return hr(n,i,s).map((o)=>o.name)}function Fl(n){let{app:i,environment:s,handlers:o}=n,c=n.config.project.slug,u=ns(i).lambdaRuntime,d=i.architecture??"x86_64",p=n.config.project.region,y={http:`${c}-${s}-http`,queue:`${c}-${s}-queue`,cli:`${c}-${s}-cli`};if(i.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 h=hr(i,c,s),b=h.map((G)=>G.name),v=b.length>0,A=i.logRetention??14,T=i.packaging==="image";if(T&&i.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 R=(i.scheduler??"on")!=="off",P=(i.cache?.driver??"dynamodb")==="dynamodb",I=Boolean(i.assets),M=Xi(c,s),L=i.tmpStorage??512,N={},O={},B=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:e.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:e.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${c}-${s}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[e.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${c}/${s}/*`),e.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${c}/${s}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[e.sub(`arn:aws:s3:::${M}`),e.sub(`arn:aws:s3:::${M}/*`),...i.storage?.bucket?[e.sub(`arn:aws:s3:::${i.storage.bucket}`),e.sub(`arn:aws:s3:::${i.storage.bucket}/*`)]:[]]}]}}];if(v)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:e.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${c}-${s}-*`)});if(P)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:e.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${c}-${s}-cache*`)});let F=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(i.vpc?.subnets?.length)F.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(i.lambdaInsights)F.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");N.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${c}-${s}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:F,Policies:B}};let U=(G)=>({TSCLOUD_LAMBDA_MODE:G,TSCLOUD_ENV:s,...i.octane?{TSCLOUD_OCTANE:"1"}:{},...i.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...P?{TSCLOUD_CACHE_TABLE:`${c}-${s}-cache`}:{},...v?{TSCLOUD_QUEUE:b[0]}:{},...i.env??{}}),j=Boolean(i.efs),H=typeof i.efs==="object"?i.efs:{},z=H.mountPath??"/mnt/local",ae=j&&!H.accessPointArn,Te=H.accessPointArn??(ae?e.getAtt("EfsAccessPoint","Arn"):void 0),oe=i.vpc?.subnets??[],pe=oe.length>0,se=i.cache?.driver==="elasticache"||i.database?.connection==="aurora-serverless"||Boolean(i.rdsProxy)||j;if(se&&!pe)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let me=pe?{VpcConfig:{SubnetIds:oe,SecurityGroupIds:[...i.vpc?.securityGroups??[],...se?[e.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Ie=ae?oe.map((G,ne)=>`EfsMountTarget${ne}`):[],Le=j?{FileSystemConfigs:[{Arn:Te,LocalMountPath:z}]}:{};if(j)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function fe(G,ne,ie,re,ye,ht,Ve,Ne=L){N[`${G}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${ne}`,RetentionInDays:A}};let Ue=[...n.runtimeLayers??[],...i.lambdaInsights?[i.lambdaInsights.layerArn]:[]],en=T?{PackageType:"Image",Code:{ImageUri:e.ref("ImageUri")},...i.kind==="php"?{}:{ImageConfig:{Command:[ie]}}}:{Runtime:u,Handler:ie,Code:{S3Bucket:e.ref("ArtifactBucket"),S3Key:e.ref("ArtifactKey")},...Ue.length?{Layers:[...new Set(Ue)]}:{}};N[G]={Type:"AWS::Lambda::Function",DependsOn:[`${G}LogGroup`,...Ie],Properties:{FunctionName:ne,Architectures:[d],MemorySize:ye,Timeout:ht,Role:e.getAtt("AppRole","Arn"),Environment:{Variables:U(re)},EphemeralStorage:{Size:Ne},...en,...Ve!==void 0?{ReservedConcurrentExecutions:Ve}:{},...me,...Le}}}if(fe("HttpFunction",y.http,o.http,"http",i.memory??1024,i.timeout??28,i.concurrency,L),fe("CliFunction",y.cli,o.cli,"cli",i.cliMemory??1024,i.cliTimeout??900,void 0,i.cliTmpStorage??L),v)fe("QueueFunction",y.queue,o.queue,"queue",i.queueMemory??1024,i.queueTimeout??120,void 0,i.queueTmpStorage??L);let ge=(i.provisionedConcurrency??0)>0?i.provisionedConcurrency:0,he=["HttpFunction","CliFunction",...v?["QueueFunction"]:[]];if(ge)for(let G of he)N[`${G}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:e.ref(G)}},N[`${G}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.ref(G),Name:"live",FunctionVersion:e.getAtt(`${G}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ge}}};let De=(G)=>ge?e.ref(`${G}Alias`):e.getAtt(G,"Arn"),Se=(G)=>ge?e.ref(`${G}Alias`):e.ref(G);N.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${c}-${s}`,ProtocolType:"HTTP"}},N.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:e.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:De("HttpFunction"),PayloadFormatVersion:"2.0"}},N.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:e.ref("HttpApi"),RouteKey:"$default",Target:e.join("/",["integrations",e.ref("HttpIntegration")])}},N.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:e.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},N.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:Se("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:e.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},O.HttpApiEndpoint={Description:"HTTP API endpoint",Value:e.getAtt("HttpApi","ApiEndpoint")},O.HttpApiId={Description:"HTTP API id",Value:e.ref("HttpApi")};let Re=(Array.isArray(i.domain)?i.domain:i.domain?[i.domain]:[]).filter(Boolean);if(Re.length){if(!i.certificateArn&&!i.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let G=i.certificateArn;if(!G)N.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:Re[0],...Re.length>1?{SubjectAlternativeNames:Re.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:Re.map((ne)=>({DomainName:ne,HostedZoneId:i.hostedZoneId}))}},G=e.ref("HttpCertificate");Re.forEach((ne,ie)=>{let re=`HttpDomain${ie}`;if(N[re]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:ne,DomainNameConfigurations:[{CertificateArn:G,EndpointType:"REGIONAL"}]}},N[`HttpApiMapping${ie}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:e.ref("HttpApi"),DomainName:e.ref(re),Stage:"$default"}},i.hostedZoneId)N[`HttpDomainRecord${ie}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:ne,Type:"A",AliasTarget:{DNSName:e.getAtt(re,"RegionalDomainName"),HostedZoneId:e.getAtt(re,"RegionalHostedZoneId")}}};O[`CustomDomain${ie}`]={Description:`Custom domain ${ne}`,Value:ne},O[`CustomDomainTarget${ie}`]={Description:`Point ${ne} (CNAME/alias) at this APIGW regional domain`,Value:e.getAtt(re,"RegionalDomainName")}})}if(v)N.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${c}-${s}-dlq`,MessageRetentionPeriod:1209600}},h.forEach((G,ne)=>{let ie=`AppQueue${ne}`,re=i.queueTimeout??120;N[ie]={Type:"AWS::SQS::Queue",Properties:{QueueName:G.name,VisibilityTimeout:Math.min(43200,re*6),RedrivePolicy:{deadLetterTargetArn:e.getAtt("AppQueueDlq","Arn"),maxReceiveCount:i.queueTries??3}}};let ye=G.concurrency??i.queueConcurrency;N[`${ie}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:e.getAtt(ie,"Arn"),FunctionName:Se("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ye?{ScalingConfig:{MaximumConcurrency:Math.max(2,ye)}}:{}}},O[`QueueUrl${ne}`]={Description:`Queue URL: ${G.name}`,Value:e.ref(ie)}});if(R)N.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:De("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},N.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:Se("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.getAtt("SchedulerRule","Arn")}};if(i.warm&&i.warm>0){let ne={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},ie=(i.warmFunctions??["http"]).filter((re)=>re!=="queue"||v);for(let re of ie){let ye=re.charAt(0).toUpperCase()+re.slice(1),ht=Math.ceil(i.warm/5),Ve=0;for(let Ne=0;Ne<ht;Ne++){let Ue=Math.min(5,i.warm-Ve);N[`Warmer${ye}Rule${Ne}`]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-warmer-${re}-${Ne}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Ue},(en,ar)=>({Id:`warm-${re}-${Ne}-${ar}`,Arn:e.getAtt(ne[re],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Ve+=Ue}N[`Warmer${ye}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:e.ref(ne[re]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${c}-${s}-warmer-${re}-*`)}}}}if(P)N.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-${s}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},O.CacheTableName={Description:"DynamoDB cache table",Value:e.ref("CacheTable")};if(I){if(N.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:M,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},N.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${c}-${s}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},N.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:e.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:e.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...i.assetDomain?{Aliases:[i.assetDomain],ViewerCertificate:{AcmCertificateArn:i.assetCertificateArn??e.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},i.assetDomain){if(!i.assetCertificateArn){if(!i.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(p!=="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 ${p}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);N.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:i.assetDomain,HostedZoneId:i.hostedZoneId}]}}}if(i.hostedZoneId)N.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:i.assetDomain,Type:"A",AliasTarget:{DNSName:e.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};O.AssetDomain={Description:"Custom asset CDN host",Value:i.assetDomain}}N.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:e.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:e.sub(`arn:aws:s3:::${M}/*`),Condition:{StringEquals:{"AWS:SourceArn":e.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},O.AssetsBucketName={Description:"Assets bucket",Value:e.ref("AssetsBucket")},O.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:e.getAtt("AssetsDistribution","DomainName")}}if(i.firewall?.enabled){let G=[],ne=0;if(i.firewall.rateLimit)G.push({Name:"rate-limit",Priority:ne++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:i.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-rate`}});let ie={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let re of i.firewall.rules??[]){let ye=ie[re];if(!ye)continue;G.push({Name:`managed-${re}`,Priority:ne++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ye}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-${re}`}})}N.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${c}-${s}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:G,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-waf`}}},O.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:e.getAtt("WebAcl","Arn")}}if(pe&&se){if(!i.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.");N.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:i.vpc.id,GroupDescription:`${c}-${s} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(ae)N.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${c}-${s}-efs`}]}},oe.forEach((G,ne)=>{N[`EfsMountTarget${ne}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:e.ref("EfsFileSystem"),SubnetId:G,SecurityGroups:[e.getAtt("DataSecurityGroup","GroupId")]}}}),N.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:e.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},O.EfsFileSystemId={Description:"EFS file system id",Value:e.ref("EfsFileSystem")};if(i.cache?.driver==="elasticache")N.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${c}-${s} cache subnets`,SubnetIds:oe}},N.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${c}-${s}-cache`,ReplicationGroupDescription:`${c}-${s} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:e.ref("CacheSubnetGroup"),SecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},O.CacheEndpoint={Description:"Redis primary endpoint",Value:e.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(i.database?.connection==="aurora-serverless")N.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${c}-${s} db subnets`,SubnetIds:oe}},N.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${c}/${s}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},N.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${c}-${s}-db`,DatabaseName:"app",MasterUsername:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:i.database?.minCapacity??0.5,MaxCapacity:i.database?.maxCapacity??4},DBSubnetGroupName:e.ref("DbSubnetGroup"),VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")]}},N.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:e.ref("DbCluster")}},O.DbEndpoint={Description:"Aurora cluster endpoint",Value:e.getAtt("DbCluster","Endpoint.Address")};if(i.rdsProxy&&i.database?.connection==="aurora-serverless")N.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:e.ref("DbSecret")}]}}]}},N.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof i.rdsProxy==="object"&&i.rdsProxy.name?i.rdsProxy.name:`${c}-${s}-proxy`,EngineFamily:"MYSQL",RoleArn:e.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:e.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:oe,VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},N.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:e.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[e.ref("DbCluster")]}},O.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:e.getAtt("DbProxy","Endpoint")};if(O.HttpFunctionName={Description:"HTTP function name",Value:e.ref("HttpFunction")},O.CliFunctionName={Description:"CLI function name",Value:e.ref("CliFunction")},v)O.QueueFunctionName={Description:"Queue function name",Value:e.ref("QueueFunction")};let $e={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${n.config.project.name} (${c}-${s})`,Parameters:T?{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:N,Outputs:O},We={};for(let G of Object.values(N))We[G.Type]=(We[G.Type]??0)+1;return{template:$e,functionNames:y,queueNames:b,resourceSummary:We}}var gS=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function pS(n){let i=`php${n.replace(".","")}`;return gS.map((s)=>`${i}-php-${s}`)}function Ul(n,i){let s=`php${n.replace(".","")}`,o=pS(n).join(" \\\n "),c=`/opt/remi/${s}/root`,u=`/etc/opt/remi/${s}`;return`${i?`FROM almalinux:9 AS ${i}`:"FROM almalinux:9"}
|
|
7241
|
+
${A}`)}let y=p.outputs[0],h=Buffer.from(await y.arrayBuffer()),b="index",v=nt([{name:`${b}.mjs`,data:h}]);return{zip:v,bundle:h,sha256:Ko(v),handlerFile:b,handlers:{http:s.handlers?.http??`${b}.http`,queue:s.handlers?.queue??`${b}.queue`,cli:s.handlers?.cli??`${b}.cli`},bundleBytes:h.length}}finally{Vi(u,{recursive:!0,force:!0})}}var uS=["18","20","22"];function as(n){if(!n)return"22";let i=String(n).match(/(\d+)/);return i?i[1]:"22"}function ns(n){let i=n.kind??"node";if(i==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:n.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(i==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:n.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let s=as(n.runtimeVersion);if(n.runtime!=="provided.al2023"&&uS.includes(s))return{lambdaRuntime:n.runtime&&n.runtime.startsWith("nodejs")?n.runtime:`nodejs${s}.x`,kind:"node",version:s,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:s,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function Ar(n,i,s){if(n.queues===!1)return[];if(n.queues===void 0||n.queues===!0)return[{name:`${i}-${s}-default`}];return n.queues.map((o)=>{if(typeof o==="string")return{name:`${i}-${s}-${o}`};let[c,u]=Object.entries(o)[0];return{name:`${i}-${s}-${c}`,concurrency:u}})}function Ml(n,i,s){return Ar(n,i,s).map((o)=>o.name)}function Fl(n){let{app:i,environment:s,handlers:o}=n,c=n.config.project.slug,u=ns(i).lambdaRuntime,d=i.architecture??"x86_64",p=n.config.project.region,y={http:`${c}-${s}-http`,queue:`${c}-${s}-queue`,cli:`${c}-${s}-cli`};if(i.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 h=Ar(i,c,s),b=h.map((G)=>G.name),v=b.length>0,A=i.logRetention??14,T=i.packaging==="image";if(T&&i.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 R=(i.scheduler??"on")!=="off",P=(i.cache?.driver??"dynamodb")==="dynamodb",I=Boolean(i.assets),M=Xi(c,s),L=i.tmpStorage??512,N={},O={},B=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:e.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:e.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${c}-${s}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[e.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${c}/${s}/*`),e.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${c}/${s}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[e.sub(`arn:aws:s3:::${M}`),e.sub(`arn:aws:s3:::${M}/*`),...i.storage?.bucket?[e.sub(`arn:aws:s3:::${i.storage.bucket}`),e.sub(`arn:aws:s3:::${i.storage.bucket}/*`)]:[]]}]}}];if(v)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:e.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${c}-${s}-*`)});if(P)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:e.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${c}-${s}-cache*`)});let F=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(i.vpc?.subnets?.length)F.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(i.lambdaInsights)F.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");N.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${c}-${s}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:F,Policies:B}};let U=(G)=>({TSCLOUD_LAMBDA_MODE:G,TSCLOUD_ENV:s,...i.octane?{TSCLOUD_OCTANE:"1"}:{},...i.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...P?{TSCLOUD_CACHE_TABLE:`${c}-${s}-cache`}:{},...v?{TSCLOUD_QUEUE:b[0]}:{},...i.env??{}}),j=Boolean(i.efs),H=typeof i.efs==="object"?i.efs:{},z=H.mountPath??"/mnt/local",se=j&&!H.accessPointArn,Te=H.accessPointArn??(se?e.getAtt("EfsAccessPoint","Arn"):void 0),oe=i.vpc?.subnets??[],pe=oe.length>0,ae=i.cache?.driver==="elasticache"||i.database?.connection==="aurora-serverless"||Boolean(i.rdsProxy)||j;if(ae&&!pe)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let me=pe?{VpcConfig:{SubnetIds:oe,SecurityGroupIds:[...i.vpc?.securityGroups??[],...ae?[e.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Ie=se?oe.map((G,ne)=>`EfsMountTarget${ne}`):[],Le=j?{FileSystemConfigs:[{Arn:Te,LocalMountPath:z}]}:{};if(j)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function fe(G,ne,ie,re,ye,ht,Ve,Ne=L){N[`${G}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${ne}`,RetentionInDays:A}};let Ue=[...n.runtimeLayers??[],...i.lambdaInsights?[i.lambdaInsights.layerArn]:[]],en=T?{PackageType:"Image",Code:{ImageUri:e.ref("ImageUri")},...i.kind==="php"?{}:{ImageConfig:{Command:[ie]}}}:{Runtime:u,Handler:ie,Code:{S3Bucket:e.ref("ArtifactBucket"),S3Key:e.ref("ArtifactKey")},...Ue.length?{Layers:[...new Set(Ue)]}:{}};N[G]={Type:"AWS::Lambda::Function",DependsOn:[`${G}LogGroup`,...Ie],Properties:{FunctionName:ne,Architectures:[d],MemorySize:ye,Timeout:ht,Role:e.getAtt("AppRole","Arn"),Environment:{Variables:U(re)},EphemeralStorage:{Size:Ne},...en,...Ve!==void 0?{ReservedConcurrentExecutions:Ve}:{},...me,...Le}}}if(fe("HttpFunction",y.http,o.http,"http",i.memory??1024,i.timeout??28,i.concurrency,L),fe("CliFunction",y.cli,o.cli,"cli",i.cliMemory??1024,i.cliTimeout??900,void 0,i.cliTmpStorage??L),v)fe("QueueFunction",y.queue,o.queue,"queue",i.queueMemory??1024,i.queueTimeout??120,void 0,i.queueTmpStorage??L);let ge=(i.provisionedConcurrency??0)>0?i.provisionedConcurrency:0,he=["HttpFunction","CliFunction",...v?["QueueFunction"]:[]];if(ge)for(let G of he)N[`${G}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:e.ref(G)}},N[`${G}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.ref(G),Name:"live",FunctionVersion:e.getAtt(`${G}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ge}}};let De=(G)=>ge?e.ref(`${G}Alias`):e.getAtt(G,"Arn"),Se=(G)=>ge?e.ref(`${G}Alias`):e.ref(G);N.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${c}-${s}`,ProtocolType:"HTTP"}},N.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:e.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:De("HttpFunction"),PayloadFormatVersion:"2.0"}},N.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:e.ref("HttpApi"),RouteKey:"$default",Target:e.join("/",["integrations",e.ref("HttpIntegration")])}},N.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:e.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},N.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:Se("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:e.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},O.HttpApiEndpoint={Description:"HTTP API endpoint",Value:e.getAtt("HttpApi","ApiEndpoint")},O.HttpApiId={Description:"HTTP API id",Value:e.ref("HttpApi")};let Re=(Array.isArray(i.domain)?i.domain:i.domain?[i.domain]:[]).filter(Boolean);if(Re.length){if(!i.certificateArn&&!i.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let G=i.certificateArn;if(!G)N.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:Re[0],...Re.length>1?{SubjectAlternativeNames:Re.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:Re.map((ne)=>({DomainName:ne,HostedZoneId:i.hostedZoneId}))}},G=e.ref("HttpCertificate");Re.forEach((ne,ie)=>{let re=`HttpDomain${ie}`;if(N[re]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:ne,DomainNameConfigurations:[{CertificateArn:G,EndpointType:"REGIONAL"}]}},N[`HttpApiMapping${ie}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:e.ref("HttpApi"),DomainName:e.ref(re),Stage:"$default"}},i.hostedZoneId)N[`HttpDomainRecord${ie}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:ne,Type:"A",AliasTarget:{DNSName:e.getAtt(re,"RegionalDomainName"),HostedZoneId:e.getAtt(re,"RegionalHostedZoneId")}}};O[`CustomDomain${ie}`]={Description:`Custom domain ${ne}`,Value:ne},O[`CustomDomainTarget${ie}`]={Description:`Point ${ne} (CNAME/alias) at this APIGW regional domain`,Value:e.getAtt(re,"RegionalDomainName")}})}if(v)N.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${c}-${s}-dlq`,MessageRetentionPeriod:1209600}},h.forEach((G,ne)=>{let ie=`AppQueue${ne}`,re=i.queueTimeout??120;N[ie]={Type:"AWS::SQS::Queue",Properties:{QueueName:G.name,VisibilityTimeout:Math.min(43200,re*6),RedrivePolicy:{deadLetterTargetArn:e.getAtt("AppQueueDlq","Arn"),maxReceiveCount:i.queueTries??3}}};let ye=G.concurrency??i.queueConcurrency;N[`${ie}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:e.getAtt(ie,"Arn"),FunctionName:Se("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ye?{ScalingConfig:{MaximumConcurrency:Math.max(2,ye)}}:{}}},O[`QueueUrl${ne}`]={Description:`Queue URL: ${G.name}`,Value:e.ref(ie)}});if(R)N.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:De("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},N.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:Se("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.getAtt("SchedulerRule","Arn")}};if(i.warm&&i.warm>0){let ne={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},ie=(i.warmFunctions??["http"]).filter((re)=>re!=="queue"||v);for(let re of ie){let ye=re.charAt(0).toUpperCase()+re.slice(1),ht=Math.ceil(i.warm/5),Ve=0;for(let Ne=0;Ne<ht;Ne++){let Ue=Math.min(5,i.warm-Ve);N[`Warmer${ye}Rule${Ne}`]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-warmer-${re}-${Ne}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Ue},(en,sr)=>({Id:`warm-${re}-${Ne}-${sr}`,Arn:e.getAtt(ne[re],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Ve+=Ue}N[`Warmer${ye}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:e.ref(ne[re]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${c}-${s}-warmer-${re}-*`)}}}}if(P)N.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-${s}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},O.CacheTableName={Description:"DynamoDB cache table",Value:e.ref("CacheTable")};if(I){if(N.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:M,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},N.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${c}-${s}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},N.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:e.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:e.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...i.assetDomain?{Aliases:[i.assetDomain],ViewerCertificate:{AcmCertificateArn:i.assetCertificateArn??e.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},i.assetDomain){if(!i.assetCertificateArn){if(!i.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(p!=="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 ${p}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);N.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:i.assetDomain,HostedZoneId:i.hostedZoneId}]}}}if(i.hostedZoneId)N.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:i.assetDomain,Type:"A",AliasTarget:{DNSName:e.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};O.AssetDomain={Description:"Custom asset CDN host",Value:i.assetDomain}}N.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:e.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:e.sub(`arn:aws:s3:::${M}/*`),Condition:{StringEquals:{"AWS:SourceArn":e.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},O.AssetsBucketName={Description:"Assets bucket",Value:e.ref("AssetsBucket")},O.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:e.getAtt("AssetsDistribution","DomainName")}}if(i.firewall?.enabled){let G=[],ne=0;if(i.firewall.rateLimit)G.push({Name:"rate-limit",Priority:ne++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:i.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-rate`}});let ie={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let re of i.firewall.rules??[]){let ye=ie[re];if(!ye)continue;G.push({Name:`managed-${re}`,Priority:ne++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ye}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-${re}`}})}N.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${c}-${s}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:G,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-waf`}}},O.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:e.getAtt("WebAcl","Arn")}}if(pe&&ae){if(!i.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.");N.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:i.vpc.id,GroupDescription:`${c}-${s} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(se)N.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${c}-${s}-efs`}]}},oe.forEach((G,ne)=>{N[`EfsMountTarget${ne}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:e.ref("EfsFileSystem"),SubnetId:G,SecurityGroups:[e.getAtt("DataSecurityGroup","GroupId")]}}}),N.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:e.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},O.EfsFileSystemId={Description:"EFS file system id",Value:e.ref("EfsFileSystem")};if(i.cache?.driver==="elasticache")N.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${c}-${s} cache subnets`,SubnetIds:oe}},N.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${c}-${s}-cache`,ReplicationGroupDescription:`${c}-${s} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:e.ref("CacheSubnetGroup"),SecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},O.CacheEndpoint={Description:"Redis primary endpoint",Value:e.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(i.database?.connection==="aurora-serverless")N.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${c}-${s} db subnets`,SubnetIds:oe}},N.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${c}/${s}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},N.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${c}-${s}-db`,DatabaseName:"app",MasterUsername:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:i.database?.minCapacity??0.5,MaxCapacity:i.database?.maxCapacity??4},DBSubnetGroupName:e.ref("DbSubnetGroup"),VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")]}},N.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:e.ref("DbCluster")}},O.DbEndpoint={Description:"Aurora cluster endpoint",Value:e.getAtt("DbCluster","Endpoint.Address")};if(i.rdsProxy&&i.database?.connection==="aurora-serverless")N.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:e.ref("DbSecret")}]}}]}},N.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof i.rdsProxy==="object"&&i.rdsProxy.name?i.rdsProxy.name:`${c}-${s}-proxy`,EngineFamily:"MYSQL",RoleArn:e.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:e.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:oe,VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},N.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:e.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[e.ref("DbCluster")]}},O.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:e.getAtt("DbProxy","Endpoint")};if(O.HttpFunctionName={Description:"HTTP function name",Value:e.ref("HttpFunction")},O.CliFunctionName={Description:"CLI function name",Value:e.ref("CliFunction")},v)O.QueueFunctionName={Description:"Queue function name",Value:e.ref("QueueFunction")};let $e={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${n.config.project.name} (${c}-${s})`,Parameters:T?{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:N,Outputs:O},We={};for(let G of Object.values(N))We[G.Type]=(We[G.Type]??0)+1;return{template:$e,functionNames:y,queueNames:b,resourceSummary:We}}var gS=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function pS(n){let i=`php${n.replace(".","")}`;return gS.map((s)=>`${i}-php-${s}`)}function Ul(n,i){let s=`php${n.replace(".","")}`,o=pS(n).join(" \\\n "),c=`/opt/remi/${s}/root`,u=`/etc/opt/remi/${s}`;return`${i?`FROM almalinux:9 AS ${i}`:"FROM almalinux:9"}
|
|
7242
7242
|
|
|
7243
7243
|
# Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
|
|
7244
7244
|
# cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
|
|
@@ -7299,7 +7299,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
7299
7299
|
|
|
7300
7300
|
# Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
|
|
7301
7301
|
CMD [ "index.http" ]
|
|
7302
|
-
`}import{execFileSync as pt}from"node:child_process";import{mkdtempSync as jn,readFileSync as gt,rmSync as Kn}from"node:fs";import{tmpdir as qn}from"node:os";import{dirname as aa,join as we}from"node:path";import{fileURLToPath as sa}from"node:url";function zn(){return aa(sa(import.meta.url))}function Bf(){return gt(we(zn(),"runtime.mjs"),"utf-8")}function Qn(n){return gt(we(zn(),`${n}-bootstrap`),"utf-8")}function DE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"arm64":"x64",o=n.version.replace(/^v/,""),c=n.onStep??(()=>{}),u=jn(we(qn(),"tscloud-node-layer-"));try{let d=o.includes(".")?o:oa(o),p=`node-v${d}-linux-${s}`,y=`https://nodejs.org/dist/v${d}/${p}.tar.xz`;c(`downloading Node ${d} (${i})`);let h=we(u,"node.tar.xz");Jn(y,h),c("extracting node binary"),pt("tar",["-xf",h,"-C",u,`${p}/bin/node`],{stdio:"inherit"});let b=gt(we(u,p,"bin","node"));c("packaging layer");let v=[{name:"bootstrap",data:Qn("node"),mode:493},{name:"runtime.mjs",data:Bf(),mode:420},{name:"bin/node",data:b,mode:493}];return{zip:rt(v),architecture:i,version:d,fileCount:v.length}}finally{Kn(u,{recursive:!0,force:!0})}}function PE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"bun-linux-aarch64":"bun-linux-x64",o=n.version==="latest"?"":n.version.replace(/^v/,""),c=n.onStep??(()=>{}),u=jn(we(qn(),"tscloud-bun-layer-"));try{let d=o?`https://github.com/oven-sh/bun/releases/download/bun-v${o}/${s}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${s}.zip`;c(`downloading Bun ${o||"latest"} (${i})`);let p=we(u,"bun.zip");Jn(d,p),c("extracting bun binary"),pt("unzip",["-o","-q",p,"-d",u],{stdio:"inherit"});let y=gt(we(u,s,"bun"));c("packaging layer");let h=[{name:"bootstrap",data:Qn("bun"),mode:493},{name:"runtime.mjs",data:Bf(),mode:420},{name:"bin/bun",data:y,mode:493}];return{zip:rt(h),architecture:i,version:o||"latest",fileCount:h.length}}finally{Kn(u,{recursive:!0,force:!0})}}function Jn(n,i){pt("curl",["-fsSL","-o",i,n],{stdio:["ignore","ignore","inherit"]})}function oa(n){let i=pt("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),o=JSON.parse(i).find((c)=>c.version.startsWith(`v${n}.`));if(!o)throw Error(`No Node release found for major version ${n}`);return o.version.replace(/^v/,"")}import{AsyncLocalStorage as la}from"node:async_hooks";import{createHash as ca}from"node:crypto";var Wo="x-ts-cloud-invoke-depth",Jo="x-ts-cloud-invoke-chain",Xo="x-ts-cloud-trace-id";function Hl(n){return ca("sha256").update(n).digest("hex").slice(0,8)}var mn={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Yt(n,i){if(typeof n.get==="function")return n.get(i)??void 0;let s=n;return s[i]??s[i.toLowerCase()]??s[i.toUpperCase()]}function Gl(n,i=64){if(!n)return[];return n.split(".").map((s)=>s.trim()).filter((s)=>/^[0-9a-f]{8}$/.test(s)).slice(-i)}function Vl(n,i=mn){let s=Hl(n.functionId),o=Gl(Yt(n.headers,Jo)),c=n.traceId??Yt(n.headers,Xo)??crypto.randomUUID(),u=[...o,s],d=o.filter((v)=>v===s).length,p=o[o.length-1]===s,y=Number.parseInt(Yt(n.headers,Wo)??"",10),h=Math.max(u.length,Number.isFinite(y)?y+1:0),b="ok";if(h>i.maxDepth)b="depth_exceeded";else if(d>=i.maxRepeats)b="cycle_detected";else if(p&&i.maxRepeats<=1)b="self_invocation";return{reason:b,depth:h,chain:u,traceId:c,selfInvocation:p,repeats:d,propagate:{[Wo]:String(h),[Jo]:u.join("."),[Xo]:c}}}var Yn={ok:"",depth_exceeded:"Invocation chain is deeper than the configured limit; the call was refused to stop a runaway loop.",cycle_detected:"This function already appears in the invocation chain; the call was refused as a recursion loop.",self_invocation:"This function invoked itself directly; the call was refused.",trace_budget_exceeded:"This request has already made more invocations than its budget allows.",breaker_open:"Recursion protection is open for this function after repeated loop detections."};class is{limits;clock;traces=new Map;breakers=new Map;constructor(n=mn,i=()=>Date.now()){this.limits=n;this.clock=i}check(n){let i=this.clock();this.expireTraces(i);let s=Vl(n,this.limits),o=this.breakers.get(n.functionId);if(o?.openUntil!=null&&o.openUntil>i)return this.deny(n.functionId,s,"breaker_open",i,!1);if(s.reason!=="ok")return this.deny(n.functionId,s,s.reason,i,!0);let c=this.traces.get(s.traceId)??{count:0,firstAt:i};if(c.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(s.traceId,c),this.deny(n.functionId,s,"trace_budget_exceeded",i,!0);if(this.traces.set(s.traceId,{count:c.count+1,firstAt:c.firstAt}),o)this.breakers.set(n.functionId,{consecutiveBlocks:0});return{...s,allowed:!0,reason:"ok",propagate:s.propagate}}deny(n,i,s,o,c){if(c){let u=this.breakers.get(n)??{consecutiveBlocks:0},d=u.consecutiveBlocks+1;this.breakers.set(n,{consecutiveBlocks:d,openUntil:d>=this.limits.breakerThreshold?o+this.limits.breakerCooldownMs:u.openUntil})}return{...i,allowed:!1,reason:s,message:Yn[s]}}breakerOpen(n){let i=this.breakers.get(n);return i?.openUntil!=null&&i.openUntil>this.clock()}reset(n){if(n){this.breakers.delete(n);return}this.breakers.clear(),this.traces.clear()}expireTraces(n){if(this.traces.size===0)return;for(let[i,s]of this.traces)if(n-s.firstAt>this.limits.traceWindowMs)this.traces.delete(i)}get trackedTraces(){return this.traces.size}}function Yo(n){return{...n.propagate}}function Zo(n){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":n.reason},body:{error:"recursion_blocked",reason:n.reason,message:n.message??Yn[n.reason],depth:n.depth,traceId:n.traceId}}}var xf=new la;function Zn(n){let i=globalThis.process?.env?.[n];if(i==null||i==="")return;return i!=="0"&&i.toLowerCase()!=="false"}function ua(){let n=globalThis.process?.env??{};return n.TS_CLOUD_FUNCTION_ID||n.AWS_LAMBDA_FUNCTION_NAME||n.FUNCTION_NAME||"function"}function mS(n){let i=n===!1?{enabled:!1}:n??{},s=Zn("TS_CLOUD_RECURSION_PROTECTION"),o=Zn("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:s??i.enabled??!0,detectionOnly:o??i.detectionOnly??!1,limits:{...mn,...i.limits},functionId:i.functionId??ua()}}var Me,ve;function fS(){let n=globalThis.fetch;if(!n||Me===n)return()=>{};ve=n;let i=async(s,o)=>{let c=xf.getStore();if(!c)return ve(s,o);let u=new Headers(o?.headers??(s instanceof Request?s.headers:void 0));for(let[d,p]of Object.entries(Yo(c)))u.set(d,p);if(s instanceof Request)return ve(new Request(s,{headers:u}),o);return ve(s,{...o,headers:u})};return Object.assign(i,n),globalThis.fetch=i,Me=i,()=>{if(globalThis.fetch===Me&&ve)globalThis.fetch=ve;Me=void 0}}var yt,Zt;function hS(n){if(!yt||JSON.stringify(Zt)!==JSON.stringify(n))yt=new is(n),Zt=n;return yt}function kE(){if(yt=void 0,Zt=void 0,Me&&ve&&globalThis.fetch===Me)globalThis.fetch=ve;Me=void 0,ve=void 0}function Of(n,i){let s=mS(i);if(!s.enabled)return;let o=hS(s.limits),c={functionId:s.functionId,headers:n},u=o.check(c);return{verdict:u,blocked:!u.allowed&&!s.detectionOnly,observed:!u.allowed&&s.detectionOnly}}function _f(n,i){return fS(),xf.run(n,i)}function NE(n){let i=n,s=i?.default??i;if(typeof s==="function")return{fetch:s};return{fetch:s?.fetch??i?.fetch,queue:s?.queue??i?.queue,cli:s?.cli??i?.cli}}var da=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function ma(n){if(!n)return!0;return da.test(n)}function pa(n){if(n?.maintenance)return n.maintenance;let i=globalThis.process?.env??{};return{enabled:i.MAINTENANCE_MODE==="1"||i.MAINTENANCE_MODE==="true",bypassSecret:i.MAINTENANCE_BYPASS_SECRET}}function AS(n){let i=n.requestContext?.domainName??"localhost",s=n.rawQueryString?`?${n.rawQueryString}`:"",o=`https://${i}${n.rawPath||"/"}${s}`,c=new Headers;for(let[p,y]of Object.entries(n.headers??{}))if(y!==void 0)c.set(p,y);if(n.cookies?.length)c.set("cookie",n.cookies.join("; "));let u=n.requestContext.http.method,d;if(n.body!==void 0&&u!=="GET"&&u!=="HEAD")d=n.isBase64Encoded?new Uint8Array(Buffer.from(n.body,"base64")):new TextEncoder().encode(n.body);return new Request(o,{method:u,headers:c,body:d})}async function Lf(n){let i={},s=[],o=typeof n.headers.getSetCookie==="function"?n.headers.getSetCookie():[];for(let d of o)s.push(d);n.headers.forEach((d,p)=>{if(p.toLowerCase()==="set-cookie")return;i[p]=d});let c=Buffer.from(await n.arrayBuffer()),u=ma(n.headers.get("content-type"));return{statusCode:n.status,headers:i,...s.length?{cookies:s}:{},body:u?c.toString("utf-8"):c.toString("base64"),isBase64Encoded:!u}}function yS(n,i){return async(s)=>{if(s.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!n)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let o=pa(i);if(o.enabled){let d=s.headers?.["x-maintenance-bypass"]??s.cookies?.find((p)=>p.startsWith("tscloud_bypass="))?.split("=")[1];if(!o.bypassSecret||d!==o.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let c=Of(s.headers??{},i?.recursionProtection);if(c?.blocked){let d=Zo(c.verdict);return{statusCode:d.status,headers:{...d.headers,"retry-after":"60"},body:JSON.stringify(d.body),isBase64Encoded:!1}}let u=AS(s);if(!c){let d=await n(u);return Lf(d)}if(c.observed)console.warn(`[ts-cloud] recursion detected (${c.verdict.reason}) at depth ${c.verdict.depth}; detection-only mode let it run`);return _f(c.verdict,async()=>Lf(await n(u)))}}function ga(n){try{return JSON.parse(n)}catch{return n}}function SS(n){return async(i)=>{let s=[];if(i.warmer)return{batchItemFailures:s};if(!n)return{batchItemFailures:s};for(let o of i.Records??[])try{await n(ga(o.body),o)}catch{s.push({itemIdentifier:o.messageId})}return{batchItemFailures:s}}}function IS(n){return async(i)=>{if(i.warmer)return{statusCode:0,output:"warm"};if(!n)return{statusCode:501,output:"No CLI handler configured"};return n(i)}}function BE(n,i){return{http:yS(n.fetch,i),queue:SS(n.queue),cli:IS(n.cli)}}function $f(n={}){let i=n.socketPath??"/tmp/.tscloud-fpm.sock",s=n.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7302
|
+
`}import{execFileSync as pt}from"node:child_process";import{mkdtempSync as jn,readFileSync as gt,rmSync as Kn}from"node:fs";import{tmpdir as qn}from"node:os";import{dirname as os,join as we}from"node:path";import{fileURLToPath as cs}from"node:url";function zn(){return os(cs(import.meta.url))}function Bf(){return gt(we(zn(),"runtime.mjs"),"utf-8")}function Qn(n){return gt(we(zn(),`${n}-bootstrap`),"utf-8")}function DE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"arm64":"x64",o=n.version.replace(/^v/,""),c=n.onStep??(()=>{}),u=jn(we(qn(),"tscloud-node-layer-"));try{let d=o.includes(".")?o:ls(o),p=`node-v${d}-linux-${s}`,y=`https://nodejs.org/dist/v${d}/${p}.tar.xz`;c(`downloading Node ${d} (${i})`);let h=we(u,"node.tar.xz");Jn(y,h),c("extracting node binary"),pt("tar",["-xf",h,"-C",u,`${p}/bin/node`],{stdio:"inherit"});let b=gt(we(u,p,"bin","node"));c("packaging layer");let v=[{name:"bootstrap",data:Qn("node"),mode:493},{name:"runtime.mjs",data:Bf(),mode:420},{name:"bin/node",data:b,mode:493}];return{zip:nt(v),architecture:i,version:d,fileCount:v.length}}finally{Kn(u,{recursive:!0,force:!0})}}function PE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"bun-linux-aarch64":"bun-linux-x64",o=n.version==="latest"?"":n.version.replace(/^v/,""),c=n.onStep??(()=>{}),u=jn(we(qn(),"tscloud-bun-layer-"));try{let d=o?`https://github.com/oven-sh/bun/releases/download/bun-v${o}/${s}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${s}.zip`;c(`downloading Bun ${o||"latest"} (${i})`);let p=we(u,"bun.zip");Jn(d,p),c("extracting bun binary"),pt("unzip",["-o","-q",p,"-d",u],{stdio:"inherit"});let y=gt(we(u,s,"bun"));c("packaging layer");let h=[{name:"bootstrap",data:Qn("bun"),mode:493},{name:"runtime.mjs",data:Bf(),mode:420},{name:"bin/bun",data:y,mode:493}];return{zip:nt(h),architecture:i,version:o||"latest",fileCount:h.length}}finally{Kn(u,{recursive:!0,force:!0})}}function Jn(n,i){pt("curl",["-fsSL","-o",i,n],{stdio:["ignore","ignore","inherit"]})}function ls(n){let i=pt("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),o=JSON.parse(i).find((c)=>c.version.startsWith(`v${n}.`));if(!o)throw Error(`No Node release found for major version ${n}`);return o.version.replace(/^v/,"")}import{AsyncLocalStorage as ds}from"node:async_hooks";import{createHash as us}from"node:crypto";var Wo="x-ts-cloud-invoke-depth",Jo="x-ts-cloud-invoke-chain",Xo="x-ts-cloud-trace-id";function Hl(n){return us("sha256").update(n).digest("hex").slice(0,8)}var mn={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Yt(n,i){if(typeof n.get==="function")return n.get(i)??void 0;let s=n;return s[i]??s[i.toLowerCase()]??s[i.toUpperCase()]}function Gl(n,i=64){if(!n)return[];return n.split(".").map((s)=>s.trim()).filter((s)=>/^[0-9a-f]{8}$/.test(s)).slice(-i)}function Vl(n,i=mn){let s=Hl(n.functionId),o=Gl(Yt(n.headers,Jo)),c=n.traceId??Yt(n.headers,Xo)??crypto.randomUUID(),u=[...o,s],d=o.filter((v)=>v===s).length,p=o[o.length-1]===s,y=Number.parseInt(Yt(n.headers,Wo)??"",10),h=Math.max(u.length,Number.isFinite(y)?y+1:0),b="ok";if(h>i.maxDepth)b="depth_exceeded";else if(d>=i.maxRepeats)b="cycle_detected";else if(p&&i.maxRepeats<=1)b="self_invocation";return{reason:b,depth:h,chain:u,traceId:c,selfInvocation:p,repeats:d,propagate:{[Wo]:String(h),[Jo]:u.join("."),[Xo]:c}}}var Yn={ok:"",depth_exceeded:"Invocation chain is deeper than the configured limit; the call was refused to stop a runaway loop.",cycle_detected:"This function already appears in the invocation chain; the call was refused as a recursion loop.",self_invocation:"This function invoked itself directly; the call was refused.",trace_budget_exceeded:"This request has already made more invocations than its budget allows.",breaker_open:"Recursion protection is open for this function after repeated loop detections."};class is{limits;clock;traces=new Map;breakers=new Map;constructor(n=mn,i=()=>Date.now()){this.limits=n;this.clock=i}check(n){let i=this.clock();this.expireTraces(i);let s=Vl(n,this.limits),o=this.breakers.get(n.functionId);if(o?.openUntil!=null&&o.openUntil>i)return this.deny(n.functionId,s,"breaker_open",i,!1);if(s.reason!=="ok")return this.deny(n.functionId,s,s.reason,i,!0);let c=this.traces.get(s.traceId)??{count:0,firstAt:i};if(c.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(s.traceId,c),this.deny(n.functionId,s,"trace_budget_exceeded",i,!0);if(this.traces.set(s.traceId,{count:c.count+1,firstAt:c.firstAt}),o)this.breakers.set(n.functionId,{consecutiveBlocks:0});return{...s,allowed:!0,reason:"ok",propagate:s.propagate}}deny(n,i,s,o,c){if(c){let u=this.breakers.get(n)??{consecutiveBlocks:0},d=u.consecutiveBlocks+1;this.breakers.set(n,{consecutiveBlocks:d,openUntil:d>=this.limits.breakerThreshold?o+this.limits.breakerCooldownMs:u.openUntil})}return{...i,allowed:!1,reason:s,message:Yn[s]}}breakerOpen(n){let i=this.breakers.get(n);return i?.openUntil!=null&&i.openUntil>this.clock()}reset(n){if(n){this.breakers.delete(n);return}this.breakers.clear(),this.traces.clear()}expireTraces(n){if(this.traces.size===0)return;for(let[i,s]of this.traces)if(n-s.firstAt>this.limits.traceWindowMs)this.traces.delete(i)}get trackedTraces(){return this.traces.size}}function Yo(n){return{...n.propagate}}function Zo(n){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":n.reason},body:{error:"recursion_blocked",reason:n.reason,message:n.message??Yn[n.reason],depth:n.depth,traceId:n.traceId}}}var xf=new ds;function Zn(n){let i=globalThis.process?.env?.[n];if(i==null||i==="")return;return i!=="0"&&i.toLowerCase()!=="false"}function ms(){let n=globalThis.process?.env??{};return n.TS_CLOUD_FUNCTION_ID||n.AWS_LAMBDA_FUNCTION_NAME||n.FUNCTION_NAME||"function"}function mS(n){let i=n===!1?{enabled:!1}:n??{},s=Zn("TS_CLOUD_RECURSION_PROTECTION"),o=Zn("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:s??i.enabled??!0,detectionOnly:o??i.detectionOnly??!1,limits:{...mn,...i.limits},functionId:i.functionId??ms()}}var Me,ve;function fS(){let n=globalThis.fetch;if(!n||Me===n)return()=>{};ve=n;let i=async(s,o)=>{let c=xf.getStore();if(!c)return ve(s,o);let u=new Headers(o?.headers??(s instanceof Request?s.headers:void 0));for(let[d,p]of Object.entries(Yo(c)))u.set(d,p);if(s instanceof Request)return ve(new Request(s,{headers:u}),o);return ve(s,{...o,headers:u})};return Object.assign(i,n),globalThis.fetch=i,Me=i,()=>{if(globalThis.fetch===Me&&ve)globalThis.fetch=ve;Me=void 0}}var yt,Zt;function hS(n){if(!yt||JSON.stringify(Zt)!==JSON.stringify(n))yt=new is(n),Zt=n;return yt}function kE(){if(yt=void 0,Zt=void 0,Me&&ve&&globalThis.fetch===Me)globalThis.fetch=ve;Me=void 0,ve=void 0}function Of(n,i){let s=mS(i);if(!s.enabled)return;let o=hS(s.limits),c={functionId:s.functionId,headers:n},u=o.check(c);return{verdict:u,blocked:!u.allowed&&!s.detectionOnly,observed:!u.allowed&&s.detectionOnly}}function _f(n,i){return fS(),xf.run(n,i)}function NE(n){let i=n,s=i?.default??i;if(typeof s==="function")return{fetch:s};return{fetch:s?.fetch??i?.fetch,queue:s?.queue??i?.queue,cli:s?.cli??i?.cli}}var ps=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function gs(n){if(!n)return!0;return ps.test(n)}function ys(n){if(n?.maintenance)return n.maintenance;let i=globalThis.process?.env??{};return{enabled:i.MAINTENANCE_MODE==="1"||i.MAINTENANCE_MODE==="true",bypassSecret:i.MAINTENANCE_BYPASS_SECRET}}function AS(n){let i=n.requestContext?.domainName??"localhost",s=n.rawQueryString?`?${n.rawQueryString}`:"",o=`https://${i}${n.rawPath||"/"}${s}`,c=new Headers;for(let[p,y]of Object.entries(n.headers??{}))if(y!==void 0)c.set(p,y);if(n.cookies?.length)c.set("cookie",n.cookies.join("; "));let u=n.requestContext.http.method,d;if(n.body!==void 0&&u!=="GET"&&u!=="HEAD")d=n.isBase64Encoded?new Uint8Array(Buffer.from(n.body,"base64")):new TextEncoder().encode(n.body);return new Request(o,{method:u,headers:c,body:d})}async function Lf(n){let i={},s=[],o=typeof n.headers.getSetCookie==="function"?n.headers.getSetCookie():[];for(let d of o)s.push(d);n.headers.forEach((d,p)=>{if(p.toLowerCase()==="set-cookie")return;i[p]=d});let c=Buffer.from(await n.arrayBuffer()),u=gs(n.headers.get("content-type"));return{statusCode:n.status,headers:i,...s.length?{cookies:s}:{},body:u?c.toString("utf-8"):c.toString("base64"),isBase64Encoded:!u}}function yS(n,i){return async(s)=>{if(s.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!n)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let o=ys(i);if(o.enabled){let d=s.headers?.["x-maintenance-bypass"]??s.cookies?.find((p)=>p.startsWith("tscloud_bypass="))?.split("=")[1];if(!o.bypassSecret||d!==o.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let c=Of(s.headers??{},i?.recursionProtection);if(c?.blocked){let d=Zo(c.verdict);return{statusCode:d.status,headers:{...d.headers,"retry-after":"60"},body:JSON.stringify(d.body),isBase64Encoded:!1}}let u=AS(s);if(!c){let d=await n(u);return Lf(d)}if(c.observed)console.warn(`[ts-cloud] recursion detected (${c.verdict.reason}) at depth ${c.verdict.depth}; detection-only mode let it run`);return _f(c.verdict,async()=>Lf(await n(u)))}}function fs(n){try{return JSON.parse(n)}catch{return n}}function SS(n){return async(i)=>{let s=[];if(i.warmer)return{batchItemFailures:s};if(!n)return{batchItemFailures:s};for(let o of i.Records??[])try{await n(fs(o.body),o)}catch{s.push({itemIdentifier:o.messageId})}return{batchItemFailures:s}}}function IS(n){return async(i)=>{if(i.warmer)return{statusCode:0,output:"warm"};if(!n)return{statusCode:501,output:"No CLI handler configured"};return n(i)}}function BE(n,i){return{http:yS(n.fetch,i),queue:SS(n.queue),cli:IS(n.cli)}}function $f(n={}){let i=n.socketPath??"/tmp/.tscloud-fpm.sock",s=n.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7303
7303
|
[global]
|
|
7304
7304
|
daemonize = no
|
|
7305
7305
|
error_log = ${n.errorLog??"/tmp/storage/logs/php-fpm.log"}
|
|
@@ -7316,4 +7316,4 @@ decorate_workers_output = no
|
|
|
7316
7316
|
php_admin_value[error_log] = /dev/stderr
|
|
7317
7317
|
php_admin_flag[log_errors] = on
|
|
7318
7318
|
clear_env = no
|
|
7319
|
-
`}import{readFileSync as ya}from"node:fs";import{dirname as fa,join as Xn}from"node:path";import{fileURLToPath as ha}from"node:url";function ba(){return Xn(fa(ha(import.meta.url)),"runtime-assets")}function fn(){let n=ba(),i=(s)=>ya(Xn(n,s),"utf-8");return[{path:"bootstrap",contents:i("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:i("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:i("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:i("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:i("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:$f(),mode:420}]}function ql(n={}){let i=n.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:i,CACHE_DRIVER:i,SESSION_DRIVER:i,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 Mf=["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 ft}from"node:child_process";import{existsSync as Sa,mkdirSync as Aa,mkdtempSync as Ca,readdirSync as va,readFileSync as Ta,rmSync as Ra,statSync as er,writeFileSync as Pa}from"node:fs";import{tmpdir as Ea}from"node:os";import{join as Ge,relative as wa}from"node:path";function*tr(n){for(let i of va(n)){let s=Ge(n,i);if(er(s).isDirectory())yield*tr(s);else yield s}}function xE(n={}){let i=n.architecture??"x86_64",s=n.platform??(i==="arm64"?"linux/arm64":"linux/amd64"),o=n.onStep??(()=>{}),c=Ca(Ge(Ea(),"tscloud-php-layer-")),u="tscloud-php-layer:build";try{Pa(Ge(c,"Dockerfile"),Nf(n)),o("Building PHP runtime image (docker)"),ft("docker",["build","--platform",s,"-t","tscloud-php-layer:build",c],{stdio:"inherit"}),o("Extracting /opt/php from image");let d=ft("docker",["create","--platform",s,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),p=Ge(c,"opt");Aa(p,{recursive:!0});try{ft("docker",["cp",`${d}:/opt/php`,Ge(p,"php")],{stdio:"inherit"})}finally{ft("docker",["rm",d],{stdio:"ignore"})}if(!Sa(Ge(p,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let y=[];for(let A of tr(p)){let T=wa(p,A).replace(/\\/g,"/"),R=er(A).mode&73?493:420;y.push({name:T,data:Ta(A),mode:R})}o("Injecting runtime assets");let h=new Set(fn().map((A)=>A.path)),b=y.filter((A)=>!h.has(A.name));for(let A of fn())b.push({name:A.path,data:A.contents,mode:A.mode});return o("Packaging layer ZIP"),{zip:rt(b),architecture:i,fileCount:b.length}}finally{Ra(c,{recursive:!0,force:!0})}}import{execSync as Ia}from"node:child_process";import{createHash as Da}from"node:crypto";import{readdirSync as Na,readFileSync as xa,statSync as nr}from"node:fs";import{join as ka,relative as rr,resolve as Xt}from"node:path";var bS=[".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 Ma(n,i){return i.some((s)=>n===s||n.startsWith(`${s}/`))}function*ir(n,i,s){for(let o of Na(n)){let c=ka(n,o),u=rr(i,c).replace(/\\/g,"/");if(Ma(u,s))continue;if(nr(c).isDirectory())yield*ir(c,i,s);else yield c}}function ea(n){if(n.skipBuild)return;let i=Xt(n.projectRoot??process.cwd()),s=n.app.build??Mf;for(let o of s)n.onStep?.(`build: ${o}`),Ia(o,{stdio:"inherit",cwd:i})}function ta(n,i=[]){let s=Xt(n),o=[...bS,cn(),...i],c=[];for(let u of ir(s,s,o)){let d=rr(s,u).replace(/\\/g,"/"),p=(nr(u).mode&73)!==0;c.push({name:d,data:xa(u),mode:p?493:420})}return c}function jl(n){let i=Xt(n.projectRoot??process.cwd());ea(n),n.onStep?.("packaging application tree");let s=ta(i,n.exclude);if(!s.length)throw Error(`No files to package under ${i}`);let o=rt(s),c=n.app.handlers?.http??"public/index.php";return{zip:o,sha256:Da("sha256").update(o).digest("hex"),handlers:{http:c,queue:n.app.handlers?.queue??c,cli:n.app.handlers?.cli??c},fileCount:s.length}}class Ff{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(n){let i=`asset-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.optimizations.set(i,s),s}createImageOptimization(n){let i=`image-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.imageConfigs.set(i,s),s}createSSGConfig(n){let i=`ssg-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.ssgConfigs.set(i,s),s}createPrerenderConfig(n){let i=`prerender-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.prerenderConfigs.set(i,s),s}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 OE=new Ff;class zl{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(n,i){let s=`lifecycle-${Date.now()}-${this.counter++}`,o={id:s,transitions:n,expiration:i};return this.policies.set(s,o),o}enableVersioning(n=!1){let i=`versioning-${Date.now()}-${this.counter++}`,s={id:i,enabled:!0,mfaDelete:n};return this.versioningConfigs.set(i,s),s}createReplicationRule(n,i,s){let o=`replication-${Date.now()}-${this.counter++}`,c={id:o,sourceRegion:n,destRegion:i,destBucket:s};return this.replicationRules.set(o,c),c}createIntelligentTiering(n,i){let s=`tiering-${Date.now()}-${this.counter++}`,o={id:s,archiveDays:n,deepArchiveDays:i};return this.tieringConfigs.set(s,o),o}enableObjectLock(n){let i=`object-lock-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,mode:n.mode||"COMPLIANCE",retentionDays:n.retentionDays,retentionYears:n.retentionYears,legalHoldEnabled:n.legalHoldEnabled||!1};return this.objectLocks.set(i,s),s}enableTransferAcceleration(n){let i=`transfer-accel-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n,enabled:!0,endpoint:`${n}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(i,s),s}createAccessPoint(n){let i=`access-point-${Date.now()}-${this.counter++}`,s={id:i,name:n.name,bucketName:n.bucketName,vpcId:n.vpcId,publicAccessBlock:n.publicAccessBlock!==!1,policy:n.policy};return this.accessPoints.set(i,s),s}createGlacierArchive(n){let i=`glacier-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,archiveType:n.archiveType,transitionDays:n.transitionDays,restoreConfig:n.restoreTier?{tier:n.restoreTier,days:n.restoreDays||7}:void 0};return this.glacierConfigs.set(i,s),s}createInventory(n){let i=`inventory-${Date.now()}-${this.counter++}`,s={id:i,sourceBucket:n.sourceBucket,destinationBucket:n.destinationBucket,schedule:n.schedule||"Daily",format:n.format||"CSV",includedFields:n.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:n.prefix};return this.inventories.set(i,s),s}createBatchOperation(n){let i=`batch-op-${Date.now()}-${this.counter++}`,s={id:i,operation:n.operation,manifestBucket:n.manifestBucket,manifestKey:n.manifestKey,priority:n.priority||10,status:"pending"};return this.batchOps.set(i,s),s}executeBatchOperation(n){let i=this.batchOps.get(n);if(!i)throw Error(`Batch operation not found: ${n}`);return i.status="in_progress",i.totalObjects=1000,i.processedObjects=0,i}getBatchOperationStatus(n){return this.batchOps.get(n)}createLambdaNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"Lambda",arn:n.lambdaArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSQSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SQS",arn:n.queueArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSNSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SNS",arn:n.topicArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}generateObjectLockCF(n){let i={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:n.mode}}}};if(n.retentionDays)i.ObjectLockConfiguration.Rule.DefaultRetention.Days=n.retentionDays;if(n.retentionYears)i.ObjectLockConfiguration.Rule.DefaultRetention.Years=n.retentionYears;return i}generateTransferAccelerationCF(n){return{AccelerateConfiguration:{AccelerationStatus:n.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(n){return{Type:"AWS::S3::AccessPoint",Properties:{Name:n.name,Bucket:n.bucketName,...n.vpcId&&{VpcConfiguration:{VpcId:n.vpcId}},PublicAccessBlockConfiguration:n.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...n.policy&&{Policy:n.policy}}}}generateInventoryCF(n){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:n.id,Destination:{BucketArn:`arn:aws:s3:::${n.destinationBucket}`,Format:n.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:n.includedFields,ScheduleFrequency:n.schedule,...n.prefix&&{Prefix:n.prefix}}]}}}generateEventNotificationCF(n){let i=n.destination.type==="Lambda"?"LambdaConfigurations":n.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",s=n.destination.type==="Lambda"?"Function":n.destination.type==="SQS"?"Queue":"Topic",o={Event:n.events[0],[s]:n.destination.arn};if(n.filter)o.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};return{NotificationConfiguration:{[i]:[o]}}}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 CS=new zl;class Uf{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(n,i=30,s=10){let o=`health-${Date.now()}-${this.counter++}`,c={id:o,url:n,interval:i,timeout:s,status:"healthy"};return this.checks.set(o,c),c}createSyntheticMonitor(n,i,s,o){let c=`synthetic-${Date.now()}-${this.counter++}`,u={id:c,name:n,script:i,frequency:s,locations:o};return this.synthetics.set(c,u),u}trackUptime(n,i,s){let o=`uptime-${Date.now()}-${this.counter++}`,c=i/(i+s)*100,u={id:o,resource:n,uptime:i,downtime:s,availability:c};return this.uptimeTrackers.set(o,u),u}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var _E=new Uf;class Qf{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(n,i,s,o){let c=`waf-${Date.now()}-${this.counter++}`,u={id:c,name:n,priority:i,action:s,conditions:o};return this.wafRules.set(c,u),u}enableShield(n,i="standard"){let s=`shield-${Date.now()}-${this.counter++}`,o={id:s,resourceArn:n,protectionType:i};return this.shieldProtections.set(s,o),o}createSecurityGroup(n,i,s){let o=`sg-${Date.now()}-${this.counter++}`,c={id:o,name:n,vpcId:i,rules:s};return this.securityGroups.set(o,c),c}createNACL(n,i){let s=`nacl-${Date.now()}-${this.counter++}`,o={id:s,vpcId:n,rules:i};return this.nacls.set(s,o),o}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var LE=new Qf;class Hf{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(n,i){let s=`tagging-${Date.now()}-${this.counter++}`,o={id:s,tags:n,resources:i};return this.strategies.set(s,o),o}createCostAllocation(n,i){let s=`cost-${Date.now()}-${this.counter++}`,o={id:s,tagKey:n,allocations:i};return this.allocations.set(s,o),o}createResourceGroup(n,i,s){let o=`group-${Date.now()}-${this.counter++}`,c={id:o,name:n,query:{resourceTypeFilters:i,tagFilters:s}};return this.groups.set(o,c),c}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var $E=new Hf;export{LI,$I,rl,ym,nl,il,cn,Q,l,sl,Sm,K,ol,g,ty,C,Xe,Ji,dn,w,be,al,ry,r,t,MI,FI,m,UI,QI,HI,GI,VI,dr,cl,Xi,ny,qI,jI,xe,Ye,dl,Im,bm,zI,Cm,Em,vm,Qo,ll,ce,ln,Dt,Ho,Pt,Ce,iy,ul,Go,Tm,wm,Rm,Dm,gl,KI,W,E,sy,oy,Pm,a,S,Ze,f,km,et,J,kt,WI,Nm,X,pl,Oe,lr,Vo,de,ml,le,ay,qo,Y,Z,_,Yi,D,ur,Nt,ee,e,un,JI,Bm,fl,XI,YI,ZI,eb,hl,tb,rb,nb,ib,sb,ob,ab,cb,db,lb,ub,gb,cy,dy,ly,uy,gy,py,my,gr,xm,Om,pr,Zi,pb,_m,mb,fb,gn,hb,Ab,yb,Sb,Ib,bb,fy,hy,Ay,yy,Sy,es,Cb,jo,Iy,Lm,V,by,tt,zo,Bt,Cy,$m,Ey,vy,Ty,Mm,q,Eb,vb,Tb,wb,wy,Rb,te,Db,Pb,kb,Al,yl,Ry,Fm,Um,Nb,Bb,xb,Ob,_b,Dy,Sl,Lb,$b,Mb,Fb,Ub,Py,ky,Qb,Hb,Gb,Vb,qb,jb,zb,Ny,Kb,Qm,Il,Wb,Jb,Xb,Yb,Hm,Gm,Vm,Zb,bl,By,xy,Oy,_y,Cl,Ly,eC,tC,rC,nC,iC,sC,oC,$y,My,Fy,Uy,qm,aC,cC,dC,lC,uC,gC,pC,mC,fC,Qy,Hy,Gy,Vy,hC,AC,jm,yC,zm,Km,Wm,Jm,SC,IC,bC,CC,_e,ts,EC,vC,TC,wC,RC,DC,PC,kC,qy,NC,BC,Xm,Ym,xC,OC,jy,_C,LC,$C,MC,FC,UC,QC,HC,GC,VC,qC,jC,zC,KC,WC,JC,XC,YC,ZC,eE,tE,El,zy,vl,Ky,Tl,Wy,wl,Jy,Rl,Xy,mr,Yy,Dl,Zy,rs,eS,Pl,tS,kl,rS,Zm,rE,ef,nE,Nl,nS,fr,iS,tf,iE,Bl,sS,rf,sE,nf,oE,sf,aE,xl,oS,of,cE,af,dE,cf,lE,df,uE,Ol,aS,_l,cS,lf,gE,uf,pE,gf,mE,pf,fE,mf,hE,ff,AE,Ll,dS,hf,yE,Af,SE,yf,IE,Sf,bE,If,CE,bf,EE,Cf,Ef,vf,Tf,wf,vE,Rf,TE,Df,wE,Pf,RE,rt,kf,lS,Ko,$l,pn,uS,ns,hr,Ml,Fl,gS,pS,Ul,Nf,Ql,Bf,DE,PE,Wo,Jo,Xo,Hl,mn,Gl,Vl,is,Yo,Zo,xf,mS,fS,hS,kE,Of,_f,NE,AS,Lf,yS,SS,IS,BE,$f,fn,ql,Mf,xE,bS,ea,ta,jl,Ff,OE,zl,CS,Uf,_E,Qf,LE,Hf,$E};
|
|
7319
|
+
`}import{readFileSync as hs}from"node:fs";import{dirname as bs,join as Xn}from"node:path";import{fileURLToPath as Ss}from"node:url";function As(){return Xn(bs(Ss(import.meta.url)),"runtime-assets")}function fn(){let n=As(),i=(s)=>hs(Xn(n,s),"utf-8");return[{path:"bootstrap",contents:i("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:i("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:i("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:i("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:i("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:$f(),mode:420}]}function ql(n={}){let i=n.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:i,CACHE_DRIVER:i,SESSION_DRIVER:i,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 Mf=["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 ft}from"node:child_process";import{existsSync as Cs,mkdirSync as vs,mkdtempSync as Ts,readdirSync as Rs,readFileSync as Ps,rmSync as Es,statSync as er,writeFileSync as ws}from"node:fs";import{tmpdir as Is}from"node:os";import{join as Ge,relative as Ds}from"node:path";function*tr(n){for(let i of Rs(n)){let s=Ge(n,i);if(er(s).isDirectory())yield*tr(s);else yield s}}function xE(n={}){let i=n.architecture??"x86_64",s=n.platform??(i==="arm64"?"linux/arm64":"linux/amd64"),o=n.onStep??(()=>{}),c=Ts(Ge(Is(),"tscloud-php-layer-")),u="tscloud-php-layer:build";try{ws(Ge(c,"Dockerfile"),Nf(n)),o("Building PHP runtime image (docker)"),ft("docker",["build","--platform",s,"-t","tscloud-php-layer:build",c],{stdio:"inherit"}),o("Extracting /opt/php from image");let d=ft("docker",["create","--platform",s,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),p=Ge(c,"opt");vs(p,{recursive:!0});try{ft("docker",["cp",`${d}:/opt/php`,Ge(p,"php")],{stdio:"inherit"})}finally{ft("docker",["rm",d],{stdio:"ignore"})}if(!Cs(Ge(p,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let y=[];for(let A of tr(p)){let T=Ds(p,A).replace(/\\/g,"/"),R=er(A).mode&73?493:420;y.push({name:T,data:Ps(A),mode:R})}o("Injecting runtime assets");let h=new Set(fn().map((A)=>A.path)),b=y.filter((A)=>!h.has(A.name));for(let A of fn())b.push({name:A.path,data:A.contents,mode:A.mode});return o("Packaging layer ZIP"),{zip:nt(b),architecture:i,fileCount:b.length}}finally{Es(c,{recursive:!0,force:!0})}}import{execSync as Ns}from"node:child_process";import{createHash as xs}from"node:crypto";import{readdirSync as ks,readFileSync as Ms,statSync as nr}from"node:fs";import{join as Ls,relative as rr,resolve as Xt}from"node:path";var bS=[".git",".github","node_modules","tests","storage/logs","storage/framework/cache","storage/framework/sessions","storage/framework/views",".env",".env.local",".vapor",".ts-cloud","dist-lambda"];function Os(n,i){return i.some((s)=>n===s||n.startsWith(`${s}/`))}function*ir(n,i,s){for(let o of ks(n)){let c=Ls(n,o),u=rr(i,c).replace(/\\/g,"/");if(Os(u,s))continue;if(nr(c).isDirectory())yield*ir(c,i,s);else yield c}}function ea(n){if(n.skipBuild)return;let i=Xt(n.projectRoot??process.cwd()),s=n.app.build??Mf;for(let o of s)n.onStep?.(`build: ${o}`),Ns(o,{stdio:"inherit",cwd:i})}function ta(n,i=[]){let s=Xt(n),o=[...bS,cn(),...i],c=[];for(let u of ir(s,s,o)){let d=rr(s,u).replace(/\\/g,"/"),p=(nr(u).mode&73)!==0;c.push({name:d,data:Ms(u),mode:p?493:420})}return c}function jl(n){let i=Xt(n.projectRoot??process.cwd());ea(n),n.onStep?.("packaging application tree");let s=ta(i,n.exclude);if(!s.length)throw Error(`No files to package under ${i}`);let o=nt(s),c=n.app.handlers?.http??"public/index.php";return{zip:o,sha256:xs("sha256").update(o).digest("hex"),handlers:{http:c,queue:n.app.handlers?.queue??c,cli:n.app.handlers?.cli??c},fileCount:s.length}}class Ff{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(n){let i=`asset-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.optimizations.set(i,s),s}createImageOptimization(n){let i=`image-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.imageConfigs.set(i,s),s}createSSGConfig(n){let i=`ssg-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.ssgConfigs.set(i,s),s}createPrerenderConfig(n){let i=`prerender-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.prerenderConfigs.set(i,s),s}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 OE=new Ff;class zl{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(n,i){let s=`lifecycle-${Date.now()}-${this.counter++}`,o={id:s,transitions:n,expiration:i};return this.policies.set(s,o),o}enableVersioning(n=!1){let i=`versioning-${Date.now()}-${this.counter++}`,s={id:i,enabled:!0,mfaDelete:n};return this.versioningConfigs.set(i,s),s}createReplicationRule(n,i,s){let o=`replication-${Date.now()}-${this.counter++}`,c={id:o,sourceRegion:n,destRegion:i,destBucket:s};return this.replicationRules.set(o,c),c}createIntelligentTiering(n,i){let s=`tiering-${Date.now()}-${this.counter++}`,o={id:s,archiveDays:n,deepArchiveDays:i};return this.tieringConfigs.set(s,o),o}enableObjectLock(n){let i=`object-lock-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,mode:n.mode||"COMPLIANCE",retentionDays:n.retentionDays,retentionYears:n.retentionYears,legalHoldEnabled:n.legalHoldEnabled||!1};return this.objectLocks.set(i,s),s}enableTransferAcceleration(n){let i=`transfer-accel-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n,enabled:!0,endpoint:`${n}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(i,s),s}createAccessPoint(n){let i=`access-point-${Date.now()}-${this.counter++}`,s={id:i,name:n.name,bucketName:n.bucketName,vpcId:n.vpcId,publicAccessBlock:n.publicAccessBlock!==!1,policy:n.policy};return this.accessPoints.set(i,s),s}createGlacierArchive(n){let i=`glacier-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,archiveType:n.archiveType,transitionDays:n.transitionDays,restoreConfig:n.restoreTier?{tier:n.restoreTier,days:n.restoreDays||7}:void 0};return this.glacierConfigs.set(i,s),s}createInventory(n){let i=`inventory-${Date.now()}-${this.counter++}`,s={id:i,sourceBucket:n.sourceBucket,destinationBucket:n.destinationBucket,schedule:n.schedule||"Daily",format:n.format||"CSV",includedFields:n.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:n.prefix};return this.inventories.set(i,s),s}createBatchOperation(n){let i=`batch-op-${Date.now()}-${this.counter++}`,s={id:i,operation:n.operation,manifestBucket:n.manifestBucket,manifestKey:n.manifestKey,priority:n.priority||10,status:"pending"};return this.batchOps.set(i,s),s}executeBatchOperation(n){let i=this.batchOps.get(n);if(!i)throw Error(`Batch operation not found: ${n}`);return i.status="in_progress",i.totalObjects=1000,i.processedObjects=0,i}getBatchOperationStatus(n){return this.batchOps.get(n)}createLambdaNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"Lambda",arn:n.lambdaArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSQSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SQS",arn:n.queueArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSNSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SNS",arn:n.topicArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}generateObjectLockCF(n){let i={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:n.mode}}}};if(n.retentionDays)i.ObjectLockConfiguration.Rule.DefaultRetention.Days=n.retentionDays;if(n.retentionYears)i.ObjectLockConfiguration.Rule.DefaultRetention.Years=n.retentionYears;return i}generateTransferAccelerationCF(n){return{AccelerateConfiguration:{AccelerationStatus:n.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(n){return{Type:"AWS::S3::AccessPoint",Properties:{Name:n.name,Bucket:n.bucketName,...n.vpcId&&{VpcConfiguration:{VpcId:n.vpcId}},PublicAccessBlockConfiguration:n.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...n.policy&&{Policy:n.policy}}}}generateInventoryCF(n){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:n.id,Destination:{BucketArn:`arn:aws:s3:::${n.destinationBucket}`,Format:n.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:n.includedFields,ScheduleFrequency:n.schedule,...n.prefix&&{Prefix:n.prefix}}]}}}generateEventNotificationCF(n){let i=n.destination.type==="Lambda"?"LambdaConfigurations":n.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",s=n.destination.type==="Lambda"?"Function":n.destination.type==="SQS"?"Queue":"Topic",o={Event:n.events[0],[s]:n.destination.arn};if(n.filter)o.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};return{NotificationConfiguration:{[i]:[o]}}}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 CS=new zl;class Uf{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(n,i=30,s=10){let o=`health-${Date.now()}-${this.counter++}`,c={id:o,url:n,interval:i,timeout:s,status:"healthy"};return this.checks.set(o,c),c}createSyntheticMonitor(n,i,s,o){let c=`synthetic-${Date.now()}-${this.counter++}`,u={id:c,name:n,script:i,frequency:s,locations:o};return this.synthetics.set(c,u),u}trackUptime(n,i,s){let o=`uptime-${Date.now()}-${this.counter++}`,c=i/(i+s)*100,u={id:o,resource:n,uptime:i,downtime:s,availability:c};return this.uptimeTrackers.set(o,u),u}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var _E=new Uf;class Qf{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(n,i,s,o){let c=`waf-${Date.now()}-${this.counter++}`,u={id:c,name:n,priority:i,action:s,conditions:o};return this.wafRules.set(c,u),u}enableShield(n,i="standard"){let s=`shield-${Date.now()}-${this.counter++}`,o={id:s,resourceArn:n,protectionType:i};return this.shieldProtections.set(s,o),o}createSecurityGroup(n,i,s){let o=`sg-${Date.now()}-${this.counter++}`,c={id:o,name:n,vpcId:i,rules:s};return this.securityGroups.set(o,c),c}createNACL(n,i){let s=`nacl-${Date.now()}-${this.counter++}`,o={id:s,vpcId:n,rules:i};return this.nacls.set(s,o),o}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var LE=new Qf;class Hf{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(n,i){let s=`tagging-${Date.now()}-${this.counter++}`,o={id:s,tags:n,resources:i};return this.strategies.set(s,o),o}createCostAllocation(n,i){let s=`cost-${Date.now()}-${this.counter++}`,o={id:s,tagKey:n,allocations:i};return this.allocations.set(s,o),o}createResourceGroup(n,i,s){let o=`group-${Date.now()}-${this.counter++}`,c={id:o,name:n,query:{resourceTypeFilters:i,tagFilters:s}};return this.groups.set(o,c),c}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var $E=new Hf;export{LI,$I,rl,ym,nl,il,cn,Q,l,sl,Sm,K,ol,g,ty,C,Ye,Ji,dn,w,be,al,ry,r,t,MI,FI,m,UI,QI,HI,GI,VI,lr,cl,Xi,ny,qI,jI,xe,Ze,dl,Im,bm,zI,Cm,Em,vm,Qo,ll,ce,ln,Pt,Ho,kt,Ce,iy,ul,Go,Tm,wm,Rm,Dm,gl,KI,W,E,sy,oy,Pm,a,S,et,f,km,tt,J,Nt,WI,Nm,X,pl,Oe,ur,Vo,de,ml,le,ay,qo,Y,Z,_,Yi,D,gr,Bt,ee,e,un,JI,Bm,fl,XI,YI,ZI,eb,hl,tb,rb,nb,ib,sb,ob,ab,cb,db,lb,ub,gb,cy,dy,ly,uy,gy,py,my,pr,xm,Om,mr,Zi,pb,_m,mb,fb,gn,hb,Ab,yb,Sb,Ib,bb,fy,hy,Ay,yy,Sy,es,Cb,jo,Iy,Lm,V,by,rt,zo,xt,Cy,$m,Ey,vy,Ty,Mm,q,Eb,vb,Tb,wb,wy,Rb,te,Db,Pb,kb,Al,yl,Ry,Fm,Um,Nb,Bb,xb,Ob,_b,Dy,Sl,Lb,$b,Mb,Fb,Ub,Py,ky,Qb,Hb,Gb,Vb,qb,jb,zb,Ny,Kb,Qm,Il,Wb,Jb,Xb,Yb,Hm,Gm,Vm,Zb,bl,By,xy,Oy,_y,Cl,Ly,eC,tC,rC,nC,iC,sC,oC,$y,My,Fy,Uy,qm,aC,cC,dC,lC,uC,gC,pC,mC,fC,Qy,Hy,Gy,Vy,hC,AC,jm,yC,zm,Km,Wm,Jm,SC,IC,bC,CC,_e,ts,EC,vC,TC,wC,RC,DC,PC,kC,qy,NC,BC,Xm,Ym,xC,OC,jy,_C,LC,$C,MC,FC,UC,QC,HC,GC,VC,qC,jC,zC,KC,WC,JC,XC,YC,ZC,eE,tE,El,zy,vl,Ky,Tl,Wy,wl,Jy,Rl,Xy,fr,Yy,Dl,Zy,rs,eS,Pl,tS,kl,rS,Zm,rE,ef,nE,Nl,nS,hr,iS,tf,iE,Bl,sS,rf,sE,nf,oE,sf,aE,xl,oS,of,cE,af,dE,cf,lE,df,uE,Ol,aS,_l,cS,lf,gE,uf,pE,gf,mE,pf,fE,mf,hE,ff,AE,Ll,dS,hf,yE,Af,SE,yf,IE,Sf,bE,If,CE,bf,EE,Cf,Ef,vf,Tf,wf,vE,Rf,TE,Df,wE,Pf,RE,nt,kf,lS,Ko,$l,pn,uS,ns,Ar,Ml,Fl,gS,pS,Ul,Nf,Ql,Bf,DE,PE,Wo,Jo,Xo,Hl,mn,Gl,Vl,is,Yo,Zo,xf,mS,fS,hS,kE,Of,_f,NE,AS,Lf,yS,SS,IS,BE,$f,fn,ql,Mf,xE,bS,ea,ta,jl,Ff,OE,zl,CS,Uf,_E,Qf,LE,Hf,$E};
|