@stacksjs/ts-cloud 0.16.73 → 0.16.74
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-kcgs4z6p.js → chunk-0sswdcvq.js} +1 -1
- package/dist/bin/{chunk-whecvra8.js → chunk-10z6s9nj.js} +2 -2
- package/dist/bin/{chunk-maes42nn.js → chunk-11xdxrp3.js} +75 -75
- package/dist/bin/chunk-1pj60edk.js +1 -0
- package/dist/bin/chunk-1qcztara.js +1 -0
- package/dist/bin/{chunk-s5gyhgw1.js → chunk-28a6yey5.js} +1 -1
- package/dist/bin/{chunk-8wvtmxpw.js → chunk-47yznk07.js} +1 -1
- package/dist/bin/{chunk-0g9ze9v3.js → chunk-613m8vf9.js} +1 -1
- package/dist/bin/{chunk-79n440fm.js → chunk-69j7md80.js} +8 -8
- package/dist/bin/{chunk-gsp1secn.js → chunk-6gspchrt.js} +1 -1
- package/dist/bin/{chunk-jnt0ypm6.js → chunk-8fspkmer.js} +8 -8
- package/dist/bin/{chunk-fvj9ktkm.js → chunk-9twr514q.js} +1 -1
- package/dist/bin/{chunk-9cqzzkrd.js → chunk-9zbfadg4.js} +1 -1
- package/dist/bin/{chunk-1c91h57k.js → chunk-c99xvba1.js} +3 -3
- package/dist/bin/{chunk-jk4v9sj1.js → chunk-cs2a075v.js} +4 -4
- package/dist/bin/chunk-cvet8kjp.js +1 -0
- package/dist/bin/{chunk-xt3jhs2k.js → chunk-e6kfkaxc.js} +1 -1
- package/dist/bin/{chunk-0sa000g6.js → chunk-eevqxagd.js} +94 -94
- package/dist/bin/{chunk-9362t52n.js → chunk-ekr2rzf6.js} +2 -2
- package/dist/bin/chunk-f80asgbh.js +1 -0
- package/dist/bin/{chunk-2j2xcq2h.js → chunk-fwcd0ef4.js} +1 -1
- package/dist/bin/{chunk-27t4ve22.js → chunk-gghy8mb4.js} +27 -27
- package/dist/bin/{chunk-jcbtp3aj.js → chunk-jh4ajbt1.js} +1 -1
- package/dist/bin/{chunk-00hq474q.js → chunk-qw5ch629.js} +1 -1
- package/dist/bin/{chunk-gwn9pezq.js → chunk-r5cpsqqk.js} +3 -3
- package/dist/bin/{chunk-efafd6hw.js → chunk-sfv47z62.js} +6 -6
- package/dist/bin/{chunk-8yv9ech5.js → chunk-t6njpv8j.js} +1 -1
- package/dist/bin/{chunk-efghc0tr.js → chunk-tvd5w8xq.js} +2 -2
- package/dist/bin/{chunk-erdkgb1d.js → chunk-w244mfsx.js} +2 -2
- package/dist/bin/{chunk-0k75pjkr.js → chunk-wkwcskhg.js} +1 -1
- package/dist/bin/{chunk-z7fnx9gx.js → chunk-yjmydj1w.js} +1 -1
- package/dist/bin/chunk-yqqx644v.js +1 -0
- package/dist/bin/{chunk-kb0yy9t1.js → chunk-zcq82zv1.js} +2 -2
- package/dist/bin/cli.js +212 -212
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-ms84y9kg.js → chunk-1ktv8jxf.js} +1 -1
- package/dist/{chunk-e32qtz2d.js → chunk-277enqjc.js} +78 -78
- package/dist/{chunk-rkashc9e.js → chunk-2r334egt.js} +1 -1
- package/dist/{chunk-2dffxn73.js → chunk-49raybtd.js} +1 -1
- package/dist/{chunk-1y1b1jy0.js → chunk-49rt1jbe.js} +1 -1
- package/dist/{chunk-ts2n068z.js → chunk-65fwpzeg.js} +14 -14
- package/dist/{chunk-vx5n4bhb.js → chunk-7qhcfnqf.js} +1 -1
- package/dist/{chunk-nx8dbae2.js → chunk-8ynkxbj6.js} +1 -1
- package/dist/{chunk-gssa1974.js → chunk-c2hvf1h5.js} +1 -1
- package/dist/chunk-c5pq3x7x.js +1 -0
- package/dist/{chunk-pydkxpf9.js → chunk-cfyn21gd.js} +1 -1
- package/dist/{chunk-3m5x6nrt.js → chunk-dq9g7cg9.js} +1 -1
- package/dist/{chunk-ysv0f0k5.js → chunk-ebb7j388.js} +1 -1
- package/dist/{chunk-0cd0mk3e.js → chunk-f4qv0c6w.js} +2 -2
- package/dist/{chunk-78xspqp6.js → chunk-fd6gsz34.js} +1 -1
- package/dist/chunk-fvad4wm8.js +1 -0
- package/dist/chunk-gc8r2gvd.js +1 -0
- package/dist/{chunk-3k9kdbsc.js → chunk-ggqxjcbe.js} +1 -1
- package/dist/chunk-k0scshn2.js +1 -0
- package/dist/{chunk-0nmtzbqn.js → chunk-mqr6s8wa.js} +1 -1
- package/dist/{chunk-65dddt6g.js → chunk-qcs3qkdf.js} +1 -1
- package/dist/{chunk-f4h7bn7y.js → chunk-s7gv665w.js} +86 -86
- package/dist/chunk-sacbxd79.js +1 -0
- package/dist/{chunk-v3z51fs0.js → chunk-ssywr12y.js} +1 -1
- package/dist/{chunk-1np2k92z.js → chunk-yqzc3a9m.js} +108 -108
- package/dist/{chunk-1eg5wsn2.js → chunk-z90dv6jx.js} +5 -5
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/index.js +39 -39
- package/dist/mail/index.js +1 -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 +6 -6
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +2 -2
- 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 +2 -2
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +2 -2
- package/dist/ui/server/capacity.html +5 -5
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +6 -6
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +6 -6
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +2 -2
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +5 -5
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +6 -6
- package/package.json +3 -3
- package/dist/bin/chunk-02kcxvf3.js +0 -1
- package/dist/bin/chunk-cq7gxt10.js +0 -1
- package/dist/bin/chunk-fy62gtke.js +0 -1
- package/dist/bin/chunk-h03hh7qw.js +0 -1
- package/dist/bin/chunk-jvwbq6j5.js +0 -1
- package/dist/chunk-2b4knhhy.js +0 -1
- package/dist/chunk-az9wzy1w.js +0 -1
- package/dist/chunk-g96mv4z5.js +0 -1
- package/dist/chunk-h3e1qc75.js +0 -1
- package/dist/chunk-qy8r2vwh.js +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import{Y,cs,_t,Nn}from"./chunk-bgjvxdds.js";import{rr,Gr}from"./chunk-7v68hpgc.js";var pl={};rr(pl,{default:()=>Dr,handler:()=>yt});var ml={};rr(ml,{default:()=>Nr,handler:()=>ft});var nd={};rr(nd,{EmailAnalyticsModule:()=>Je,EmailRules:()=>Ft,EmailScheduling:()=>$t,EmailSearch:()=>Lt,EmailTemplates:()=>Ce,EmailThreading:()=>Ot,SharedMailboxes:()=>Bt});var id={};rr(id,{default:()=>ms,handler:()=>ds});var od={};rr(od,{CallAnalytics:()=>Wt,CallRecording:()=>Gt,Callbacks:()=>it,IVRBuilder:()=>we});var sd={};rr(sd,{AbTesting:()=>me,LinkTracking:()=>Kt,MmsSupport:()=>Ht,SmsAnalytics:()=>Ut,SmsCampaigns:()=>Vt,SmsChatbot:()=>jt});var Tm={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}},Em={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}};import{isAbsolute as pt,join as Ye,relative as ur}from"node:path";var da=".ts-cloud",il="TS_CLOUD_STATE_DIR",gt=null;function ua(e){gt=e?.trim()||null}function pa(){return Boolean(process.env[il]?.trim()||gt)}function En(){return process.env[il]?.trim()||gt||da}function Ve(...e){return Ye(En(),...e)}function R(e,...n){let r=En();return pt(r)?Ye(r,...n):Ye(e,r,...n)}function ma(e,n=process.cwd()){let r=(s,a)=>{let c=ur(s,a);return c===""||!c.startsWith("..")&&!pt(c)},i=pt(e)?e:Ye(n,e);return r(R(n),i)}function ol(e){let n=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((i)=>i?.app!=null);return{server:n,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:n}=ol(e);return n?"serverless":"server"}function Fr(e){let{server:n,serverless:r}=ol(e);if(n&&r)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(e.mode==="server"&&r&&!n)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&n&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function A(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function dr(e){return typeof e==="object"&&e!==null?e:{}}function ou(e){return e===!0||typeof e==="object"&&e!==null}function mr(e,n){let r=n?e.environments?.[n]:void 0;if(r?.domain)return r.domain;let i=Object.values(e.sites??{}),s=e.sites?.main?.domain??i.find((a)=>a.domain)?.domain;if(s)return s;return`${e.project?.slug??"app"}.local`}function pr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function ne(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=dr(r),s=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),a=i.mode??(s==="production"?"server":"catcher"),c=a==="server",u=mr(e,n.environment),d=i.hostname??(c?`mail.${u}`:"localhost"),m=i.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=i.tls??{},y=g.enabled??c,f=!!(g.certPath&&g.keyPath),h=(i.accounts??[]).map((Q)=>({address:Q.address,password:Q.password,passwordPolicy:Q.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},C=i.dkim===!1?!1:i.dkim===!0||c,E=typeof i.webmail==="object"&&i.webmail!==null?i.webmail:{},w=i.webmail===!1?!1:E.enabled??!0,v=d.includes(".")&&!d.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(d),I=E.domain===!1?void 0:E.domain??(c&&v?d:void 0),D=E.tls??(I?!1:y),x=[...new Set(E.aliases??[])].filter((Q)=>Q!==I),L=i.spam??{},B=i.delivery??(c?"direct":"none"),O=i.expose??c,F=pr(d),V=[...new Set([d,...F?[F]:[],...i.domains??[]])],ce=E.attachments?.maxFileBytes??20971520,q=E.attachments?.maxTotalBytes??20971520,J=E.attachments?.maxCount??20,K=E.undoSendSeconds??10;for(let[Q,ge,Te]of[["maxFileBytes",ce,104857600],["maxTotalBytes",q,104857600],["maxCount",J,100],["undoSendSeconds",K,30]])if(!Number.isInteger(ge)||ge<0||ge>Te)throw Error(`Mail webmail ${Q} must be an integer from 0 to ${Te}`);return{enabled:ou(r),mode:a,version:i.version,hostname:d,domains:V,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:C,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:w,port:E.port??p.webmail,domain:I,aliases:x,tls:D,secureCookies:E.secureCookies??(!!I||D),attachmentMaxFileBytes:ce,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:B,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:L.enabled??c,enforce:L.enforce??!1,junkScore:L.junkScore??5,rejectScore:L.rejectScore??12,dnsbl:L.dnsbl??c,dnsblReject:L.dnsblReject??!1,greylist:L.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function jr(e){if(!e.enabled||!e.expose)return[];let n=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)n.push(e.webmail.port);return[...new Set(n)].sort((r,i)=>r-i)}function ga(e){if(!e.enabled)return{};let n=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(n)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let i=e.accounts[0];if(i)r.MAIL_USERNAME=i.address,r.MAIL_PASSWORD=i.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function Jo(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let n=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(n.map((r,i)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(r))throw Error(`Invalid mail webmail hostname: ${r}`);return[`__mail_webmail_${i}`,{domain:r,proxyTo:`localhost:${e.webmail.port}`}]}))}function le(e,n={}){let r=e.infrastructure?.compute?.proxy,i=ne(e,n);if(!i.enabled||!i.webmail.enabled||!i.webmail.domain)return r;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:i.tls.acmeEmail??`webmaster@${i.webmail.domain}`,...r}}function U(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class Xo{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,n){return this.template.Resources[e]=n,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,n){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=n,this}addOutput(e,n){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=n,this}addMetadata(e,n){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=n,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,n=0){let r=" ".repeat(n),i="";for(let[s,a]of Object.entries(e)){if(a===null||a===void 0)continue;if(typeof a==="object"&&!Array.isArray(a))i+=`${r}${s}:
|
|
1
|
+
import{Y,cs,_t,Nn}from"./chunk-bgjvxdds.js";import{rr,Gr}from"./chunk-7v68hpgc.js";var pl={};rr(pl,{default:()=>Dr,handler:()=>yt});var ml={};rr(ml,{default:()=>Nr,handler:()=>ft});var nd={};rr(nd,{EmailAnalyticsModule:()=>Je,EmailRules:()=>Ft,EmailScheduling:()=>$t,EmailSearch:()=>Lt,EmailTemplates:()=>Ce,EmailThreading:()=>Ot,SharedMailboxes:()=>Bt});var id={};rr(id,{default:()=>ms,handler:()=>ds});var od={};rr(od,{CallAnalytics:()=>Wt,CallRecording:()=>Gt,Callbacks:()=>it,IVRBuilder:()=>we});var sd={};rr(sd,{AbTesting:()=>me,LinkTracking:()=>Kt,MmsSupport:()=>Ht,SmsAnalytics:()=>Ut,SmsCampaigns:()=>Vt,SmsChatbot:()=>jt});var Tm={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}},Em={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}};import{isAbsolute as pt,join as Ye,relative as ur}from"node:path";var da=".ts-cloud",il="TS_CLOUD_STATE_DIR",gt=null;function ua(e){gt=e?.trim()||null}function pa(){return Boolean(process.env[il]?.trim()||gt)}function En(){return process.env[il]?.trim()||gt||da}function ze(...e){return Ye(En(),...e)}function I(e,...n){let r=En();return pt(r)?Ye(r,...n):Ye(e,r,...n)}function ma(e,n=process.cwd()){let r=(s,a)=>{let c=ur(s,a);return c===""||!c.startsWith("..")&&!pt(c)},i=pt(e)?e:Ye(n,e);return r(I(n),i)}function ol(e){let n=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((i)=>i?.app!=null);return{server:n,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:n}=ol(e);return n?"serverless":"server"}function Fr(e){let{server:n,serverless:r}=ol(e);if(n&&r)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(e.mode==="server"&&r&&!n)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&n&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function A(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function dr(e){return typeof e==="object"&&e!==null?e:{}}function ou(e){return e===!0||typeof e==="object"&&e!==null}function mr(e,n){let r=n?e.environments?.[n]:void 0;if(r?.domain)return r.domain;let i=Object.values(e.sites??{}),s=e.sites?.main?.domain??i.find((a)=>a.domain)?.domain;if(s)return s;return`${e.project?.slug??"app"}.local`}function pr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function ne(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=dr(r),s=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),a=i.mode??(s==="production"?"server":"catcher"),c=a==="server",u=mr(e,n.environment),d=i.hostname??(c?`mail.${u}`:"localhost"),m=i.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=i.tls??{},y=g.enabled??c,f=!!(g.certPath&&g.keyPath),h=(i.accounts??[]).map((Q)=>({address:Q.address,password:Q.password,passwordPolicy:Q.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},C=i.dkim===!1?!1:i.dkim===!0||c,P=typeof i.webmail==="object"&&i.webmail!==null?i.webmail:{},E=i.webmail===!1?!1:P.enabled??!0,v=d.includes(".")&&!d.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(d),w=P.domain===!1?void 0:P.domain??(c&&v?d:void 0),D=P.tls??(w?!1:y),x=[...new Set(P.aliases??[])].filter((Q)=>Q!==w),L=i.spam??{},B=i.delivery??(c?"direct":"none"),O=i.expose??c,F=pr(d),V=[...new Set([d,...F?[F]:[],...i.domains??[]])],ce=P.attachments?.maxFileBytes??20971520,q=P.attachments?.maxTotalBytes??20971520,J=P.attachments?.maxCount??20,K=P.undoSendSeconds??10;for(let[Q,ge,Te]of[["maxFileBytes",ce,104857600],["maxTotalBytes",q,104857600],["maxCount",J,100],["undoSendSeconds",K,30]])if(!Number.isInteger(ge)||ge<0||ge>Te)throw Error(`Mail webmail ${Q} must be an integer from 0 to ${Te}`);return{enabled:ou(r),mode:a,version:i.version,hostname:d,domains:V,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:C,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:E,port:P.port??p.webmail,domain:w,aliases:x,tls:D,secureCookies:P.secureCookies??(!!w||D),attachmentMaxFileBytes:ce,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:B,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:L.enabled??c,enforce:L.enforce??!1,junkScore:L.junkScore??5,rejectScore:L.rejectScore??12,dnsbl:L.dnsbl??c,dnsblReject:L.dnsblReject??!1,greylist:L.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function jr(e){if(!e.enabled||!e.expose)return[];let n=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)n.push(e.webmail.port);return[...new Set(n)].sort((r,i)=>r-i)}function ga(e){if(!e.enabled)return{};let n=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(n)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let i=e.accounts[0];if(i)r.MAIL_USERNAME=i.address,r.MAIL_PASSWORD=i.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function Jo(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let n=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(n.map((r,i)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(r))throw Error(`Invalid mail webmail hostname: ${r}`);return[`__mail_webmail_${i}`,{domain:r,proxyTo:`localhost:${e.webmail.port}`}]}))}function le(e,n={}){let r=e.infrastructure?.compute?.proxy,i=ne(e,n);if(!i.enabled||!i.webmail.enabled||!i.webmail.domain)return r;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:i.tls.acmeEmail??`webmaster@${i.webmail.domain}`,...r}}function U(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class Xo{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,n){return this.template.Resources[e]=n,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,n){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=n,this}addOutput(e,n){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=n,this}addMetadata(e,n){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=n,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,n=0){let r=" ".repeat(n),i="";for(let[s,a]of Object.entries(e)){if(a===null||a===void 0)continue;if(typeof a==="object"&&!Array.isArray(a))i+=`${r}${s}:
|
|
2
2
|
${this.convertToYAML(a,n+1)}`;else if(Array.isArray(a)){i+=`${r}${s}:
|
|
3
3
|
`;for(let c of a)if(typeof c==="object")i+=`${r} -
|
|
4
4
|
${this.convertToYAML(c,n+2)}`;else i+=`${r} - ${c}
|
|
5
5
|
`}else i+=`${r}${s}: ${a}
|
|
6
|
-
`}return i}}function su(e){let n=[],r=[],i=[];if(gr(e,n),e.Resources)yr(e.Resources,n,r);else n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)fr(e.Parameters,n,r);if(e.Outputs)hr(e.Outputs,n);br(e,n);let s=Sr(e);if(s.length>0)for(let a of s)n.push({path:"Resources",message:`Circular dependency detected: ${a.join(" → ")}`,severity:"error"});return Cr(e,r,i),{valid:n.length===0,errors:n,warnings:r,info:i}}function gr(e,n){if(!e.AWSTemplateFormatVersion)n.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")n.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function yr(e,n,r){let i=Object.keys(e);if(i.length===0){n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(i.length>500)r.push({path:"Resources",message:`Template contains ${i.length} resources (limit is 500)`,severity:"warning"});for(let s of i){let a=e[s];if(!/^[a-zA-Z0-9]+$/.test(s))n.push({path:`Resources.${s}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!a.Type)n.push({path:`Resources.${s}.Type`,message:"Resource Type is required",severity:"error"});else if(!a.Type.startsWith("AWS::")&&!a.Type.startsWith("Custom::"))n.push({path:`Resources.${s}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(a.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(a.DeletionPolicy))n.push({path:`Resources.${s}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!a.DeletionPolicy&&tn(a.Type))r.push({path:`Resources.${s}.DeletionPolicy`,message:`${a.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function fr(e,n,r){let i=Object.keys(e);if(i.length>200)r.push({path:"Parameters",message:`Template contains ${i.length} parameters (limit is 200)`,severity:"warning"});for(let s of i){let a=e[s];if(!a.Type)n.push({path:`Parameters.${s}.Type`,message:"Parameter Type is required",severity:"error"});let c=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(a.Type&&!c.includes(a.Type))n.push({path:`Parameters.${s}.Type`,message:`Invalid parameter type: ${a.Type}`,severity:"error"})}}function hr(e,n){let r=Object.keys(e);for(let i of r)if(!e[i].Value)n.push({path:`Outputs.${i}.Value`,message:"Output Value is required",severity:"error"})}function br(e,n){let r=e.Resources||{},i=e.Parameters||{},s=new Set(Object.keys(r)),a=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!s.has(m)&&!a.has(m)&&m!=="AWS::Region"&&m!=="AWS::AccountId"&&m!=="AWS::StackName"&&m!=="AWS::StackId"&&m!=="AWS::URLSuffix"&&m!=="AWS::Partition"&&m!=="AWS::NoValue")n.push({path:d,message:`Reference to non-existent resource or parameter: ${m}`,severity:"error"})}if(u["Fn::GetAtt"]){let m=u["Fn::GetAtt"];if(Array.isArray(m)&&m.length>=1){let p=m[0];if(!s.has(p))n.push({path:d,message:`GetAtt references non-existent resource: ${p}`,severity:"error"})}}for(let m in u)c(u[m],`${d}.${m}`)}for(let u in r)c(r[u],`Resources.${u}`);if(e.Outputs)for(let u in e.Outputs)c(e.Outputs[u],`Outputs.${u}`)}function Sr(e){let n=e.Resources||{},r=new Map;for(let u in n){let d=new Set,m=n[u];if(m.DependsOn)if(Array.isArray(m.DependsOn))m.DependsOn.forEach((g)=>d.add(g));else d.add(m.DependsOn);Ar(m).forEach((g)=>d.add(g)),r.set(u,d)}let i=[],s=new Set,a=new Set;function c(u,d){s.add(u),a.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!s.has(p))c(p,[...d]);else if(a.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}a.delete(u)}for(let u of r.keys())if(!s.has(u))c(u,[]);return i}function Ar(e){let n=new Set;function r(i){if(typeof i!=="object"||i===null)return;if(i.Ref&&typeof i.Ref==="string"){if(!i.Ref.startsWith("AWS::"))n.add(i.Ref)}if(i["Fn::GetAtt"]&&Array.isArray(i["Fn::GetAtt"]))n.add(i["Fn::GetAtt"][0]);for(let s in i)r(i[s])}return r(e),n}function tn(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function Cr(e,n,r){let i=e.Resources||{};if(!e.Description)r.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let s in i){let a=i[s],c=a.Properties;if(c&&!c.Tags&&vr(a.Type))r.push({path:`Resources.${s}`,message:`Consider adding Tags to ${a.Type}`,severity:"info"});if(tn(a.Type)){if(a.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${s}`,message:"S3 bucket should enable encryption",severity:"warning"});if(a.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${s}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function vr(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function au(e){let n=[],r=[],i=[],s=Buffer.byteLength(e,"utf8"),a=s/1024,c=51200,u=460800;if(s>460800)n.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(s>51200)r.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:n.length===0,errors:n,warnings:r,info:i}}function cu(e){let n=[],r=[],i=[],s=e.Resources||{},a=e.Parameters||{},c=e.Outputs||{};if(Object.keys(s).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(s).length} resources (limit is 500)`,severity:"error"});if(Object.keys(a).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(a).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(c).length>200)n.push({path:"Outputs",message:`Template has ${Object.keys(c).length} outputs (limit is 200)`,severity:"error"});return{valid:n.length===0,errors:n,warnings:r,info:i}}var P={Ref:(e)=>({Ref:e}),GetAtt:(e,n)=>({"Fn::GetAtt":[e,n]}),Sub:(e,n)=>{if(n)return{"Fn::Sub":[e,n]};return{"Fn::Sub":e}},Join:(e,n)=>({"Fn::Join":[e,n]}),Select:(e,n)=>({"Fn::Select":[e,n]}),Split:(e,n)=>({"Fn::Split":[e,n]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,n,r)=>({"Fn::If":[e,n,r]}),Equals:(e,n)=>({"Fn::Equals":[e,n]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},lu={AccountId:{Ref:"AWS::AccountId"},Region:{Ref:"AWS::Region"},StackId:{Ref:"AWS::StackId"},StackName:{Ref:"AWS::StackName"},NotificationARNs:{Ref:"AWS::NotificationARNs"},Partition:{Ref:"AWS::Partition"},URLSuffix:{Ref:"AWS::URLSuffix"},NoValue:{Ref:"AWS::NoValue"}};function l(e){let{slug:n,environment:r,resourceType:i,timestamp:s,suffix:a}=e,c=[n,r,i];if(s)c.push(s);if(a)c.push(a);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function wm(){return Date.now().toString()}function Am(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function T(e,n){return e.project.stackName??`${e.project.slug}-${n}`}function fa(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function ha(e,n){return`${e.project.slug}-${n}`}function ya(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function Rm(e,n,r,i){return i??`${e}-${n}-${r}`}function Im(e,n){return`${e}-${n}-deploy`}function $e(e,n){return`${e.project.slug}-${n}-app`}function ba(e,n){return`${e}-${n}-deployments`}function Bi(e,n){return`${e}-${n}-assets`}class du{nodes=new Map;addResource(e,n){let r=this.extractDependencies(n);this.nodes.set(e,{logicalId:e,resource:n,dependencies:r})}extractDependencies(e){let n=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((r)=>n.add(r));else n.add(e.DependsOn);return this.findReferences(e.Properties||{},n),n}findReferences(e,n){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))n.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))n.add(e["Fn::GetAtt"][0]);for(let r of Object.values(e))if(typeof r==="object")this.findReferences(r,n)}topologicalSort(){let e=[],n=new Set,r=new Set,i=(s)=>{if(n.has(s))return;if(r.has(s))throw Error(`Circular dependency detected: ${s}`);r.add(s);let a=this.nodes.get(s);if(a)for(let c of a.dependencies)i(c);r.delete(s),n.add(s),e.push(s)};for(let s of this.nodes.keys())i(s);return e}validate(){for(let[e,n]of this.nodes.entries())for(let r of n.dependencies)if(!this.nodes.has(r))throw Error(`Resource "${e}" depends on "${r}" which does not exist`)}getDependents(e){let n=[];for(let[r,i]of this.nodes.entries())if(i.dependencies.has(e))n.push(r);return n}}function Pm(e,n){let r=[],i=[],s=[],a=[],c=[],u=e.Resources||{},d=n.Resources||{},m=new Set([...Object.keys(u),...Object.keys(d)]);for(let g of m){let y=u[g],f=d[g];if(!y&&f)r.push({logicalId:g,action:"add",resourceType:f.Type});else if(y&&!f)i.push({logicalId:g,action:"remove",resourceType:y.Type});else if(y&&f)if(y.Type!==f.Type)a.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=nn(y.Properties||{},f.Properties||{});if(h.length>0)if(Tr(y.Type,h))a.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else s.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Rr([...i,...a,...s]);return{added:r,removed:i,updated:s,replaced:a,unchanged:c,summary:{totalChanges:r.length+i.length+s.length+a.length,requiresReplacement:a.length>0,dangerousChanges:p}}}function nn(e,n,r=""){let i=[],s=new Set([...Object.keys(e),...Object.keys(n)]);for(let a of s){let c=r?`${r}.${a}`:a,u=e[a],d=n[a];if(u===void 0&&d!==void 0)i.push({path:c,oldValue:void 0,newValue:d});else if(u!==void 0&&d===void 0)i.push({path:c,oldValue:u,newValue:void 0});else if(typeof u!==typeof d)i.push({path:c,oldValue:u,newValue:d});else if(typeof u==="object"&&u!==null)if(Array.isArray(u)&&Array.isArray(d)){if(JSON.stringify(u)!==JSON.stringify(d))i.push({path:c,oldValue:u,newValue:d})}else if(!Array.isArray(u)&&!Array.isArray(d)){let m=nn(u,d,c);i.push(...m)}else i.push({path:c,oldValue:u,newValue:d});else if(u!==d)i.push({path:c,oldValue:u,newValue:d})}return i}function Tr(e,n){let i={"AWS::S3::Bucket":new Set(["BucketName"]),"AWS::DynamoDB::Table":new Set(["TableName","KeySchema"]),"AWS::RDS::DBInstance":new Set(["DBInstanceIdentifier","DBName","Engine"]),"AWS::Lambda::Function":new Set(["FunctionName"]),"AWS::EC2::Instance":new Set(["ImageId","InstanceType","KeyName"]),"AWS::ECS::TaskDefinition":new Set(["Family","ContainerDefinitions"]),"AWS::ElastiCache::CacheCluster":new Set(["CacheNodeType","Engine"]),"AWS::CloudFront::Distribution":new Set([]),"AWS::Route53::HostedZone":new Set(["Name"]),"AWS::IAM::Role":new Set(["RoleName","Path"]),"AWS::KMS::Key":new Set(["KeyPolicy"]),"AWS::Cognito::UserPool":new Set(["UserPoolName"]),"AWS::OpenSearchService::Domain":new Set(["DomainName"])}[e];if(!i)return!1;for(let s of n){let a=s.path.split(".")[0];if(i.has(a))return!0}return!1}function Rr(e){let n=[];for(let r of e){if(r.action==="remove"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"||r.resourceType==="AWS::ElastiCache::CacheCluster"))n.push(`Removing ${r.resourceType} ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"))n.push(`Replacing ${r.resourceType} ${r.logicalId} - data loss risk!`);if((r.action==="remove"||r.action==="replace")&&r.resourceType==="AWS::S3::Bucket")n.push(`${r.action==="remove"?"Removing":"Replacing"} S3 bucket ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&r.resourceType==="AWS::EC2::Instance")n.push(`Replacing EC2 instance ${r.logicalId} - downtime expected`);if(r.action==="update"&&r.resourceType==="AWS::EC2::SecurityGroup")n.push(`Updating security group ${r.logicalId} - may affect connectivity`);if((r.action==="update"||r.action==="replace")&&(r.resourceType==="AWS::IAM::Role"||r.resourceType==="AWS::IAM::Policy"))n.push(`Modifying IAM ${r.resourceType.split("::")[2]} ${r.logicalId} - may affect permissions`)}return n}function Dm(e){let n=[];if(n.push(`=== Stack Update Analysis ===
|
|
6
|
+
`}return i}}function su(e){let n=[],r=[],i=[];if(gr(e,n),e.Resources)yr(e.Resources,n,r);else n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)fr(e.Parameters,n,r);if(e.Outputs)hr(e.Outputs,n);br(e,n);let s=Sr(e);if(s.length>0)for(let a of s)n.push({path:"Resources",message:`Circular dependency detected: ${a.join(" → ")}`,severity:"error"});return Cr(e,r,i),{valid:n.length===0,errors:n,warnings:r,info:i}}function gr(e,n){if(!e.AWSTemplateFormatVersion)n.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")n.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function yr(e,n,r){let i=Object.keys(e);if(i.length===0){n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(i.length>500)r.push({path:"Resources",message:`Template contains ${i.length} resources (limit is 500)`,severity:"warning"});for(let s of i){let a=e[s];if(!/^[a-zA-Z0-9]+$/.test(s))n.push({path:`Resources.${s}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!a.Type)n.push({path:`Resources.${s}.Type`,message:"Resource Type is required",severity:"error"});else if(!a.Type.startsWith("AWS::")&&!a.Type.startsWith("Custom::"))n.push({path:`Resources.${s}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(a.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(a.DeletionPolicy))n.push({path:`Resources.${s}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!a.DeletionPolicy&&tn(a.Type))r.push({path:`Resources.${s}.DeletionPolicy`,message:`${a.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function fr(e,n,r){let i=Object.keys(e);if(i.length>200)r.push({path:"Parameters",message:`Template contains ${i.length} parameters (limit is 200)`,severity:"warning"});for(let s of i){let a=e[s];if(!a.Type)n.push({path:`Parameters.${s}.Type`,message:"Parameter Type is required",severity:"error"});let c=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(a.Type&&!c.includes(a.Type))n.push({path:`Parameters.${s}.Type`,message:`Invalid parameter type: ${a.Type}`,severity:"error"})}}function hr(e,n){let r=Object.keys(e);for(let i of r)if(!e[i].Value)n.push({path:`Outputs.${i}.Value`,message:"Output Value is required",severity:"error"})}function br(e,n){let r=e.Resources||{},i=e.Parameters||{},s=new Set(Object.keys(r)),a=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!s.has(m)&&!a.has(m)&&m!=="AWS::Region"&&m!=="AWS::AccountId"&&m!=="AWS::StackName"&&m!=="AWS::StackId"&&m!=="AWS::URLSuffix"&&m!=="AWS::Partition"&&m!=="AWS::NoValue")n.push({path:d,message:`Reference to non-existent resource or parameter: ${m}`,severity:"error"})}if(u["Fn::GetAtt"]){let m=u["Fn::GetAtt"];if(Array.isArray(m)&&m.length>=1){let p=m[0];if(!s.has(p))n.push({path:d,message:`GetAtt references non-existent resource: ${p}`,severity:"error"})}}for(let m in u)c(u[m],`${d}.${m}`)}for(let u in r)c(r[u],`Resources.${u}`);if(e.Outputs)for(let u in e.Outputs)c(e.Outputs[u],`Outputs.${u}`)}function Sr(e){let n=e.Resources||{},r=new Map;for(let u in n){let d=new Set,m=n[u];if(m.DependsOn)if(Array.isArray(m.DependsOn))m.DependsOn.forEach((g)=>d.add(g));else d.add(m.DependsOn);Ar(m).forEach((g)=>d.add(g)),r.set(u,d)}let i=[],s=new Set,a=new Set;function c(u,d){s.add(u),a.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!s.has(p))c(p,[...d]);else if(a.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}a.delete(u)}for(let u of r.keys())if(!s.has(u))c(u,[]);return i}function Ar(e){let n=new Set;function r(i){if(typeof i!=="object"||i===null)return;if(i.Ref&&typeof i.Ref==="string"){if(!i.Ref.startsWith("AWS::"))n.add(i.Ref)}if(i["Fn::GetAtt"]&&Array.isArray(i["Fn::GetAtt"]))n.add(i["Fn::GetAtt"][0]);for(let s in i)r(i[s])}return r(e),n}function tn(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function Cr(e,n,r){let i=e.Resources||{};if(!e.Description)r.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let s in i){let a=i[s],c=a.Properties;if(c&&!c.Tags&&vr(a.Type))r.push({path:`Resources.${s}`,message:`Consider adding Tags to ${a.Type}`,severity:"info"});if(tn(a.Type)){if(a.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${s}`,message:"S3 bucket should enable encryption",severity:"warning"});if(a.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${s}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function vr(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function au(e){let n=[],r=[],i=[],s=Buffer.byteLength(e,"utf8"),a=s/1024,c=51200,u=460800;if(s>460800)n.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(s>51200)r.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:n.length===0,errors:n,warnings:r,info:i}}function cu(e){let n=[],r=[],i=[],s=e.Resources||{},a=e.Parameters||{},c=e.Outputs||{};if(Object.keys(s).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(s).length} resources (limit is 500)`,severity:"error"});if(Object.keys(a).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(a).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(c).length>200)n.push({path:"Outputs",message:`Template has ${Object.keys(c).length} outputs (limit is 200)`,severity:"error"});return{valid:n.length===0,errors:n,warnings:r,info:i}}var R={Ref:(e)=>({Ref:e}),GetAtt:(e,n)=>({"Fn::GetAtt":[e,n]}),Sub:(e,n)=>{if(n)return{"Fn::Sub":[e,n]};return{"Fn::Sub":e}},Join:(e,n)=>({"Fn::Join":[e,n]}),Select:(e,n)=>({"Fn::Select":[e,n]}),Split:(e,n)=>({"Fn::Split":[e,n]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,n,r)=>({"Fn::If":[e,n,r]}),Equals:(e,n)=>({"Fn::Equals":[e,n]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},lu={AccountId:{Ref:"AWS::AccountId"},Region:{Ref:"AWS::Region"},StackId:{Ref:"AWS::StackId"},StackName:{Ref:"AWS::StackName"},NotificationARNs:{Ref:"AWS::NotificationARNs"},Partition:{Ref:"AWS::Partition"},URLSuffix:{Ref:"AWS::URLSuffix"},NoValue:{Ref:"AWS::NoValue"}};function l(e){let{slug:n,environment:r,resourceType:i,timestamp:s,suffix:a}=e,c=[n,r,i];if(s)c.push(s);if(a)c.push(a);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function wm(){return Date.now().toString()}function Am(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function T(e,n){return e.project.stackName??`${e.project.slug}-${n}`}function fa(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function ha(e,n){return`${e.project.slug}-${n}`}function ya(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function Rm(e,n,r,i){return i??`${e}-${n}-${r}`}function Im(e,n){return`${e}-${n}-deploy`}function $e(e,n){return`${e.project.slug}-${n}-app`}function ba(e,n){return`${e}-${n}-deployments`}function Bi(e,n){return`${e}-${n}-assets`}class du{nodes=new Map;addResource(e,n){let r=this.extractDependencies(n);this.nodes.set(e,{logicalId:e,resource:n,dependencies:r})}extractDependencies(e){let n=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((r)=>n.add(r));else n.add(e.DependsOn);return this.findReferences(e.Properties||{},n),n}findReferences(e,n){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))n.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))n.add(e["Fn::GetAtt"][0]);for(let r of Object.values(e))if(typeof r==="object")this.findReferences(r,n)}topologicalSort(){let e=[],n=new Set,r=new Set,i=(s)=>{if(n.has(s))return;if(r.has(s))throw Error(`Circular dependency detected: ${s}`);r.add(s);let a=this.nodes.get(s);if(a)for(let c of a.dependencies)i(c);r.delete(s),n.add(s),e.push(s)};for(let s of this.nodes.keys())i(s);return e}validate(){for(let[e,n]of this.nodes.entries())for(let r of n.dependencies)if(!this.nodes.has(r))throw Error(`Resource "${e}" depends on "${r}" which does not exist`)}getDependents(e){let n=[];for(let[r,i]of this.nodes.entries())if(i.dependencies.has(e))n.push(r);return n}}function Pm(e,n){let r=[],i=[],s=[],a=[],c=[],u=e.Resources||{},d=n.Resources||{},m=new Set([...Object.keys(u),...Object.keys(d)]);for(let g of m){let y=u[g],f=d[g];if(!y&&f)r.push({logicalId:g,action:"add",resourceType:f.Type});else if(y&&!f)i.push({logicalId:g,action:"remove",resourceType:y.Type});else if(y&&f)if(y.Type!==f.Type)a.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=nn(y.Properties||{},f.Properties||{});if(h.length>0)if(Tr(y.Type,h))a.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else s.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Rr([...i,...a,...s]);return{added:r,removed:i,updated:s,replaced:a,unchanged:c,summary:{totalChanges:r.length+i.length+s.length+a.length,requiresReplacement:a.length>0,dangerousChanges:p}}}function nn(e,n,r=""){let i=[],s=new Set([...Object.keys(e),...Object.keys(n)]);for(let a of s){let c=r?`${r}.${a}`:a,u=e[a],d=n[a];if(u===void 0&&d!==void 0)i.push({path:c,oldValue:void 0,newValue:d});else if(u!==void 0&&d===void 0)i.push({path:c,oldValue:u,newValue:void 0});else if(typeof u!==typeof d)i.push({path:c,oldValue:u,newValue:d});else if(typeof u==="object"&&u!==null)if(Array.isArray(u)&&Array.isArray(d)){if(JSON.stringify(u)!==JSON.stringify(d))i.push({path:c,oldValue:u,newValue:d})}else if(!Array.isArray(u)&&!Array.isArray(d)){let m=nn(u,d,c);i.push(...m)}else i.push({path:c,oldValue:u,newValue:d});else if(u!==d)i.push({path:c,oldValue:u,newValue:d})}return i}function Tr(e,n){let i={"AWS::S3::Bucket":new Set(["BucketName"]),"AWS::DynamoDB::Table":new Set(["TableName","KeySchema"]),"AWS::RDS::DBInstance":new Set(["DBInstanceIdentifier","DBName","Engine"]),"AWS::Lambda::Function":new Set(["FunctionName"]),"AWS::EC2::Instance":new Set(["ImageId","InstanceType","KeyName"]),"AWS::ECS::TaskDefinition":new Set(["Family","ContainerDefinitions"]),"AWS::ElastiCache::CacheCluster":new Set(["CacheNodeType","Engine"]),"AWS::CloudFront::Distribution":new Set([]),"AWS::Route53::HostedZone":new Set(["Name"]),"AWS::IAM::Role":new Set(["RoleName","Path"]),"AWS::KMS::Key":new Set(["KeyPolicy"]),"AWS::Cognito::UserPool":new Set(["UserPoolName"]),"AWS::OpenSearchService::Domain":new Set(["DomainName"])}[e];if(!i)return!1;for(let s of n){let a=s.path.split(".")[0];if(i.has(a))return!0}return!1}function Rr(e){let n=[];for(let r of e){if(r.action==="remove"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"||r.resourceType==="AWS::ElastiCache::CacheCluster"))n.push(`Removing ${r.resourceType} ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"))n.push(`Replacing ${r.resourceType} ${r.logicalId} - data loss risk!`);if((r.action==="remove"||r.action==="replace")&&r.resourceType==="AWS::S3::Bucket")n.push(`${r.action==="remove"?"Removing":"Replacing"} S3 bucket ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&r.resourceType==="AWS::EC2::Instance")n.push(`Replacing EC2 instance ${r.logicalId} - downtime expected`);if(r.action==="update"&&r.resourceType==="AWS::EC2::SecurityGroup")n.push(`Updating security group ${r.logicalId} - may affect connectivity`);if((r.action==="update"||r.action==="replace")&&(r.resourceType==="AWS::IAM::Role"||r.resourceType==="AWS::IAM::Policy"))n.push(`Modifying IAM ${r.resourceType.split("::")[2]} ${r.logicalId} - may affect permissions`)}return n}function Dm(e){let n=[];if(n.push(`=== Stack Update Analysis ===
|
|
7
7
|
`),e.summary.totalChanges===0)return n.push(`No changes detected.
|
|
8
8
|
`),n.join(`
|
|
9
9
|
`);if(n.push(`Total changes: ${e.summary.totalChanges}`),n.push(`Requires replacement: ${e.summary.requiresReplacement?"Yes":"No"}
|
|
10
10
|
`),e.summary.dangerousChanges.length>0){n.push("⚠️ DANGEROUS CHANGES DETECTED:");for(let r of e.summary.dangerousChanges)n.push(` • ${r}`);n.push("")}if(e.added.length>0){n.push(`✅ Resources to Add (${e.added.length}):`);for(let r of e.added)n.push(` + ${r.logicalId} (${r.resourceType})`);n.push("")}if(e.removed.length>0){n.push(`❌ Resources to Remove (${e.removed.length}):`);for(let r of e.removed)n.push(` - ${r.logicalId} (${r.resourceType})`);n.push("")}if(e.replaced.length>0){n.push(`\uD83D\uDD04 Resources to Replace (${e.replaced.length}):`);for(let r of e.replaced){if(n.push(` ~ ${r.logicalId} (${r.resourceType})`),r.reason)n.push(` Reason: ${r.reason}`);if(r.changes){for(let i of r.changes.slice(0,3))n.push(` • ${i.path}: ${JSON.stringify(i.oldValue)} → ${JSON.stringify(i.newValue)}`);if(r.changes.length>3)n.push(` ... and ${r.changes.length-3} more changes`)}}n.push("")}if(e.updated.length>0){n.push(`\uD83D\uDCDD Resources to Update (${e.updated.length}):`);for(let r of e.updated)if(n.push(` ~ ${r.logicalId} (${r.resourceType})`),r.changes){for(let i of r.changes.slice(0,3))n.push(` • ${i.path}: ${JSON.stringify(i.oldValue)} → ${JSON.stringify(i.newValue)}`);if(r.changes.length>3)n.push(` ... and ${r.changes.length-3} more changes`)}n.push("")}if(e.unchanged.length>0)n.push(`⚪ Unchanged Resources (${e.unchanged.length})`);return n.join(`
|
|
11
|
-
`)}import{existsSync as _e,readdirSync as Pr}from"node:fs";import{join as de}from"node:path";class ze{static createBucket(e){let{name:n,bucketName:r,slug:i,environment:s,public:a=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,y=r??l({slug:i,environment:s,resourceType:"s3",suffix:n}),f=o(y),h={Type:"AWS::S3::Bucket",Properties:{BucketName:y}};if(d)h.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(c)h.Properties.VersioningConfiguration={Status:"Enabled"};if(u)h.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!a)h.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(p&&p.length>0)h.Properties.CorsConfiguration={CorsRules:p.map((C)=>({AllowedOrigins:C.allowedOrigins,AllowedMethods:C.allowedMethods,AllowedHeaders:C.allowedHeaders,MaxAge:C.maxAge}))};if(g&&g.length>0)h.Properties.LifecycleConfiguration={Rules:g.map((C)=>({Id:C.id,Status:C.enabled?"Enabled":"Disabled",ExpirationInDays:C.expirationDays,Transitions:C.transitions?.map((E)=>({TransitionInDays:E.days,StorageClass:E.storageClass}))}))};if(m&&g){let C={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!h.Properties.LifecycleConfiguration)h.Properties.LifecycleConfiguration={Rules:[]};h.Properties.LifecycleConfiguration.Rules.push({Id:C.id,Status:"Enabled",Transitions:C.transitions?.map((E)=>({TransitionInDays:E.days,StorageClass:E.storageClass}))})}let S;if(a)S={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(f),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(f,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:S,logicalId:f}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,n="index.html",r="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:n,ErrorDocument:r},e}static setLifecycleRules(e,n){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:n.map((r)=>({Id:r.id,Status:r.enabled?"Enabled":"Disabled",ExpirationInDays:r.expirationDays,Transitions:r.transitions?.map((i)=>({TransitionInDays:i.days,StorageClass:i.storageClass}))}))},e}static enableIntelligentTiering(e){if(!e.Properties)e.Properties={};if(!e.Properties.LifecycleConfiguration)e.Properties.LifecycleConfiguration={Rules:[]};return e.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),e}static addLambdaNotification(e,n){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let r={Event:n.events[0],Function:n.functionArn};if(n.filter)r.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};for(let i of n.events){let s={...r,Event:i};e.Properties.NotificationConfiguration.LambdaConfigurations.push(s)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n,suffix:".jpg"}}),onFileType:(e,n,r)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:r,suffix:n}}),onFolderUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n.endsWith("/")?n:`${n}/`}})};static createBackupPlan(e){let{name:n,slug:r,environment:i,bucketLogicalIds:s,retentionDays:a,schedule:c="cron(0 5 * * ? *)",vaultName:u,enableContinuousBackup:d=!1,moveToColdStorageAfterDays:m}=e,p=u||l({slug:r,environment:i,resourceType:"backup-vault",suffix:n}),g=o(p),y={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:p}},f=l({slug:r,environment:i,resourceType:"backup-role",suffix:n}),h=o(f),S={Type:"AWS::IAM::Role",Properties:{RoleName:f,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},C=l({slug:r,environment:i,resourceType:"backup-plan",suffix:n}),E=o(C),w={DeleteAfterDays:a};if(m&&m<a)w.MoveToColdStorageAfterDays=m;let v={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:C,BackupPlanRule:[{RuleName:`${n}-daily-backup`,TargetBackupVault:P.Ref(g),ScheduleExpression:c,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:w,EnableContinuousBackup:d}]}}},I=l({slug:r,environment:i,resourceType:"backup-selection",suffix:n}),D=o(I),x=s.map((B)=>P.GetAtt(B,"Arn")),L={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:P.Ref(E),BackupSelection:{SelectionName:I,IamRoleArn:P.GetAtt(h,"Arn"),Resources:x}}};return{vault:y,plan:v,selection:L,role:S,vaultLogicalId:g,planLogicalId:E,selectionLogicalId:D,roleLogicalId:h}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"www-redirect"}),u=o(c),d={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},m={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:d,bucketPolicy:m,logicalId:u}}static createDocsBucket(e){let{slug:n,environment:r,domain:i}=e,s=i||l({slug:n,environment:r,resourceType:"s3",suffix:"docs"}),a=o(s);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:s,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:a}}static createEmailBucket(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"s3",suffix:"email"}),s=o(i),a={Type:"AWS::S3::Bucket",Properties:{BucketName:i,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},c={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(s),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:P.Join("",[P.GetAtt(s,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":P.Ref("AWS::AccountId")}}}]}}};return{bucket:a,bucketPolicy:c,logicalId:s}}static docsExist(e={}){let{projectRoot:n=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let i of r){let s=de(n,i);if(_e(s)){let a=["dist","build",".bunpress/dist","_site","out","public"];for(let c of a){let u=de(s,c);if(_e(u))try{if(Pr(u).length>0)return{exists:!0,path:s,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:s,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let n=ze.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!n.exists)return{bucket:null,logicalId:null,docsInfo:n};let r=ze.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:r.bucket,bucketPolicy:r.bucketPolicy,logicalId:r.logicalId,docsInfo:n}}static createPrivateBucket(e){let{slug:n,environment:r,enableVersioning:i=!0,retentionDays:s,encryptionKeyArn:a}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"private"}),u=o(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:a?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:a}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:i?{Status:"Enabled"}:void 0,LifecycleConfiguration:s?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:s}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:u}}static checkSourcePaths(e={}){let{projectRoot:n=process.cwd(),paths:r={}}=e,i=r.web||"views/web/dist",s=r.docs||"docs/dist",a=r.private||"private";return{web:{exists:_e(de(n,i)),path:de(n,i)},docs:{exists:_e(de(n,s)),path:de(n,s)},private:{exists:_e(de(n,a)),path:de(n,a)}}}static createDeploymentBuckets(e){let{slug:n,environment:r,domain:i,projectRoot:s,paths:a}=e,c=ze.checkSourcePaths({projectRoot:s,paths:a}),u={},d={web:!1,docs:!1,private:!1},m=ze.createBucket({name:"web",slug:n,environment:r,public:!1,versioning:!1,encryption:!0});if(u[m.logicalId]=m.bucket,d.web=!0,c.docs.exists){let p=ze.createDocsBucket({slug:n,environment:r,domain:i?`docs.${i}`:void 0});if(u[p.logicalId]=p.bucket,p.bucketPolicy)u[`${p.logicalId}Policy`]=p.bucketPolicy;d.docs=!0}if(c.private.exists){let p=ze.createPrivateBucket({slug:n,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class Pt{static createRepository(e){let{name:n,slug:r,environment:i,scanOnPush:s=!0,imageMutability:a="MUTABLE",encryption:c="AES256",kmsKey:u,lifecyclePolicy:d,tags:m}=e,p=l({slug:r,environment:i,resourceType:"ecr",suffix:n}),g=o(p),y={Type:"AWS::ECR::Repository",Properties:{RepositoryName:p,ImageTagMutability:a,ImageScanningConfiguration:{ScanOnPush:s},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)y.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Pt.generateLifecyclePolicy(d))};if(m)y.Properties.Tags=Object.entries(m).map(([f,h])=>({Key:f,Value:h}));return{repository:y,logicalId:g}}static generateLifecyclePolicy(e){let n=[];if(e.untaggedImageExpireDays!==void 0)n.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(e.maxImageCount!==void 0)n.push({rulePriority:n.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)n.push({rulePriority:n.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:n}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(e){if(!e.Properties)e.Properties={};return e.Properties.ImageTagMutability="IMMUTABLE",e}static enableScanOnPush(e){if(!e.Properties)e.Properties={};return e.Properties.ImageScanningConfiguration={ScanOnPush:!0},e}static setLifecyclePolicy(e,n){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Pt.generateLifecyclePolicy(n))},e}static addCrossAccountAccess(e,n){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:n.map((r)=>`arn:aws:iam::${r}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:n="oven/bun:1-debian",serverPath:r,port:i=3000,additionalDirs:s=[],healthCheckEndpoint:a="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...s],g=m||`bun run ${r}`,y=`# Multi-stage build for Bun application
|
|
11
|
+
`)}import{existsSync as _e,readdirSync as Pr}from"node:fs";import{join as de}from"node:path";class He{static createBucket(e){let{name:n,bucketName:r,slug:i,environment:s,public:a=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,y=r??l({slug:i,environment:s,resourceType:"s3",suffix:n}),f=o(y),h={Type:"AWS::S3::Bucket",Properties:{BucketName:y}};if(d)h.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(c)h.Properties.VersioningConfiguration={Status:"Enabled"};if(u)h.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!a)h.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(p&&p.length>0)h.Properties.CorsConfiguration={CorsRules:p.map((C)=>({AllowedOrigins:C.allowedOrigins,AllowedMethods:C.allowedMethods,AllowedHeaders:C.allowedHeaders,MaxAge:C.maxAge}))};if(g&&g.length>0)h.Properties.LifecycleConfiguration={Rules:g.map((C)=>({Id:C.id,Status:C.enabled?"Enabled":"Disabled",ExpirationInDays:C.expirationDays,Transitions:C.transitions?.map((P)=>({TransitionInDays:P.days,StorageClass:P.storageClass}))}))};if(m&&g){let C={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!h.Properties.LifecycleConfiguration)h.Properties.LifecycleConfiguration={Rules:[]};h.Properties.LifecycleConfiguration.Rules.push({Id:C.id,Status:"Enabled",Transitions:C.transitions?.map((P)=>({TransitionInDays:P.days,StorageClass:P.storageClass}))})}let S;if(a)S={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:R.Ref(f),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[R.Join("",[R.GetAtt(f,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:S,logicalId:f}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,n="index.html",r="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:n,ErrorDocument:r},e}static setLifecycleRules(e,n){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:n.map((r)=>({Id:r.id,Status:r.enabled?"Enabled":"Disabled",ExpirationInDays:r.expirationDays,Transitions:r.transitions?.map((i)=>({TransitionInDays:i.days,StorageClass:i.storageClass}))}))},e}static enableIntelligentTiering(e){if(!e.Properties)e.Properties={};if(!e.Properties.LifecycleConfiguration)e.Properties.LifecycleConfiguration={Rules:[]};return e.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),e}static addLambdaNotification(e,n){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let r={Event:n.events[0],Function:n.functionArn};if(n.filter)r.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};for(let i of n.events){let s={...r,Event:i};e.Properties.NotificationConfiguration.LambdaConfigurations.push(s)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n,suffix:".jpg"}}),onFileType:(e,n,r)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:r,suffix:n}}),onFolderUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n.endsWith("/")?n:`${n}/`}})};static createBackupPlan(e){let{name:n,slug:r,environment:i,bucketLogicalIds:s,retentionDays:a,schedule:c="cron(0 5 * * ? *)",vaultName:u,enableContinuousBackup:d=!1,moveToColdStorageAfterDays:m}=e,p=u||l({slug:r,environment:i,resourceType:"backup-vault",suffix:n}),g=o(p),y={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:p}},f=l({slug:r,environment:i,resourceType:"backup-role",suffix:n}),h=o(f),S={Type:"AWS::IAM::Role",Properties:{RoleName:f,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},C=l({slug:r,environment:i,resourceType:"backup-plan",suffix:n}),P=o(C),E={DeleteAfterDays:a};if(m&&m<a)E.MoveToColdStorageAfterDays=m;let v={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:C,BackupPlanRule:[{RuleName:`${n}-daily-backup`,TargetBackupVault:R.Ref(g),ScheduleExpression:c,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:E,EnableContinuousBackup:d}]}}},w=l({slug:r,environment:i,resourceType:"backup-selection",suffix:n}),D=o(w),x=s.map((B)=>R.GetAtt(B,"Arn")),L={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:R.Ref(P),BackupSelection:{SelectionName:w,IamRoleArn:R.GetAtt(h,"Arn"),Resources:x}}};return{vault:y,plan:v,selection:L,role:S,vaultLogicalId:g,planLogicalId:P,selectionLogicalId:D,roleLogicalId:h}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"www-redirect"}),u=o(c),d={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},m={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:R.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[R.Join("",[R.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:d,bucketPolicy:m,logicalId:u}}static createDocsBucket(e){let{slug:n,environment:r,domain:i}=e,s=i||l({slug:n,environment:r,resourceType:"s3",suffix:"docs"}),a=o(s);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:s,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:a}}static createEmailBucket(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"s3",suffix:"email"}),s=o(i),a={Type:"AWS::S3::Bucket",Properties:{BucketName:i,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},c={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:R.Ref(s),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:R.Join("",[R.GetAtt(s,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":R.Ref("AWS::AccountId")}}}]}}};return{bucket:a,bucketPolicy:c,logicalId:s}}static docsExist(e={}){let{projectRoot:n=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let i of r){let s=de(n,i);if(_e(s)){let a=["dist","build",".bunpress/dist","_site","out","public"];for(let c of a){let u=de(s,c);if(_e(u))try{if(Pr(u).length>0)return{exists:!0,path:s,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:s,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let n=He.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!n.exists)return{bucket:null,logicalId:null,docsInfo:n};let r=He.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:r.bucket,bucketPolicy:r.bucketPolicy,logicalId:r.logicalId,docsInfo:n}}static createPrivateBucket(e){let{slug:n,environment:r,enableVersioning:i=!0,retentionDays:s,encryptionKeyArn:a}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"private"}),u=o(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:a?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:a}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:i?{Status:"Enabled"}:void 0,LifecycleConfiguration:s?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:s}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:u}}static checkSourcePaths(e={}){let{projectRoot:n=process.cwd(),paths:r={}}=e,i=r.web||"views/web/dist",s=r.docs||"docs/dist",a=r.private||"private";return{web:{exists:_e(de(n,i)),path:de(n,i)},docs:{exists:_e(de(n,s)),path:de(n,s)},private:{exists:_e(de(n,a)),path:de(n,a)}}}static createDeploymentBuckets(e){let{slug:n,environment:r,domain:i,projectRoot:s,paths:a}=e,c=He.checkSourcePaths({projectRoot:s,paths:a}),u={},d={web:!1,docs:!1,private:!1},m=He.createBucket({name:"web",slug:n,environment:r,public:!1,versioning:!1,encryption:!0});if(u[m.logicalId]=m.bucket,d.web=!0,c.docs.exists){let p=He.createDocsBucket({slug:n,environment:r,domain:i?`docs.${i}`:void 0});if(u[p.logicalId]=p.bucket,p.bucketPolicy)u[`${p.logicalId}Policy`]=p.bucketPolicy;d.docs=!0}if(c.private.exists){let p=He.createPrivateBucket({slug:n,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class Pt{static createRepository(e){let{name:n,slug:r,environment:i,scanOnPush:s=!0,imageMutability:a="MUTABLE",encryption:c="AES256",kmsKey:u,lifecyclePolicy:d,tags:m}=e,p=l({slug:r,environment:i,resourceType:"ecr",suffix:n}),g=o(p),y={Type:"AWS::ECR::Repository",Properties:{RepositoryName:p,ImageTagMutability:a,ImageScanningConfiguration:{ScanOnPush:s},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)y.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Pt.generateLifecyclePolicy(d))};if(m)y.Properties.Tags=Object.entries(m).map(([f,h])=>({Key:f,Value:h}));return{repository:y,logicalId:g}}static generateLifecyclePolicy(e){let n=[];if(e.untaggedImageExpireDays!==void 0)n.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(e.maxImageCount!==void 0)n.push({rulePriority:n.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)n.push({rulePriority:n.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:n}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(e){if(!e.Properties)e.Properties={};return e.Properties.ImageTagMutability="IMMUTABLE",e}static enableScanOnPush(e){if(!e.Properties)e.Properties={};return e.Properties.ImageScanningConfiguration={ScanOnPush:!0},e}static setLifecyclePolicy(e,n){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Pt.generateLifecyclePolicy(n))},e}static addCrossAccountAccess(e,n){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:n.map((r)=>`arn:aws:iam::${r}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:n="oven/bun:1-debian",serverPath:r,port:i=3000,additionalDirs:s=[],healthCheckEndpoint:a="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...s],g=m||`bun run ${r}`,y=`# Multi-stage build for Bun application
|
|
12
12
|
# Generated by ts-cloud
|
|
13
13
|
|
|
14
14
|
# Builder stage
|
|
@@ -91,7 +91,7 @@ echo "Image: $IMAGE_URI:${i}"
|
|
|
91
91
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
|
92
92
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest`},...e.ecsCluster&&e.ecsService?[{name:"Deploy to ECS",run:`aws ecs update-service --cluster ${e.ecsCluster} --service ${e.ecsService} --force-new-deployment`}]:[]]}}};return`# Generated by ts-cloud
|
|
93
93
|
${JSON.stringify(n,null,2).replace(/"/g,"").replace(/,\n/g,`
|
|
94
|
-
`)}`}};static DockerfileTemplates={bunServer:(e,n=3000)=>Pt.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>Pt.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>Pt.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>Pt.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var Sa=[400,403,404,416,429,500,502,503,504],sl=[500,502,503,504],al=["GET","HEAD","OPTIONS"],km="-failover-group",cl=["default","media-quality-based"],ll={min:1,max:3},dl={min:1,max:10};function Qo(e){if(e===void 0)return[...sl];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Sa.join(", ")}). Omit it to use the default ${sl.join(", ")}.`);let n=e.filter((r)=>!Sa.includes(r));if(n.length>0)throw Error(`CloudFront origin failover: ${n.join(", ")} ${n.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${Sa.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function va(e){let{primaryOriginId:n,secondaryOriginId:r}=e;if(!n||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(n===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${n}")`);let i=Qo(e.statusCodes);return rn(e.selectionCriteria),{Id:e.groupId??`${n}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:i.length,Items:i}},Members:{Quantity:2,Items:[{OriginId:n},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function rn(e,n="the origin group"){if(e===void 0)return;if(!cl.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${cl.join(", ")}.`)}function Ze(e,n,r){if(typeof e!=="number"||!Number.isInteger(e)||e<n.min||e>n.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${n.min} to ${n.max}, got ${JSON.stringify(e)}.`)}function ot(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)Ze(e.connectionAttempts,ll,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)Ze(e.connectionTimeout,dl,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Yo(e){return{Quantity:1,Items:[va(e)]}}function wn(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((s)=>!al.includes(s.toUpperCase()));if(i.length>0)throw Error(`CloudFront origin failover: ${n} allows ${i.join(", ")}, but a cache behavior that targets an origin group may only allow ${al.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Fi(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function We(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function ae(e){return typeof e==="string"?e:void 0}var Er=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function An(e,n="the distribution"){let r=We(e.Origins),i=new Set(r.map((p)=>ae(p.Id)).filter((p)=>!!p)),s=new Map(r.map((p)=>[ae(p.Id)??"",p.DomainName])),a=r.some((p)=>ae(p.Id)===void 0);for(let p of r){let g=ae(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)Ze(p.ConnectionAttempts,ll,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)Ze(p.ConnectionTimeout,dl,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=We(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${n} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=ae(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${n} has an origin group without an Id.`);let y=`${n} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${n} declares origin group "${g}" twice.`);if(i.has(g))throw Error(`CloudFront origin failover: ${y} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let f=p.Members,h=We(f);if(h.length!==2||f?.Quantity!==void 0&&f.Quantity!==h.length)throw Error(`CloudFront origin failover: ${y} must have exactly 2 members (a primary and a secondary), it has ${h.length}${f?.Quantity!==void 0&&f.Quantity!==h.length?` with Quantity ${f.Quantity}`:""}.`);let S=h.map((w)=>ae(w.OriginId));for(let w of S)if(w&&!i.has(w)&&!a)throw Error(`CloudFront origin failover: ${y} lists member "${w}", which is not an origin of this distribution. Origins: ${[...i].join(", ")||"(none)"}.`);if(S[0]&&S[0]===S[1])throw Error(`CloudFront origin failover: ${y} lists "${S[0]}" as both primary and secondary.`);let C=p.FailoverCriteria?.StatusCodes,E=We(C);if(Qo(E),C?.Quantity!==void 0&&C.Quantity!==E.length)throw Error(`CloudFront origin failover: ${y} FailoverCriteria.StatusCodes.Quantity is ${C.Quantity} but it lists ${E.length} code(s).`);if(rn(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let w of S){let v=w?ae(s.get(w)):void 0;if(v&&!Er.test(v))throw Error(`CloudFront origin failover: ${y} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${w}" is ${v}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of We(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let y=ae(p.TargetOriginId);if(!y)continue;if(d.has(y))wn(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!a&&u.every((f)=>ae(f.Id)!==void 0))throw Error(`CloudFront: ${g} of ${n} targets "${y}", which is neither an origin nor an origin group of this distribution.`)}}class He{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,y=l({slug:n,environment:r,resourceType:"cdn"}),f=o(y),h={Id:"DefaultOrigin",DomainName:i.domainName,OriginPath:i.originPath||"",...ot(i,"the CDN origin")},S;if(i.type==="s3"){let E=`${f}OAC`;S={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${y}-oac`,Description:`Origin Access Control for ${y}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},h.OriginAccessControlId=P.Ref(E)}else if(i.type==="alb"||i.type==="custom")h.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let C={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${y}`,DefaultRootObject:"index.html",Origins:[h],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:m?"http2and3":"http2"}}};if(s&&a)C.Properties.DistributionConfig.Aliases=[s],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:a,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)C.Properties.DistributionConfig.CustomErrorResponses=c.map((E)=>({ErrorCode:E.errorCode,ResponseCode:E.responseCode,ResponsePagePath:E.responsePagePath}));if(d&&d.length>0)C.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((E)=>({EventType:E.event,LambdaFunctionARN:E.functionArn}));if(g)He.addOriginFailover(C,g);return{distribution:C,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,s=i.TargetOriginId,a=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(wn(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===a))throw Error(`CloudFront origin failover: an origin with id "${a}" already exists`);let c=va({primaryOriginId:s,secondaryOriginId:a,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(Fi(n.domainName)?"s3":"custom"),d={Id:a,DomainName:n.domainName,OriginPath:n.originPath||"",...ot(n,"the failover origin")},m=ot(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===s);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===s);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},i.TargetOriginId=c.Id,An(r),e}static setCustomDomain(e,n,r){return e.Properties.DistributionConfig.Aliases=[n],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,n){return e.Properties.DistributionConfig.CustomErrorResponses=n.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,n,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:n,LambdaFunctionARN:r}),e}static setCachePolicy(e,n){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${n.default||86400}s)`,e}static createSpaDistribution(e){return He.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"edge-docs"}),s=o(i),a=o(`${i}-role`),c=o(`${i}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},d=`
|
|
94
|
+
`)}`}};static DockerfileTemplates={bunServer:(e,n=3000)=>Pt.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>Pt.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>Pt.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>Pt.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var Sa=[400,403,404,416,429,500,502,503,504],sl=[500,502,503,504],al=["GET","HEAD","OPTIONS"],km="-failover-group",cl=["default","media-quality-based"],ll={min:1,max:3},dl={min:1,max:10};function Qo(e){if(e===void 0)return[...sl];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Sa.join(", ")}). Omit it to use the default ${sl.join(", ")}.`);let n=e.filter((r)=>!Sa.includes(r));if(n.length>0)throw Error(`CloudFront origin failover: ${n.join(", ")} ${n.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${Sa.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function va(e){let{primaryOriginId:n,secondaryOriginId:r}=e;if(!n||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(n===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${n}")`);let i=Qo(e.statusCodes);return rn(e.selectionCriteria),{Id:e.groupId??`${n}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:i.length,Items:i}},Members:{Quantity:2,Items:[{OriginId:n},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function rn(e,n="the origin group"){if(e===void 0)return;if(!cl.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${cl.join(", ")}.`)}function Ze(e,n,r){if(typeof e!=="number"||!Number.isInteger(e)||e<n.min||e>n.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${n.min} to ${n.max}, got ${JSON.stringify(e)}.`)}function st(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)Ze(e.connectionAttempts,ll,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)Ze(e.connectionTimeout,dl,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Yo(e){return{Quantity:1,Items:[va(e)]}}function wn(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((s)=>!al.includes(s.toUpperCase()));if(i.length>0)throw Error(`CloudFront origin failover: ${n} allows ${i.join(", ")}, but a cache behavior that targets an origin group may only allow ${al.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Fi(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function We(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function ae(e){return typeof e==="string"?e:void 0}var Er=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function An(e,n="the distribution"){let r=We(e.Origins),i=new Set(r.map((p)=>ae(p.Id)).filter((p)=>!!p)),s=new Map(r.map((p)=>[ae(p.Id)??"",p.DomainName])),a=r.some((p)=>ae(p.Id)===void 0);for(let p of r){let g=ae(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)Ze(p.ConnectionAttempts,ll,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)Ze(p.ConnectionTimeout,dl,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=We(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${n} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=ae(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${n} has an origin group without an Id.`);let y=`${n} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${n} declares origin group "${g}" twice.`);if(i.has(g))throw Error(`CloudFront origin failover: ${y} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let f=p.Members,h=We(f);if(h.length!==2||f?.Quantity!==void 0&&f.Quantity!==h.length)throw Error(`CloudFront origin failover: ${y} must have exactly 2 members (a primary and a secondary), it has ${h.length}${f?.Quantity!==void 0&&f.Quantity!==h.length?` with Quantity ${f.Quantity}`:""}.`);let S=h.map((E)=>ae(E.OriginId));for(let E of S)if(E&&!i.has(E)&&!a)throw Error(`CloudFront origin failover: ${y} lists member "${E}", which is not an origin of this distribution. Origins: ${[...i].join(", ")||"(none)"}.`);if(S[0]&&S[0]===S[1])throw Error(`CloudFront origin failover: ${y} lists "${S[0]}" as both primary and secondary.`);let C=p.FailoverCriteria?.StatusCodes,P=We(C);if(Qo(P),C?.Quantity!==void 0&&C.Quantity!==P.length)throw Error(`CloudFront origin failover: ${y} FailoverCriteria.StatusCodes.Quantity is ${C.Quantity} but it lists ${P.length} code(s).`);if(rn(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let E of S){let v=E?ae(s.get(E)):void 0;if(v&&!Er.test(v))throw Error(`CloudFront origin failover: ${y} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${E}" is ${v}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of We(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let y=ae(p.TargetOriginId);if(!y)continue;if(d.has(y))wn(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!a&&u.every((f)=>ae(f.Id)!==void 0))throw Error(`CloudFront: ${g} of ${n} targets "${y}", which is neither an origin nor an origin group of this distribution.`)}}class Ge{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,y=l({slug:n,environment:r,resourceType:"cdn"}),f=o(y),h={Id:"DefaultOrigin",DomainName:i.domainName,OriginPath:i.originPath||"",...st(i,"the CDN origin")},S;if(i.type==="s3"){let P=`${f}OAC`;S={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${y}-oac`,Description:`Origin Access Control for ${y}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},h.OriginAccessControlId=R.Ref(P)}else if(i.type==="alb"||i.type==="custom")h.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let C={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${y}`,DefaultRootObject:"index.html",Origins:[h],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:m?"http2and3":"http2"}}};if(s&&a)C.Properties.DistributionConfig.Aliases=[s],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:a,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)C.Properties.DistributionConfig.CustomErrorResponses=c.map((P)=>({ErrorCode:P.errorCode,ResponseCode:P.responseCode,ResponsePagePath:P.responsePagePath}));if(d&&d.length>0)C.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((P)=>({EventType:P.event,LambdaFunctionARN:P.functionArn}));if(g)Ge.addOriginFailover(C,g);return{distribution:C,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,s=i.TargetOriginId,a=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(wn(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===a))throw Error(`CloudFront origin failover: an origin with id "${a}" already exists`);let c=va({primaryOriginId:s,secondaryOriginId:a,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(Fi(n.domainName)?"s3":"custom"),d={Id:a,DomainName:n.domainName,OriginPath:n.originPath||"",...st(n,"the failover origin")},m=st(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===s);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===s);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},i.TargetOriginId=c.Id,An(r),e}static setCustomDomain(e,n,r){return e.Properties.DistributionConfig.Aliases=[n],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,n){return e.Properties.DistributionConfig.CustomErrorResponses=n.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,n,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:n,LambdaFunctionARN:r}),e}static setCachePolicy(e,n){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${n.default||86400}s)`,e}static createSpaDistribution(e){return Ge.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"edge-docs"}),s=o(i),a=o(`${i}-role`),c=o(`${i}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},d=`
|
|
95
95
|
'use strict';
|
|
96
96
|
|
|
97
97
|
exports.handler = async (event) => {
|
|
@@ -124,7 +124,7 @@ exports.handler = async (event) => {
|
|
|
124
124
|
|
|
125
125
|
return request;
|
|
126
126
|
};
|
|
127
|
-
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:i,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:
|
|
127
|
+
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:i,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:R.GetAtt(a,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:s,roleLogicalId:a,versionLogicalId:c}}static createDocsDistribution(e){let{slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,lambdaEdgeFunctionArn:c}=e,u=Ge.createDistribution({slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,comment:`Docs CDN for ${n}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(c)Ge.addEdgeFunction(u.distribution,"origin-request",c);return u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,u}static createApiDistribution(e){let{slug:n,environment:r,albDomainName:i,customDomain:s,certificateArn:a,pathPattern:c="/api/*",forwardHeaders:u=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:d="all",whitelistedCookies:m,customOriginHeaders:p={}}=e,g=l({slug:n,environment:r,resourceType:"cdn-api"}),y=o(g),f=Object.entries(p).map(([P,E])=>({HeaderName:P,HeaderValue:E})),h={Id:"ALBOrigin",DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(f.length>0)h.OriginCustomHeaders=f;let S={Forward:d};if(d==="whitelist"&&m)S.WhitelistedNames=m;let C={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${g}`,Origins:[h],DefaultCacheBehavior:{TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:u,Cookies:S}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(s&&a)C.Properties.DistributionConfig.Aliases=[s],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:a,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:C,logicalId:y}}static createMultiOriginDistribution(e){let{slug:n,environment:r,s3BucketDomainName:i,albDomainName:s,apiPathPattern:a="/api/*",customDomain:c,certificateArn:u,customOriginHeaders:d={}}=e,m=l({slug:n,environment:r,resourceType:"cdn"}),p=o(m),g=`${p}OAC`,y={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${m}-oac`,Description:`Origin Access Control for ${m}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},f=Object.entries(d).map(([P,E])=>({HeaderName:P,HeaderValue:E})),h={Id:"S3Origin",DomainName:i,OriginAccessControlId:R.Ref(g)},S={Id:"ALBOrigin",DomainName:s,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(f.length>0)S.OriginCustomHeaders=f;let C={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${m}`,DefaultRootObject:"index.html",Origins:[h,S],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:a,TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:["Host","Origin","Authorization","Content-Type","Accept"],Cookies:{Forward:"all"}}}],PriceClass:"PriceClass_100",HttpVersion:"http2",CustomErrorResponses:[{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html"},{ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html"}]}}};if(c&&u)C.Properties.DistributionConfig.Aliases=[c],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:u,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:C,originAccessControl:y,logicalId:p,oacLogicalId:g}}static addAlbOrigin(e,n){let{originId:r,domainName:i,pathPattern:s,customHeaders:a={},forwardHeaders:c=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:u={default:0,max:0,min:0}}=n,d=Object.entries(a).map(([p,g])=>({HeaderName:p,HeaderValue:g})),m={Id:r,DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(d.length>0)m.OriginCustomHeaders=d;if(!e.Properties.DistributionConfig.Origins)e.Properties.DistributionConfig.Origins=[];if(e.Properties.DistributionConfig.Origins.push(m),!e.Properties.DistributionConfig.CacheBehaviors)e.Properties.DistributionConfig.CacheBehaviors=[];return e.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:s,TargetOriginId:r,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:u.default,MaxTTL:u.max,MinTTL:u.min,ForwardedValues:{QueryString:!0,Headers:c,Cookies:{Forward:"all"}}}),e}static addOriginHeader(e,n,r,i){let s=e.Properties.DistributionConfig.Origins?.find((a)=>a.Id===n);if(s){if(!s.OriginCustomHeaders)s.OriginCustomHeaders=[];s.OriginCustomHeaders.push({HeaderName:r,HeaderValue:i})}return e}static EdgeFunctionTemplates={docsOriginRequest:`
|
|
128
128
|
'use strict';
|
|
129
129
|
exports.handler = async (event) => {
|
|
130
130
|
const request = event.Records[0].cf.request;
|
|
@@ -197,7 +197,7 @@ exports.handler = async (event) => {
|
|
|
197
197
|
|
|
198
198
|
return request;
|
|
199
199
|
};
|
|
200
|
-
`.trim()};static Config={ttl:(e)=>{let{min:n=0,max:r=86400,default:i=86400}=e;return{MinTTL:n,MaxTTL:r,DefaultTTL:i}},cookies:(e,n)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&n)r.WhitelistedNames=n;return r},allowedMethods:(e)=>{let n={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},cachedMethods:(e)=>{let n={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},ttlPresets:{static:{min:0,max:31536000,default:31536000},dynamic:{min:0,max:0,default:0},api:{min:0,max:3600,default:60},html:{min:0,max:86400,default:86400},images:{min:0,max:604800,default:604800}},cacheBehavior:(e)=>{let{ttl:n={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:i,allowedMethods:s="GET_HEAD",cachedMethods:a="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:He.Config.allowedMethods(s),CachedMethods:He.Config.cachedMethods(a),ForwardedValues:{QueryString:u,Headers:d,Cookies:He.Config.cookies(r,i)}}}};static applyConfig(e,n){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(n.ttl)r.MinTTL=n.ttl.min,r.MaxTTL=n.ttl.max,r.DefaultTTL=n.ttl.default;if(n.compress!==void 0)r.Compress=n.compress;if(n.allowedMethods)r.AllowedMethods=He.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=He.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=He.Config.cookies(n.cookies,n.allowedCookies)}return e}}var uu=[403,404,500,502,503,504],Zo="TsCloud::StorageFailover",es="AllowCloudFrontFailoverRead",wr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Ir=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function Ca(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,s=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${s}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!wr.test(n.region))throw Error(`${s}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${s}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let a=n.bucket??`${r}-${n.region}`;if(!Ir.test(a)||a.includes("..")){let c=n.bucket===void 0&&a.length>63?` The default name (<primary bucket>-<region>) is ${a.length} characters; S3 allows 63. Set ${s}.failover.bucket.`:"";throw Error(`${s}.failover: "${a}" is not a valid S3 bucket name.${c}`)}if(a===r)throw Error(`${s}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:a,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:Qo(n.statusCodes??uu),primaryConnection:ot(n,`${s}.failover`)}}function Ta(e,n){return`${e}.s3.${n}.amazonaws.com`}function Ea(e){let n=`arn:aws:s3:::${e.primaryBucket}`,r=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:n},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${n}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function wa(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Aa(e){return{Sid:es,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function Ra(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Zo];return Array.isArray(r)?r:[]}class Ae{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:s}=e,a=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${a}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:s||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:s,ttl:a,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${s}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:s}};if(n)m.Properties.HostedZoneId=n;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=a||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,n,r){return Ae.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:i,values:[n]})}static createWwwRedirect(e,n){return Ae.createRecord({hostedZoneId:n,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:i,values:n.map((s)=>`${s.priority} ${s.server}`)})}static createTxtRecord(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:i,values:[`"${n}"`]})}static createSpfRecord(e,n,r){return Ae.createTxtRecord(e,n,r)}static createDmarcRecord(e,n,r,i){let s=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Ae.createTxtRecord(`_dmarc.${e}`,s,i)}static createS3WebsiteAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,n){return`${e}.s3-website-${n}.amazonaws.com`}static createStoreRecord(e,n,r){return Ae.createCname(`store.${e}`,n,r)}static createApiRecord(e,n,r){return Ae.createCname(`api.${e}`,n,r)}static createDocsRecord(e,n,r){return Ae.createCname(`docs.${e}`,n,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:n,subdomains:r=[],slug:i,environment:s,validationMethod:a="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:s,resourceType:"acm"}),d=o(`${u}-${n.replace(/\./g,"")}`),m=[n];for(let g of r)if(g==="*")m.push(`*.${n}`);else m.push(`${g}.${n}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n,SubjectAlternativeNames:m,ValidationMethod:a}};if(a==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:n,slug:r,environment:i,enableRotation:s=!0,multiRegion:a=!1}=e,c=l({slug:r,environment:i,resourceType:"kms"}),u=o(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:P.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},m={Type:"AWS::KMS::Key",Properties:{Description:n,Enabled:!0,EnableKeyRotation:s,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:a}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:P.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:s="allow"}=e,a=l({slug:n,environment:r,resourceType:"waf"}),c=o(a);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:a,Scope:i,DefaultAction:s==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-metric`}}},logicalId:c}}static setRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockCountries(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{GeoMatchStatement:{CountryCodes:n.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockIpAddresses(e,n,r,i){let s=l({slug:r,environment:i,resourceType:"ipset"}),a=o(`${s}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${s}-${n.name}`,Scope:e.Properties.Scope,IPAddressVersion:n.ipVersion||"IPV4",Addresses:n.ipAddresses,Description:`Blocked IPs for ${n.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{IPSetReferenceStatement:{Arn:P.GetAtt(a,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:a}}static addManagedRules(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:n.vendorName,Name:n.ruleName}};if(n.excludedRules&&n.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=n.excludedRules.map((i)=>({Name:i}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r=n.paths.map((i)=>({SearchString:i,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((i)=>({ByteMatchStatement:i}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static setHeaderRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:n.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(n.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:n.headerValue,FieldToMatch:{SingleHeader:{Name:n.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static protectLoginEndpoint(e,n){let{loginPaths:r,priority:i,requestsPerMinute:s=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:s=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:s=!1,enableRateLimiting:a=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:n,environment:r,scope:i,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),s)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(a)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function pu(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function mu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${pu(e)?"arm64":"x86_64"}`}function ul(e="t3.micro"){return`{{resolve:ssm:${mu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:s=ul(i),keyName:a,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,y=l({slug:n,environment:r,resourceType:"ec2"}),f=o(y),h={Type:"AWS::EC2::Instance",Properties:{ImageId:s,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=P.Base64(d);return h.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:h,logicalId:f}}static createSecurityGroup(e){let{slug:n,environment:r,vpcId:i,description:s,ingress:a=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:s||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(a.length>0)m.Properties.SecurityGroupIngress=a.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,n,r){return b.createSecurityGroup({slug:e,environment:n,vpcId:r,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:n,environment:r,scheme:i="internet-facing",subnets:s,securityGroups:a,type:c="application"}=e,u=l({slug:n,environment:r,resourceType:"alb"}),d=o(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:i,Type:c,Subnets:s,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a)m.Properties.SecurityGroups=a;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:s="HTTP",vpcId:a,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,y=l({slug:n,environment:r,resourceType:"tg"}),f=o(y);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:y,Port:i,Protocol:s,VpcId:a,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:s,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}},logicalId:f}}static createListener(e,n){let{port:r,protocol:i="HTTP",certificateArn:s,defaultTargetGroupArn:a}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:P.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:a}]}};if(i==="HTTPS"&&s)u.Properties.Certificates=[{CertificateArn:s}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,n){let r=l({slug:e,environment:n,resourceType:"ecs-cluster"}),i=o(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createFargateService(e){let{slug:n,environment:r,image:i,cpu:s="256",memory:a="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:y,securityGroups:f,targetGroupArn:h}=e,{cluster:S,logicalId:C}=b.createEcsCluster(n,r),E=l({slug:n,environment:r,resourceType:"fargate"}),w=o(`${E}-execution-role`),v={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}},I=o(`${E}-task-role`),D={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},x=o(`${E}-task`),L={Type:"AWS::ECS::TaskDefinition",Properties:{Family:E,TaskRoleArn:P.GetAtt(I,"Arn"),ExecutionRoleArn:P.GetAtt(w,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:s,Memory:a,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([F,V])=>({Name:F,Value:V})),Secrets:m.map((F)=>({Name:F.name,ValueFrom:F.valueFrom}))}],Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:r}]}};if(p)L.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)L.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":P.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let B=o(`${E}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:E,Cluster:P.Ref(C),TaskDefinition:P.Ref(x),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:y,SecurityGroups:f,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:r}]}};if(h)O.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:n,ContainerPort:u}];return{cluster:S,taskDefinition:L,service:O,taskRole:D,executionRole:v,clusterLogicalId:C,taskDefinitionLogicalId:x,serviceLogicalId:B,taskRoleLogicalId:I,executionRoleLogicalId:w}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:s,code:a,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:n,environment:r,resourceType:"lambda"}),g=o(p),y=o(`${p}-role`),f={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(m)f.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:i,Role:P.GetAtt(y,"Arn"),Handler:s,Code:{...a.s3Bucket&&{S3Bucket:a.s3Bucket},...a.s3Key&&{S3Key:a.s3Key},...a.zipFile&&{ZipFile:a.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)h.Properties.Environment={Variables:d};if(m)h.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:h,role:f,logicalId:g,roleLogicalId:y}}static generateNodeServerUserData(e={}){let{nodeVersion:n="20",appRepo:r,environment:i={}}=e,s=Object.entries(i).map(([a,c])=>`echo "export ${a}='${c}'" >> /etc/environment`).join(`
|
|
200
|
+
`.trim()};static Config={ttl:(e)=>{let{min:n=0,max:r=86400,default:i=86400}=e;return{MinTTL:n,MaxTTL:r,DefaultTTL:i}},cookies:(e,n)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&n)r.WhitelistedNames=n;return r},allowedMethods:(e)=>{let n={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},cachedMethods:(e)=>{let n={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},ttlPresets:{static:{min:0,max:31536000,default:31536000},dynamic:{min:0,max:0,default:0},api:{min:0,max:3600,default:60},html:{min:0,max:86400,default:86400},images:{min:0,max:604800,default:604800}},cacheBehavior:(e)=>{let{ttl:n={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:i,allowedMethods:s="GET_HEAD",cachedMethods:a="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:Ge.Config.allowedMethods(s),CachedMethods:Ge.Config.cachedMethods(a),ForwardedValues:{QueryString:u,Headers:d,Cookies:Ge.Config.cookies(r,i)}}}};static applyConfig(e,n){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(n.ttl)r.MinTTL=n.ttl.min,r.MaxTTL=n.ttl.max,r.DefaultTTL=n.ttl.default;if(n.compress!==void 0)r.Compress=n.compress;if(n.allowedMethods)r.AllowedMethods=Ge.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=Ge.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=Ge.Config.cookies(n.cookies,n.allowedCookies)}return e}}var uu=[403,404,500,502,503,504],Zo="TsCloud::StorageFailover",es="AllowCloudFrontFailoverRead",wr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Ir=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function Ca(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,s=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${s}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!wr.test(n.region))throw Error(`${s}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${s}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let a=n.bucket??`${r}-${n.region}`;if(!Ir.test(a)||a.includes("..")){let c=n.bucket===void 0&&a.length>63?` The default name (<primary bucket>-<region>) is ${a.length} characters; S3 allows 63. Set ${s}.failover.bucket.`:"";throw Error(`${s}.failover: "${a}" is not a valid S3 bucket name.${c}`)}if(a===r)throw Error(`${s}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:a,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:Qo(n.statusCodes??uu),primaryConnection:st(n,`${s}.failover`)}}function Ta(e,n){return`${e}.s3.${n}.amazonaws.com`}function Ea(e){let n=`arn:aws:s3:::${e.primaryBucket}`,r=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:n},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${n}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function wa(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Aa(e){return{Sid:es,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function Ra(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Zo];return Array.isArray(r)?r:[]}class Ae{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:s}=e,a=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${a}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:s||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:s,ttl:a,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${s}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:s}};if(n)m.Properties.HostedZoneId=n;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=a||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,n,r){return Ae.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:i,values:[n]})}static createWwwRedirect(e,n){return Ae.createRecord({hostedZoneId:n,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:i,values:n.map((s)=>`${s.priority} ${s.server}`)})}static createTxtRecord(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:i,values:[`"${n}"`]})}static createSpfRecord(e,n,r){return Ae.createTxtRecord(e,n,r)}static createDmarcRecord(e,n,r,i){let s=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Ae.createTxtRecord(`_dmarc.${e}`,s,i)}static createS3WebsiteAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,n){return`${e}.s3-website-${n}.amazonaws.com`}static createStoreRecord(e,n,r){return Ae.createCname(`store.${e}`,n,r)}static createApiRecord(e,n,r){return Ae.createCname(`api.${e}`,n,r)}static createDocsRecord(e,n,r){return Ae.createCname(`docs.${e}`,n,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:n,subdomains:r=[],slug:i,environment:s,validationMethod:a="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:s,resourceType:"acm"}),d=o(`${u}-${n.replace(/\./g,"")}`),m=[n];for(let g of r)if(g==="*")m.push(`*.${n}`);else m.push(`${g}.${n}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n,SubjectAlternativeNames:m,ValidationMethod:a}};if(a==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:n,slug:r,environment:i,enableRotation:s=!0,multiRegion:a=!1}=e,c=l({slug:r,environment:i,resourceType:"kms"}),u=o(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:R.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},m={Type:"AWS::KMS::Key",Properties:{Description:n,Enabled:!0,EnableKeyRotation:s,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:a}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:R.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:s="allow"}=e,a=l({slug:n,environment:r,resourceType:"waf"}),c=o(a);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:a,Scope:i,DefaultAction:s==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-metric`}}},logicalId:c}}static setRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockCountries(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{GeoMatchStatement:{CountryCodes:n.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockIpAddresses(e,n,r,i){let s=l({slug:r,environment:i,resourceType:"ipset"}),a=o(`${s}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${s}-${n.name}`,Scope:e.Properties.Scope,IPAddressVersion:n.ipVersion||"IPV4",Addresses:n.ipAddresses,Description:`Blocked IPs for ${n.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{IPSetReferenceStatement:{Arn:R.GetAtt(a,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:a}}static addManagedRules(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:n.vendorName,Name:n.ruleName}};if(n.excludedRules&&n.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=n.excludedRules.map((i)=>({Name:i}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r=n.paths.map((i)=>({SearchString:i,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((i)=>({ByteMatchStatement:i}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static setHeaderRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:n.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(n.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:n.headerValue,FieldToMatch:{SingleHeader:{Name:n.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static protectLoginEndpoint(e,n){let{loginPaths:r,priority:i,requestsPerMinute:s=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:s=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:s=!1,enableRateLimiting:a=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:n,environment:r,scope:i,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),s)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(a)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function pu(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function mu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${pu(e)?"arm64":"x86_64"}`}function ul(e="t3.micro"){return`{{resolve:ssm:${mu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:s=ul(i),keyName:a,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,y=l({slug:n,environment:r,resourceType:"ec2"}),f=o(y),h={Type:"AWS::EC2::Instance",Properties:{ImageId:s,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=R.Base64(d);return h.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:h,logicalId:f}}static createSecurityGroup(e){let{slug:n,environment:r,vpcId:i,description:s,ingress:a=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:s||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(a.length>0)m.Properties.SecurityGroupIngress=a.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,n,r){return b.createSecurityGroup({slug:e,environment:n,vpcId:r,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:n,environment:r,scheme:i="internet-facing",subnets:s,securityGroups:a,type:c="application"}=e,u=l({slug:n,environment:r,resourceType:"alb"}),d=o(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:i,Type:c,Subnets:s,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a)m.Properties.SecurityGroups=a;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:s="HTTP",vpcId:a,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,y=l({slug:n,environment:r,resourceType:"tg"}),f=o(y);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:y,Port:i,Protocol:s,VpcId:a,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:s,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}},logicalId:f}}static createListener(e,n){let{port:r,protocol:i="HTTP",certificateArn:s,defaultTargetGroupArn:a}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:R.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:a}]}};if(i==="HTTPS"&&s)u.Properties.Certificates=[{CertificateArn:s}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,n){let r=l({slug:e,environment:n,resourceType:"ecs-cluster"}),i=o(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createFargateService(e){let{slug:n,environment:r,image:i,cpu:s="256",memory:a="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:y,securityGroups:f,targetGroupArn:h}=e,{cluster:S,logicalId:C}=b.createEcsCluster(n,r),P=l({slug:n,environment:r,resourceType:"fargate"}),E=o(`${P}-execution-role`),v={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}},w=o(`${P}-task-role`),D={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},x=o(`${P}-task`),L={Type:"AWS::ECS::TaskDefinition",Properties:{Family:P,TaskRoleArn:R.GetAtt(w,"Arn"),ExecutionRoleArn:R.GetAtt(E,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:s,Memory:a,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([F,V])=>({Name:F,Value:V})),Secrets:m.map((F)=>({Name:F.name,ValueFrom:F.valueFrom}))}],Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(p)L.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)L.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":R.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let B=o(`${P}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:P,Cluster:R.Ref(C),TaskDefinition:R.Ref(x),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:y,SecurityGroups:f,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(h)O.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:n,ContainerPort:u}];return{cluster:S,taskDefinition:L,service:O,taskRole:D,executionRole:v,clusterLogicalId:C,taskDefinitionLogicalId:x,serviceLogicalId:B,taskRoleLogicalId:w,executionRoleLogicalId:E}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:s,code:a,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:n,environment:r,resourceType:"lambda"}),g=o(p),y=o(`${p}-role`),f={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(m)f.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:i,Role:R.GetAtt(y,"Arn"),Handler:s,Code:{...a.s3Bucket&&{S3Bucket:a.s3Bucket},...a.s3Key&&{S3Key:a.s3Key},...a.zipFile&&{ZipFile:a.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)h.Properties.Environment={Variables:d};if(m)h.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:h,role:f,logicalId:g,roleLogicalId:y}}static generateNodeServerUserData(e={}){let{nodeVersion:n="20",appRepo:r,environment:i={}}=e,s=Object.entries(i).map(([a,c])=>`echo "export ${a}='${c}'" >> /etc/environment`).join(`
|
|
201
201
|
`);return`#!/bin/bash
|
|
202
202
|
# Update system
|
|
203
203
|
yum update -y
|
|
@@ -298,12 +298,12 @@ systemctl enable caddy
|
|
|
298
298
|
systemctl start caddy
|
|
299
299
|
|
|
300
300
|
echo "Bun server setup complete!"
|
|
301
|
-
`}static createLaunchConfiguration(e){let{slug:n,environment:r,imageId:i,instanceType:s,keyName:a,securityGroups:c,userData:u,volumeSize:d=20,volumeType:m="gp3",encrypted:p=!0,iamInstanceProfile:g}=e,y=l({slug:n,environment:r,resourceType:"launch-config"}),f=o(y),h={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:i,InstanceType:s,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroups=c;if(u)h.Properties.UserData=
|
|
301
|
+
`}static createLaunchConfiguration(e){let{slug:n,environment:r,imageId:i,instanceType:s,keyName:a,securityGroups:c,userData:u,volumeSize:d=20,volumeType:m="gp3",encrypted:p=!0,iamInstanceProfile:g}=e,y=l({slug:n,environment:r,resourceType:"launch-config"}),f=o(y),h={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:i,InstanceType:s,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroups=c;if(u)h.Properties.UserData=R.Base64(u);if(g)h.Properties.IamInstanceProfile=g;return{launchConfiguration:h,logicalId:f}}static createAutoScalingGroup(e){let{slug:n,environment:r,launchConfigurationName:i,minSize:s,maxSize:a,desiredCapacity:c,vpcZoneIdentifier:u,targetGroupArns:d,healthCheckType:m="EC2",healthCheckGracePeriod:p=300,cooldown:g=300,tags:y={}}=e,f=l({slug:n,environment:r,resourceType:"asg"}),h=o(f),S={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:f,LaunchConfigurationName:i,MinSize:s,MaxSize:a,HealthCheckType:m,HealthCheckGracePeriod:p,Cooldown:g,Tags:[{Key:"Name",Value:f,PropagateAtLaunch:!0},{Key:"Environment",Value:r,PropagateAtLaunch:!0},...Object.entries(y).map(([C,P])=>({Key:C,Value:P,PropagateAtLaunch:!0}))]}};if(c!==void 0)S.Properties.DesiredCapacity=c;if(u)S.Properties.VPCZoneIdentifier=u;if(d)S.Properties.TargetGroupARNs=d;return S.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,s-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:S,logicalId:h}}static createScalingPolicy(e){let{slug:n,environment:r,autoScalingGroupName:i,policyType:s="TargetTrackingScaling",targetValue:a=70,predefinedMetricType:c="ASGAverageCPUUtilization"}=e,u=l({slug:n,environment:r,resourceType:"scaling-policy"}),d=o(u),m={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:i,PolicyType:s}};if(s==="TargetTrackingScaling")m.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:c},TargetValue:a};return{scalingPolicy:m,logicalId:d}}static AutoScaling={smallWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(e,n,r,i=70)=>b.createScalingPolicy({slug:e,environment:n,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:i}),requestCountScaling:(e,n,r,i=1000)=>b.createScalingPolicy({slug:e,environment:n,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:i})};static Secrets={fromSecretsManager:(e)=>Object.entries(e).map(([n,r])=>({name:n,valueFrom:r})),fromJsonSecret:(e,n)=>`${e}:${n}::`,fromSecretVersion:(e,n)=>`${e}::${n}:`,fromSecretVersionStage:(e,n)=>`${e}:::${n}`,createAccessPolicy:(e)=>({PolicyName:"SecretsManagerAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:e}]}}),createKmsPolicy:(e)=>({PolicyName:"KMSDecryptAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["kms:Decrypt"],Resource:e}]}}),buildSecretArn:(e)=>`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretName}`,buildSecretArnPattern:(e)=>{let n=e.region||"*",r=e.accountId||"*";return`arn:aws:secretsmanager:${n}:${r}:secret:${e.secretNamePrefix}*`},commonAppSecrets:(e)=>({DATABASE_URL:`${e}/database-url`,DATABASE_PASSWORD:`${e}/database-password`,REDIS_URL:`${e}/redis-url`,REDIS_PASSWORD:`${e}/redis-password`,API_KEY:`${e}/api-key`,JWT_SECRET:`${e}/jwt-secret`,ENCRYPTION_KEY:`${e}/encryption-key`,AWS_ACCESS_KEY_ID:`${e}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${e}/aws-secret-access-key`,MAIL_PASSWORD:`${e}/mail-password`,STRIPE_SECRET_KEY:`${e}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${e}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(e){let{secretArns:n=[],kmsKeyArns:r=[],...i}=e,s=b.createFargateService(i);if(n.length>0){if(!s.executionRole.Properties.Policies)s.executionRole.Properties.Policies=[];if(s.executionRole.Properties.Policies.push(b.Secrets.createAccessPolicy(n)),r.length>0)s.executionRole.Properties.Policies.push(b.Secrets.createKmsPolicy(r))}return s}static generateSecretReferences(e){return e.secrets.map((n)=>{let r=`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretPrefix}/${n}`;return{name:n.toUpperCase().replace(/-/g,"_"),valueFrom:r}})}static EnvSecrets={database:(e)=>[{name:"DB_HOST",valueFrom:`${e}:host::`},{name:"DB_PORT",valueFrom:`${e}:port::`},{name:"DB_USERNAME",valueFrom:`${e}:username::`},{name:"DB_PASSWORD",valueFrom:`${e}:password::`},{name:"DB_NAME",valueFrom:`${e}:dbname::`}],redis:(e)=>[{name:"REDIS_HOST",valueFrom:`${e}:host::`},{name:"REDIS_PORT",valueFrom:`${e}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${e}:password::`}],apiCredentials:(e)=>[{name:"API_KEY",valueFrom:`${e}:apiKey::`},{name:"API_SECRET",valueFrom:`${e}:apiSecret::`}],mail:(e)=>[{name:"MAIL_HOST",valueFrom:`${e}:host::`},{name:"MAIL_PORT",valueFrom:`${e}:port::`},{name:"MAIL_USERNAME",valueFrom:`${e}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${e}:password::`}],awsCredentials:(e)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${e}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${e}:secretAccessKey::`}]};static createJumpBox(e){let{slug:n,environment:r,vpcId:i,subnetId:s,keyName:a,instanceType:c="t3.micro",imageId:u=ul(c),mountEfs:d,databaseTools:m=!1}=e,p=e.allowedCidrs??(a?["0.0.0.0/0"]:[]),g=l({slug:n,environment:r,resourceType:"jumpbox"}),y=o(`${g}-sg`),f={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${g}-sg`,GroupDescription:`Security group for ${g} JumpBox access`,VpcId:i,SecurityGroupIngress:p.map((x)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:x,Description:`SSH access from ${x}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${g}-sg`},{Key:"Environment",Value:r}]}},h=o(`${g}-role`),S={Type:"AWS::IAM::Role",Properties:{RoleName:`${g}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"],Policies:d?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},C=o(`${g}-profile`),P={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${g}-profile`,Roles:[R.Ref(h)]}},E=`#!/bin/bash
|
|
302
302
|
dnf install -y amazon-efs-utils nfs-utils jq wget htop
|
|
303
|
-
`;if(m)
|
|
303
|
+
`;if(m)E+=`
|
|
304
304
|
# Database clients: psql, mysql (MariaDB), redis-cli
|
|
305
305
|
dnf install -y postgresql16 mariadb105 redis6
|
|
306
|
-
`;if(d){let x=d.mountPath||"/mnt/efs";
|
|
306
|
+
`;if(d){let x=d.mountPath||"/mnt/efs";E+=`
|
|
307
307
|
# Mount EFS
|
|
308
308
|
mkdir -p ${x}
|
|
309
309
|
for attempt in $(seq 1 30); do
|
|
@@ -311,7 +311,7 @@ for attempt in $(seq 1 30); do
|
|
|
311
311
|
sleep 10
|
|
312
312
|
done
|
|
313
313
|
echo "\${FileSystemId}:/ ${x} efs _netdev,tls,nofail 0 0" >> /etc/fstab
|
|
314
|
-
`}let v=o(g),
|
|
314
|
+
`}let v=o(g),w={Type:"AWS::EC2::Instance",DependsOn:[C],Properties:{ImageId:u,InstanceType:c,SubnetId:s,SecurityGroupIds:[R.Ref(y)],IamInstanceProfile:R.Ref(C),UserData:d?{"Fn::Base64":R.Sub(E,{FileSystemId:d.fileSystemId})}:R.Base64(E),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:r},{Key:"Purpose",Value:"JumpBox/Bastion"}]}};if(a)w.Properties.KeyName=a;let D={[y]:f,[h]:S,[C]:P,[v]:w};return{instance:w,securityGroup:f,instanceProfile:P,instanceRole:S,instanceLogicalId:v,securityGroupLogicalId:y,instanceProfileLogicalId:C,instanceRoleLogicalId:h,resources:D}}static JumpBox={withEfsMount:(e)=>b.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:e.instanceType,allowedCidrs:e.allowedCidrs,mountEfs:{fileSystemId:e.fileSystemId,mountPath:e.mountPath||"/mnt/efs"}}),minimal:(e)=>b.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:"t3.nano",allowedCidrs:e.allowedCidrs}),withDatabaseTools:(e)=>b.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:e.instanceType,allowedCidrs:e.allowedCidrs,databaseTools:!0}),commonCidrs:{any:["0.0.0.0/0"],privateOnly:["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16"]}};static InstanceSize={toInstanceType:(e,n="t3")=>`${n}.${e}`,specs:{nano:{vcpu:2,memory:0.5,instanceType:"t3.nano"},micro:{vcpu:2,memory:1,instanceType:"t3.micro"},small:{vcpu:2,memory:2,instanceType:"t3.small"},medium:{vcpu:2,memory:4,instanceType:"t3.medium"},large:{vcpu:2,memory:8,instanceType:"t3.large"},xlarge:{vcpu:4,memory:16,instanceType:"t3.xlarge"},"2xlarge":{vcpu:8,memory:32,instanceType:"t3.2xlarge"}},toFargateSpecs:(e)=>{let n={nano:{cpu:"256",memory:"512"},micro:{cpu:"256",memory:"1024"},small:{cpu:"512",memory:"1024"},medium:{cpu:"1024",memory:"2048"},large:{cpu:"2048",memory:"4096"},xlarge:{cpu:"4096",memory:"8192"},"2xlarge":{cpu:"4096",memory:"16384"}};return n[e]||n.medium},toLambdaMemory:(e)=>({nano:128,micro:256,small:512,medium:1024,large:2048,xlarge:4096,"2xlarge":8192})[e]||1024,presets:{webServer:"t3.small",apiServer:"t3.medium",worker:"t3.medium",database:"r6i.large",cache:"r6i.medium",compute:"c6i.large",general:"m6i.medium"}};static DiskConfig={create:(e)=>{let{size:n,type:r="ssd",encrypted:i=!0,iops:s,throughput:a,deleteOnTermination:c=!0}=e,d={standard:"gp2",ssd:"gp3",premium:"io2",gp2:"gp2",gp3:"gp3",io1:"io1",io2:"io2"}[r]||"gp3",m={VolumeSize:n,VolumeType:d,Encrypted:i,DeleteOnTermination:c};if((d==="io1"||d==="io2"||d==="gp3")&&s)m.Iops=s;if(d==="gp3"&&a)m.Throughput=a;return m},presets:{standard:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},large:{VolumeSize:100,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},highPerformance:{VolumeSize:50,VolumeType:"io2",Iops:3000,Encrypted:!0,DeleteOnTermination:!0},database:{VolumeSize:100,VolumeType:"io2",Iops:1e4,Encrypted:!0,DeleteOnTermination:!1}}};static SpotConfig={create:(e)=>{let{maxPrice:n,spotInstanceType:r="one-time",interruptionBehavior:i="terminate",blockDurationMinutes:s}=e,a={SpotInstanceType:r,InstanceInterruptionBehavior:i};if(n)a.MaxPrice=n;if(s)a.BlockDurationMinutes=s;return{SpotOptions:a}},presets:{standard:{spotInstanceType:"one-time",interruptionBehavior:"terminate"},persistent:{spotInstanceType:"persistent",interruptionBehavior:"stop"},costOptimized:{maxPrice:"0.05",spotInstanceType:"one-time",interruptionBehavior:"terminate"}}};static MixedInstances={create:(e)=>{let{instanceTypes:n,baseCapacity:r=0,onDemandPercentage:i=20,spotAllocationStrategy:s="capacity-optimized",spotMaxPrice:a}=e,c={OnDemandBaseCapacity:r,OnDemandPercentageAboveBaseCapacity:i,SpotAllocationStrategy:s};if(a)c.SpotMaxPrice=a;let u=n.map(({size:d,weight:m})=>{let p={InstanceType:b.InstanceSize.toInstanceType(d)};if(m)p.WeightedCapacity=String(m);return p});return{MixedInstancesPolicy:{InstancesDistribution:c,LaunchTemplate:{Overrides:u}}}},presets:{costOptimized:{baseCapacity:0,onDemandPercentage:20,spotAllocationStrategy:"lowest-price",instanceTypes:[{size:"small",weight:1},{size:"medium",weight:2}]},balanced:{baseCapacity:1,onDemandPercentage:50,spotAllocationStrategy:"capacity-optimized",instanceTypes:[{size:"medium",weight:1},{size:"large",weight:2}]},highAvailability:{baseCapacity:2,onDemandPercentage:80,spotAllocationStrategy:"capacity-optimized-prioritized",instanceTypes:[{size:"medium",weight:1}]}}};static AutoScalingConfig={create:(e)=>{let{min:n,max:r,desired:i=n,scaleUpThreshold:s=70,scaleDownThreshold:a=30,cooldownSeconds:c=300,targetMetric:u="cpu"}=e,d={cpu:"ASGAverageCPUUtilization",memory:"ASGAverageMemoryUtilization",requests:"ALBRequestCountPerTarget"};return{minSize:n,maxSize:r,desiredCapacity:i,scalingPolicies:[{policyType:"TargetTrackingScaling",targetValue:s,predefinedMetricType:d[u]||d.cpu,scaleInCooldown:c,scaleOutCooldown:c}]}},forEcs:(e)=>{let{min:n,max:r,cpuTarget:i=70,memoryTarget:s}=e,a=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:i}];if(s)a.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:s});return{minCapacity:n,maxCapacity:r,targetTrackingPolicies:a}},presets:{small:{min:1,max:3,scaleUpThreshold:70,scaleDownThreshold:30},medium:{min:2,max:10,scaleUpThreshold:70,scaleDownThreshold:30},large:{min:3,max:50,scaleUpThreshold:60,scaleDownThreshold:40},highAvailability:{min:2,max:20,scaleUpThreshold:60,scaleDownThreshold:30}}};static LoadBalancerConfig={healthCheck:(e)=>{let{path:n="/",interval:r=30,timeout:i=5,healthyThreshold:s=2,unhealthyThreshold:a=5,protocol:c="HTTP"}=e,u={HealthCheckIntervalSeconds:r,HealthCheckTimeoutSeconds:i,HealthyThresholdCount:s,UnhealthyThresholdCount:a};if(c!=="TCP")u.HealthCheckPath=n,u.HealthCheckProtocol=c;return u},presets:{standard:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:5},fast:{path:"/health",interval:10,timeout:3,healthyThreshold:2,unhealthyThreshold:2},relaxed:{path:"/health",interval:60,timeout:30,healthyThreshold:2,unhealthyThreshold:10}}};static SslConfig={httpsListener:(e)=>{let{certificateArn:n,targetGroupArn:r,port:i=443,sslPolicy:s="ELBSecurityPolicy-TLS13-1-2-2021-06"}=e;return{Port:i,Protocol:"HTTPS",Certificates:[{CertificateArn:n}],SslPolicy:s,DefaultActions:[{Type:"forward",TargetGroupArn:r}]}},httpRedirectListener:(e=80)=>({Port:e,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}),policies:{tls13:"ELBSecurityPolicy-TLS13-1-2-2021-06",tls12:"ELBSecurityPolicy-TLS-1-2-Ext-2018-06",tls11:"ELBSecurityPolicy-TLS-1-1-2017-01",fips:"ELBSecurityPolicy-TLS-1-2-Ext-FIPS-2022-05"}};static FunctionConfig={create:(e)=>{let{handler:n,runtime:r="nodejs20.x",timeout:i=30,memorySize:s=256,environmentVariables:a,reservedConcurrency:c}=e,u={Handler:n,Runtime:r,Timeout:i,MemorySize:s};if(a)u.Environment={Variables:a};if(c)u.ReservedConcurrentExecutions=c;return u},runtimes:{nodejs20:"nodejs20.x",nodejs18:"nodejs18.x",python312:"python3.12",python311:"python3.11",java21:"java21",java17:"java17",go:"provided.al2023",rust:"provided.al2023",bun:"provided.al2023"},presets:{api:{runtime:"nodejs20.x",timeout:30,memorySize:256},worker:{runtime:"nodejs20.x",timeout:300,memorySize:512},cron:{runtime:"nodejs20.x",timeout:900,memorySize:1024},dataProcessing:{runtime:"nodejs20.x",timeout:900,memorySize:3008}}};static UserData={generateAppServerScript:(e)=>{let{runtime:n="bun",runtimeVersion:r="latest",webServer:i="nginx",processManager:s="systemd",enableSsl:a=!0,sslEmail:c="admin@example.com",domain:u,appPort:d=3000,installDatabaseClients:m=!1,installRedis:p=!1,extraPackages:g=[]}=e,y=`#!/bin/bash
|
|
315
315
|
set -e
|
|
316
316
|
|
|
317
317
|
# Update system
|
|
@@ -569,7 +569,7 @@ ufw default allow outgoing
|
|
|
569
569
|
${e.map((n)=>`ufw allow ${n}`).join(`
|
|
570
570
|
`)}
|
|
571
571
|
ufw --force enable
|
|
572
|
-
`},Presets:{bunWithNginx:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:n,enableSsl:!0}),bunWithCaddy:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:n,enableSsl:!1}),nodeWithPm2:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:n,enableSsl:!0}),worker:(e="bun")=>b.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:n,environment:r,domain:i,instanceLogicalId:s}=e,a=l({slug:n,environment:r,resourceType:"eip"}),c=o(a),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r},...i?[{Key:"Domain",Value:i}]:[]]}},d={[c]:u},m,p;if(s)p=o(`${a}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:
|
|
572
|
+
`},Presets:{bunWithNginx:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:n,enableSsl:!0}),bunWithCaddy:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:n,enableSsl:!1}),nodeWithPm2:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:n,enableSsl:!0}),worker:(e="bun")=>b.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:n,environment:r,domain:i,instanceLogicalId:s}=e,a=l({slug:n,environment:r,resourceType:"eip"}),c=o(a),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r},...i?[{Key:"Domain",Value:i}]:[]]}},d={[c]:u},m,p;if(s)p=o(`${a}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:R.GetAtt(c,"AllocationId"),InstanceId:R.Ref(s)}},d[p]=m;return{eip:u,eipAssociation:m,eipLogicalId:c,associationLogicalId:p,resources:d}}static createServerModeStack(e){let{slug:n,environment:r,vpcId:i,subnetId:s,instanceType:a="t3.small",imageId:c="ami-0f3caa1cf4417e51b",keyName:u,domain:d,userData:m,allowedPorts:p=[22,80,443],volumeSize:g=20,volumeType:y="gp3"}=e,f={},h=l({slug:n,environment:r,resourceType:"server-sg"}),S=o(h),C={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:h,GroupDescription:`Security group for ${n} server`,VpcId:i,SecurityGroupIngress:p.map((K)=>({IpProtocol:"tcp",FromPort:K,ToPort:K,CidrIp:"0.0.0.0/0",Description:`Port ${K}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};f[S]=C;let P=l({slug:n,environment:r,resourceType:"server-role"}),E=o(P),v={Type:"AWS::IAM::Role",Properties:{RoleName:P,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Policies:[{PolicyName:"StacksServerPermissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:SendBulkEmail","ses:VerifyDomainIdentity","ses:VerifyDomainDkim","ses:GetIdentityDkimAttributes","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["route53:ChangeResourceRecordSets","route53:ListResourceRecordSets","route53:GetHostedZone"],Resource:"*"},{Effect:"Allow",Action:["ssm:GetParameter","ssm:GetParameters"],Resource:"*"}]}}]}};f[E]=v;let w=l({slug:n,environment:r,resourceType:"server-profile"}),D=o(w),x={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:w,Roles:[R.Ref(E)]}};f[D]=x;let L=l({slug:n,environment:r,resourceType:"server"}),B=o(L),O={Type:"AWS::EC2::Instance",DependsOn:[D],Properties:{ImageId:c,InstanceType:a,KeyName:u,SubnetId:s,SecurityGroupIds:[R.Ref(S)],IamInstanceProfile:R.Ref(D),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:g,VolumeType:y,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:L},{Key:"Environment",Value:r},...d?[{Key:"Domain",Value:d}]:[]]}};if(m)O.Properties.UserData=R.Base64(m);f[B]=O;let{eip:F,eipAssociation:V,eipLogicalId:ce,associationLogicalId:q,resources:J}=b.createElasticIp({slug:n,environment:r,domain:d,instanceLogicalId:B});return Object.assign(f,J),{instance:O,securityGroup:C,eip:F,eipAssociation:V,instanceRole:v,instanceProfile:x,resources:f,outputs:{instanceLogicalId:B,securityGroupLogicalId:S,eipLogicalId:ce,associationLogicalId:q,roleLogicalId:E,profileLogicalId:D}}}static ServerMode={webServer:(e)=>{let n=b.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:e.webServer||"nginx",domain:e.domain,enableSsl:!0});return b.createServerModeStack({...e,userData:n,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(e)=>{let n=b.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:"none",installRedis:e.installRedis});return b.createServerModeStack({...e,userData:n,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(e)=>b.createServerModeStack({...e,userData:`#!/bin/bash
|
|
573
573
|
set -e
|
|
574
574
|
apt-get update && apt-get upgrade -y
|
|
575
575
|
apt-get install -y redis-server
|
|
@@ -577,7 +577,7 @@ sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
|
|
|
577
577
|
systemctl enable redis-server
|
|
578
578
|
systemctl restart redis-server
|
|
579
579
|
echo "Redis server setup complete!"
|
|
580
|
-
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class M{static createVpc(e){let{slug:n,environment:r,cidr:i="10.0.0.0/16",enableDnsHostnames:s=!0,enableDnsSupport:a=!0}=e,c=l({slug:n,environment:r,resourceType:"vpc"}),u=o(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:i,EnableDnsHostnames:s,EnableDnsSupport:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:n,environment:r,vpcId:i,type:s,cidr:a,availabilityZone:c,mapPublicIp:u=s==="public"}=e,d=l({slug:n,environment:r,resourceType:`subnet-${s}`}),m=o(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:i,CidrBlock:a,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:s}]}},logicalId:m}}static createInternetGateway(e,n){let r=l({slug:e,environment:n,resourceType:"igw"}),i=o(r);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static attachInternetGateway(e,n){let r=o(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:
|
|
580
|
+
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class M{static createVpc(e){let{slug:n,environment:r,cidr:i="10.0.0.0/16",enableDnsHostnames:s=!0,enableDnsSupport:a=!0}=e,c=l({slug:n,environment:r,resourceType:"vpc"}),u=o(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:i,EnableDnsHostnames:s,EnableDnsSupport:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:n,environment:r,vpcId:i,type:s,cidr:a,availabilityZone:c,mapPublicIp:u=s==="public"}=e,d=l({slug:n,environment:r,resourceType:`subnet-${s}`}),m=o(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:i,CidrBlock:a,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:s}]}},logicalId:m}}static createInternetGateway(e,n){let r=l({slug:e,environment:n,resourceType:"igw"}),i=o(r);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static attachInternetGateway(e,n){let r=o(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:R.Ref(e),InternetGatewayId:R.Ref(n)}},logicalId:r}}static createEip(e,n){let r=l({slug:e,environment:n,resourceType:"eip"}),i=o(r);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createNatGateway(e,n){let{slug:r,environment:i,subnetId:s}=e,a=l({slug:r,environment:i,resourceType:"nat"}),c=o(a);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:R.GetAtt(n,"AllocationId"),SubnetId:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:c}}static createRouteTable(e,n,r,i){let s=l({slug:e,environment:n,resourceType:`rt-${i}`}),a=o(s);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:R.Ref(r),Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n},{Key:"Type",Value:i}]}},logicalId:a}}static createRoute(e,n,r){let i=o(`${e}-route-${r.type}`),s={Type:"AWS::EC2::Route",Properties:{RouteTableId:R.Ref(e),DestinationCidrBlock:n}};if(r.type==="igw")s.Properties.GatewayId=R.Ref(r.logicalId);else if(r.type==="nat")s.Properties.NatGatewayId=R.Ref(r.logicalId);else if(r.type==="instance")s.Properties.InstanceId=R.Ref(r.logicalId);return{route:s,logicalId:i}}static associateSubnetWithRouteTable(e,n){let r=o(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:R.Ref(e),RouteTableId:R.Ref(n)}},logicalId:r}}static enableFlowLogs(e){let{slug:n,environment:r,resourceId:i,resourceType:s,trafficType:a="ALL",logGroupName:c}=e,u=l({slug:n,environment:r,resourceType:"flowlog"}),d=o(u);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:s,ResourceIds:[i],TrafficType:a,LogDestinationType:"cloud-watch-logs",LogGroupName:c||`/aws/vpc/${n}-${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static calculateSubnetCidrs(e,n,r=3){let[i,s]=e.split("/"),a=Number.parseInt(s,10),c=Math.ceil(Math.log2(n*r)),u=a+c;if(u>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[d,m,p,g]=i.split(".").map(Number),y=(d<<24)+(m<<16)+(p<<8)+g,f=2**(32-u),h=[];for(let S=0;S<n*r;S++){let C=y+S*f,P=[C>>>24&255,C>>>16&255,C>>>8&255,C&255].join(".");h.push(`${P}/${u}`)}return h}static getAvailabilityZones(e,n){return["a","b","c","d","e","f"].slice(0,n).map((i)=>`${e}${i}`)}static createMultiAzNetwork(e){let{slug:n,environment:r,region:i,cidr:s="10.0.0.0/16",zones:a=3,enableNatGateway:c=!1,singleNatGateway:u=!1,enableFlowLogs:d=!1}=e,m={},p=[],g=[],y=[],{vpc:f,logicalId:h}=M.createVpc({slug:n,environment:r,cidr:s});m[h]=f;let{internetGateway:S,logicalId:C}=M.createInternetGateway(n,r);m[C]=S;let{attachment:P,logicalId:E}=M.attachInternetGateway(h,C);m[E]=P;let{routeTable:v,logicalId:w}=M.createRouteTable(n,r,h,"public");m[w]=v;let{route:D,logicalId:x}=M.createRoute(w,"0.0.0.0/0",{type:"igw",logicalId:C});D.DependsOn=E,m[x]=D;let L=M.calculateSubnetCidrs(s,a,2),B=M.getAvailabilityZones(i,a),O=[];for(let F=0;F<a;F++){let V=B[F],ce=L[F*2],q=L[F*2+1],{subnet:J,logicalId:K}=M.createSubnet({slug:n,environment:r,vpcId:R.Ref(h),type:"public",cidr:ce,availabilityZone:V});m[K]=J,p.push(K);let{association:Q,logicalId:ge}=M.associateSubnetWithRouteTable(K,w);m[ge]=Q;let{subnet:Te,logicalId:te}=M.createSubnet({slug:n,environment:r,vpcId:R.Ref(h),type:"private",cidr:q,availabilityZone:V});if(m[te]=Te,g.push(te),c&&(!u||F===0)){let{eip:Z,logicalId:re}=M.createEip(`${n}-${V}`,r);m[re]=Z;let{natGateway:fe,logicalId:se}=M.createNatGateway({slug:`${n}-${V}`,environment:r,subnetId:R.Ref(K)},re);fe.DependsOn=E,m[se]=fe,y.push(se);let{routeTable:ue,logicalId:Ee}=M.createRouteTable(`${n}-${V}`,r,h,"private");m[Ee]=ue,O.push(Ee);let{route:Oe,logicalId:k}=M.createRoute(Ee,"0.0.0.0/0",{type:"nat",logicalId:se});m[k]=Oe;let{association:G,logicalId:W}=M.associateSubnetWithRouteTable(te,Ee);m[W]=G}else if(c&&u&&F>0){let{association:Z,logicalId:re}=M.associateSubnetWithRouteTable(te,O[0]);m[re]=Z}else{let{routeTable:Z,logicalId:re}=M.createRouteTable(`${n}-${V}-isolated`,r,h,"private");m[re]=Z;let{association:fe,logicalId:se}=M.associateSubnetWithRouteTable(te,re);m[se]=fe}}if(d){let{flowLog:F,logicalId:V}=M.enableFlowLogs({slug:n,environment:r,resourceId:R.Ref(h),resourceType:"VPC"});m[V]=F}return{resources:m,outputs:{vpcId:h,publicSubnetIds:p,privateSubnetIds:g,natGatewayIds:y.length>0?y:void 0}}}static NatGatewayCostWarning=`
|
|
581
581
|
⚠️ NAT Gateway Cost Warning:
|
|
582
582
|
- Each NAT Gateway costs approximately $32-45/month (hourly charges)
|
|
583
583
|
- Data processing charges: $0.045/GB processed
|
|
@@ -585,7 +585,7 @@ echo "Redis server setup complete!"
|
|
|
585
585
|
- Using a single NAT Gateway (singleNatGateway: true)
|
|
586
586
|
- Using NAT Instances instead (cheaper but requires management)
|
|
587
587
|
- Disabling NAT entirely for isolated private subnets
|
|
588
|
-
`}class st{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:s,performanceMode:a="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:n,environment:r,resourceType:"efs"}),p=o(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:i,PerformanceMode:a,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(s)g.Properties.KmsKeyId=s;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,n){let{slug:r,environment:i,subnetId:s,securityGroups:a,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${s}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:s,SecurityGroups:a}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:s="/",uid:a="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${s.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:P.Ref(e),PosixUser:{Uid:a,Gid:c},RootDirectory:{Path:s,CreationInfo:{OwnerUid:a,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${s}`},{Key:"Environment",Value:i}]}},logicalId:m}}static setLifecyclePolicy(e,n){let{transitionToIA:r,transitionToPrimary:i=!1}=n;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let s=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:s})}if(i)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,n){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=n,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s=[],sourceCidrBlocks:a=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of s)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:g,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${n} ${r}`,VpcId:i,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,n){let{slug:r,environment:i,subnetIds:s,securityGroupId:a}=n,c=[],u=[];for(let d=0;d<s.length;d++){let m=s[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:m,SecurityGroups:[a]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:s,sourceSecurityGroupIds:a=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=st.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)st.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=st.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:a});g[S]=h;let{mountTargets:C,logicalIds:E}=st.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:s,securityGroupId:P.Ref(S)});for(let w=0;w<C.length;w++)g[E[w]]=C[w];return{resources:g,outputs:{fileSystemId:f,securityGroupId:S,mountTargetIds:E}}}}class N{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:s=!0,dkimKeyLength:a="RSA_2048_BIT"}=e,c=l({slug:r,environment:i,resourceType:"ses-identity"}),u=o(`${c}-${n.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(s)d.Properties.DkimSigningAttributes={NextSigningKeyLength:a};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let s=0;s<n.length;s++){let a=n[s],c=o(`dkim-${e.replace(/\./g,"")}-${s+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${a}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${a}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:s=!0,sendingEnabled:a=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=i||l({slug:n,environment:r,resourceType:"ses-config"}),m=o(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:s},SendingOptions:{SendingEnabled:a},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,s=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),a=o(s);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:s}},logicalId:a}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:s,recipients:a,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=n,y=l({slug:r,environment:i,resourceType:"ses-rule"}),f=o(y),h=[];if(m)h.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)h.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)h.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:s,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:a,Actions:h.length>0?h:void 0}}},logicalId:f}}static createMxRecord(e,n,r){let i=o(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:i}}static createVerificationRecord(e,n,r){let i=o(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${n}"`]}},logicalId:i}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,n,r){let{includeDomains:i=[],softFail:s=!1}=r||{},a=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=s?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:a}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:s,percentage:a=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${a}`;if(s)m+=`; sp=${s}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3KeyPrefix:a="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=N.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=N.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:s,prefix:a},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:C}=N.createMxRecord(i,u,c);return p[C]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:C}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:s,region:a,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=N.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=N.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=N.createSpfRecord(i,s);m[S]=h;let{record:C,logicalId:E}=N.createDmarcRecord(i,s,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[E]=C,c&&u){let w=N.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:a,hostedZoneId:s});Object.assign(m,w.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:f}}}static InboundSmtpEndpoints={"us-east-1":"inbound-smtp.us-east-1.amazonaws.com","us-west-2":"inbound-smtp.us-west-2.amazonaws.com","eu-west-1":"inbound-smtp.eu-west-1.amazonaws.com"};static supportsInboundEmail(e){return e in N.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:s}=e,a=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(a),u=o(`${a}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(s)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:s});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${a}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[P.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:s,configurationSetName:a,timeout:c=30,memorySize:u=256}=e,d=l({slug:n,environment:r,resourceType:"outbound-email"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:s,CONFIGURATION_SET:a||""}},Code:{ZipFile:N.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,organizedPrefix:a="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"inbound-email"}),m=o(d),p=o(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,ORGANIZED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName:P.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:P.Ref("AWS::AccountId")}};return{function:g,permission:y,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,convertedPrefix:a="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"email-conversion"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,CONVERTED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:n,prefix:r="inbound/",suffix:i,events:s}=e,a=s??["s3:ObjectCreated:*"],c={};if(r||i){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(i)c.S3Key.Rules.push({Name:"suffix",Value:i})}return{notificationConfiguration:{LambdaConfigurations:[{Event:a[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:s}=e,a=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(a);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:P.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:s}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3BucketArn:a,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=N.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:a,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=N.createOutboundEmailLambda({slug:n,environment:r,roleArn:P.GetAtt(y,"Arn"),domain:i,configurationSetName:c});m[S]=h;let C={roleLogicalId:y,outboundLambdaLogicalId:S};if(u){let{function:E,permission:w,logicalId:v,permissionLogicalId:I}=N.createInboundEmailLambda({slug:n,environment:r,roleArn:P.GetAtt(y,"Arn"),s3BucketName:s});m[v]=E,m[I]=w;let{permission:D,logicalId:x}=N.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:v,s3BucketArn:a});m[x]=D,C.inboundLambdaLogicalId=v}if(d){let{function:E,logicalId:w}=N.createEmailConversionLambda({slug:n,environment:r,roleArn:P.GetAtt(y,"Arn"),s3BucketName:s});m[w]=E,C.conversionLambdaLogicalId=w}return{resources:m,outputs:C}}static LambdaCode={outboundEmail:`
|
|
588
|
+
`}class at{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:s,performanceMode:a="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:n,environment:r,resourceType:"efs"}),p=o(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:i,PerformanceMode:a,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(s)g.Properties.KmsKeyId=s;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,n){let{slug:r,environment:i,subnetId:s,securityGroups:a,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${s}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:s,SecurityGroups:a}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:s="/",uid:a="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${s.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:R.Ref(e),PosixUser:{Uid:a,Gid:c},RootDirectory:{Path:s,CreationInfo:{OwnerUid:a,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${s}`},{Key:"Environment",Value:i}]}},logicalId:m}}static setLifecyclePolicy(e,n){let{transitionToIA:r,transitionToPrimary:i=!1}=n;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let s=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:s})}if(i)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,n){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=n,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s=[],sourceCidrBlocks:a=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of s)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:g,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${n} ${r}`,VpcId:i,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,n){let{slug:r,environment:i,subnetIds:s,securityGroupId:a}=n,c=[],u=[];for(let d=0;d<s.length;d++){let m=s[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:m,SecurityGroups:[a]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:s,sourceSecurityGroupIds:a=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=at.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)at.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=at.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:a});g[S]=h;let{mountTargets:C,logicalIds:P}=at.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:s,securityGroupId:R.Ref(S)});for(let E=0;E<C.length;E++)g[P[E]]=C[E];return{resources:g,outputs:{fileSystemId:f,securityGroupId:S,mountTargetIds:P}}}}class N{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:s=!0,dkimKeyLength:a="RSA_2048_BIT"}=e,c=l({slug:r,environment:i,resourceType:"ses-identity"}),u=o(`${c}-${n.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(s)d.Properties.DkimSigningAttributes={NextSigningKeyLength:a};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let s=0;s<n.length;s++){let a=n[s],c=o(`dkim-${e.replace(/\./g,"")}-${s+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${a}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${a}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:s=!0,sendingEnabled:a=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=i||l({slug:n,environment:r,resourceType:"ses-config"}),m=o(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:s},SendingOptions:{SendingEnabled:a},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,s=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),a=o(s);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:s}},logicalId:a}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:s,recipients:a,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=n,y=l({slug:r,environment:i,resourceType:"ses-rule"}),f=o(y),h=[];if(m)h.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)h.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)h.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:s,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:a,Actions:h.length>0?h:void 0}}},logicalId:f}}static createMxRecord(e,n,r){let i=o(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:i}}static createVerificationRecord(e,n,r){let i=o(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${n}"`]}},logicalId:i}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,n,r){let{includeDomains:i=[],softFail:s=!1}=r||{},a=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=s?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:a}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:s,percentage:a=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${a}`;if(s)m+=`; sp=${s}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3KeyPrefix:a="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=N.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=N.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:s,prefix:a},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:C}=N.createMxRecord(i,u,c);return p[C]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:C}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:s,region:a,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=N.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=N.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=N.createSpfRecord(i,s);m[S]=h;let{record:C,logicalId:P}=N.createDmarcRecord(i,s,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[P]=C,c&&u){let E=N.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:a,hostedZoneId:s});Object.assign(m,E.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:f}}}static InboundSmtpEndpoints={"us-east-1":"inbound-smtp.us-east-1.amazonaws.com","us-west-2":"inbound-smtp.us-west-2.amazonaws.com","eu-west-1":"inbound-smtp.eu-west-1.amazonaws.com"};static supportsInboundEmail(e){return e in N.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:s}=e,a=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(a),u=o(`${a}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(s)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:s});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${a}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[R.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:s,configurationSetName:a,timeout:c=30,memorySize:u=256}=e,d=l({slug:n,environment:r,resourceType:"outbound-email"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:s,CONFIGURATION_SET:a||""}},Code:{ZipFile:N.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,organizedPrefix:a="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"inbound-email"}),m=o(d),p=o(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,ORGANIZED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:R.Ref("AWS::AccountId")}};return{function:g,permission:y,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,convertedPrefix:a="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"email-conversion"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,CONVERTED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:n,prefix:r="inbound/",suffix:i,events:s}=e,a=s??["s3:ObjectCreated:*"],c={};if(r||i){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(i)c.S3Key.Rules.push({Name:"suffix",Value:i})}return{notificationConfiguration:{LambdaConfigurations:[{Event:a[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:s}=e,a=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(a);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:s}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3BucketArn:a,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=N.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:a,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=N.createOutboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),domain:i,configurationSetName:c});m[S]=h;let C={roleLogicalId:y,outboundLambdaLogicalId:S};if(u){let{function:P,permission:E,logicalId:v,permissionLogicalId:w}=N.createInboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:s});m[v]=P,m[w]=E;let{permission:D,logicalId:x}=N.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:v,s3BucketArn:a});m[x]=D,C.inboundLambdaLogicalId=v}if(d){let{function:P,logicalId:E}=N.createEmailConversionLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:s});m[E]=P,C.conversionLambdaLogicalId=E}return{resources:m,outputs:C}}static LambdaCode={outboundEmail:`
|
|
589
589
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
590
590
|
const ses = new SESClient({});
|
|
591
591
|
|
|
@@ -1623,7 +1623,7 @@ catch (error) {
|
|
|
1623
1623
|
|
|
1624
1624
|
return { statusCode: 200, body: 'OK' };
|
|
1625
1625
|
};
|
|
1626
|
-
`;class Dt{static LambdaCode={incomingCall:yt,voicemail:an,missedCall:sn};static createConnectInstance(e){let{slug:n,environment:r,instanceAlias:i,inboundCallsEnabled:s=!0,outboundCallsEnabled:a=!0}=e;return{[`${n}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:i,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:s,OutboundCalls:a,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(e){return{[`${e.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:e.instanceArn,Name:e.name,TimeZone:e.timezone,Config:e.schedule.map((n)=>({Day:n.day,StartTime:{Hours:n.startHour,Minutes:n.startMinute},EndTime:{Hours:n.endHour,Minutes:n.endMinute}}))}}}}static createQueue(e){return{[`${e.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:e.instanceArn,Name:e.name,HoursOfOperationArn:e.hoursOfOperationArn,MaxContacts:e.maxContacts||10}}}}static createContactFlow(e){return{[`${e.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:e.instanceArn,Name:e.name,Type:e.type,Content:e.content}}}}static createBasicIvrFlow(e){let n={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:e.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:e.queueArn},Transitions:{NextAction:e.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...e.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(n)}static createPhoneLambdaRole(e){return{[`${e.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-phone-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(e){return{[`${e.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Dt.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createVoicemailLambda(e){return{[`${e.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:Dt.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:e.voicemailBucket,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",TRANSCRIPTION_ENABLED:e.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(e){return{[`${e.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Dt.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createCallLogTable(e){return{[`${e.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(e){let n={},r={};Object.assign(n,Dt.createPhoneLambdaRole({slug:e.slug})),Object.assign(n,Dt.createCallLogTable({slug:e.slug})),n[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},n[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let i={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},s={Ref:`${e.slug}PhoneNotificationTopic`},a={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(n,Dt.createIncomingCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(n,Dt.createVoicemailLambda({slug:e.slug,roleArn:i,voicemailBucket:c,notificationTopicArn:s,callLogTable:a,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(n,Dt.createMissedCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),r[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},r[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},r[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:n,outputs:r}}}class ye{static createQueue(e){let{slug:n,environment:r,name:i,delaySeconds:s=0,visibilityTimeout:a=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:y}=e,f=i||l({slug:n,environment:r,resourceType:"queue"}),h=m?`${f}.fifo`:f,S=o(f),C={Type:"AWS::SQS::Queue",Properties:{QueueName:h,DelaySeconds:s,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:a,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(m)C.Properties.FifoQueue=!0,C.Properties.ContentBasedDeduplication=p;if(g)if(y)C.Properties.KmsMasterKeyId=y;else C.Properties.SqsManagedSseEnabled=!0;return{queue:C,logicalId:S}}static createDeadLetterQueue(e,n){let{slug:r,environment:i,maxReceiveCount:s=3}=n,a=l({slug:r,environment:i,resourceType:"dlq"}),c=o(a),u={Type:"AWS::SQS::Queue",Properties:{QueueName:a,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:P.GetAtt(c,"Arn"),maxReceiveCount:s}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"schedule"}),d=o(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:a,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,n,r){let{slug:i,environment:s,name:a,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:y=!1,taskCount:f=1,containerOverrides:h}=r,S=a||l({slug:i,environment:s,resourceType:"ecs-schedule"}),C=o(S),w={Id:"1",Arn:m,RoleArn:n,EcsParameters:{TaskDefinitionArn:d,TaskCount:f,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:y?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(h&&h.length>0)w.Input=JSON.stringify({containerOverrides:h});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:S,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[w]}},logicalId:C}}static scheduleLambda(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,functionArn:u,input:d}=n,m=s||l({slug:r,environment:i,resourceType:"lambda-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,queueArn:u,messageGroupId:d}=n,m=s||l({slug:r,environment:i,resourceType:"sqs-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,n){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:n.id,Arn:n.arn};if(n.roleArn)r.RoleArn=n.roleArn;if(n.input)r.Input=JSON.stringify(n.input);return e.Properties.Targets.push(r),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,n){return`rate(${e} ${n})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(e){let n=e.toLowerCase().trim(),r=n.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(r){let m=parseInt(r[1],10),p=r[2].toLowerCase(),g=p.endsWith("s")&&m===1?p.slice(0,-1):p,y=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:y})`}let i=n.match(/^every\s+(minute|hour|day)$/i);if(i)return`rate(1 ${i[1]})`;let s={"every minute":"rate(1 minute)","every hour":"rate(1 hour)","every day":"rate(1 day)",hourly:"cron(0 * * * ? *)",daily:"cron(0 0 * * ? *)","daily at midnight":"cron(0 0 * * ? *)",weekly:"cron(0 0 ? * SUN *)",monthly:"cron(0 0 1 * ? *)",yearly:"cron(0 0 1 1 ? *)"};if(s[n])return s[n];let a=n.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(a){let m=parseInt(a[1],10),p=a[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=n.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(c){let m=parseInt(c[1],10);return`cron(${parseInt(c[2],10)} ${m} * * ? *)`}let u={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},d=n.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return ye.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:n,handler:r,retries:i=3,backoff:s="exponential",backoffDelay:a=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:n,handler:r,retries:i,backoff:s,backoffDelay:a,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,n)=>{let{backoff:r,backoffDelay:i,maxDelay:s,jitter:a}=n,c;switch(r){case"linear":c=i*e;break;case"exponential":c=i*2**(e-1);break;case"fixed":default:c=i}if(c=Math.min(c,s||Number.MAX_SAFE_INTEGER),a){let u=c*0.25*Math.random();c+=u}return Math.floor(c)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(e){let{containerName:n,jobClass:r,jobData:i,environment:s={}}=e,a=[{name:"JOB_CLASS",value:r}];if(i)a.push({name:"JOB_DATA",value:JSON.stringify(i)});for(let[c,u]of Object.entries(s))a.push({name:c,value:u});return{name:n,command:["bun","run","app/Jobs/runner.ts"],environment:a}}static createScheduledJob(e){let{slug:n,environment:r,schedule:i,jobClass:s,jobData:a,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,y=ye.rateStringToExpression(i),f=ye.createJobContainerOverride({containerName:g,jobClass:s,jobData:a});return ye.scheduleEcsTask(y,p,{slug:n,environment:r,name:`${n}-${s.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${s}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[f]})}static QueuePresets={highThroughput:(e,n)=>ye.createQueue({slug:e,environment:n,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,n)=>ye.createQueue({slug:e,environment:n,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,n)=>ye.createQueue({slug:e,environment:n,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,n,r=60)=>ye.createQueue({slug:e,environment:n,delaySeconds:r})}}class Xt{static async discoverJobs(e){let{projectRoot:n,jobsPath:r="app/Jobs"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Xt.parseJobMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseJobMetadata(e,n,r){let i=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),s=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),a=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),c=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),u=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),d=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:n,path:r,schedule:i?.[1],handler:`${n}.handle`,enabled:s?.[1]!=="false",retries:a?parseInt(a[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:n,actionsPath:r="app/Actions"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Xt.parseActionMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseActionMetadata(e,n,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let s=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:n,path:r,handler:`${n}.handle`,description:s?.[1]}}static generateScheduledJobResources(e){let{slug:n,environment:r,jobs:i,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let y of i){if(!y.schedule||!y.enabled)continue;let{rule:f,logicalId:h}=ye.createScheduledJob({slug:n,environment:r,schedule:y.schedule,jobClass:y.name,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[h]=f,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1626
|
+
`;class Dt{static LambdaCode={incomingCall:yt,voicemail:an,missedCall:sn};static createConnectInstance(e){let{slug:n,environment:r,instanceAlias:i,inboundCallsEnabled:s=!0,outboundCallsEnabled:a=!0}=e;return{[`${n}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:i,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:s,OutboundCalls:a,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(e){return{[`${e.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:e.instanceArn,Name:e.name,TimeZone:e.timezone,Config:e.schedule.map((n)=>({Day:n.day,StartTime:{Hours:n.startHour,Minutes:n.startMinute},EndTime:{Hours:n.endHour,Minutes:n.endMinute}}))}}}}static createQueue(e){return{[`${e.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:e.instanceArn,Name:e.name,HoursOfOperationArn:e.hoursOfOperationArn,MaxContacts:e.maxContacts||10}}}}static createContactFlow(e){return{[`${e.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:e.instanceArn,Name:e.name,Type:e.type,Content:e.content}}}}static createBasicIvrFlow(e){let n={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:e.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:e.queueArn},Transitions:{NextAction:e.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...e.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(n)}static createPhoneLambdaRole(e){return{[`${e.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-phone-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(e){return{[`${e.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Dt.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createVoicemailLambda(e){return{[`${e.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:Dt.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:e.voicemailBucket,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",TRANSCRIPTION_ENABLED:e.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(e){return{[`${e.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Dt.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createCallLogTable(e){return{[`${e.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(e){let n={},r={};Object.assign(n,Dt.createPhoneLambdaRole({slug:e.slug})),Object.assign(n,Dt.createCallLogTable({slug:e.slug})),n[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},n[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let i={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},s={Ref:`${e.slug}PhoneNotificationTopic`},a={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(n,Dt.createIncomingCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(n,Dt.createVoicemailLambda({slug:e.slug,roleArn:i,voicemailBucket:c,notificationTopicArn:s,callLogTable:a,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(n,Dt.createMissedCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),r[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},r[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},r[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:n,outputs:r}}}class ye{static createQueue(e){let{slug:n,environment:r,name:i,delaySeconds:s=0,visibilityTimeout:a=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:y}=e,f=i||l({slug:n,environment:r,resourceType:"queue"}),h=m?`${f}.fifo`:f,S=o(f),C={Type:"AWS::SQS::Queue",Properties:{QueueName:h,DelaySeconds:s,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:a,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(m)C.Properties.FifoQueue=!0,C.Properties.ContentBasedDeduplication=p;if(g)if(y)C.Properties.KmsMasterKeyId=y;else C.Properties.SqsManagedSseEnabled=!0;return{queue:C,logicalId:S}}static createDeadLetterQueue(e,n){let{slug:r,environment:i,maxReceiveCount:s=3}=n,a=l({slug:r,environment:i,resourceType:"dlq"}),c=o(a),u={Type:"AWS::SQS::Queue",Properties:{QueueName:a,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:R.GetAtt(c,"Arn"),maxReceiveCount:s}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"schedule"}),d=o(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:a,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,n,r){let{slug:i,environment:s,name:a,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:y=!1,taskCount:f=1,containerOverrides:h}=r,S=a||l({slug:i,environment:s,resourceType:"ecs-schedule"}),C=o(S),E={Id:"1",Arn:m,RoleArn:n,EcsParameters:{TaskDefinitionArn:d,TaskCount:f,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:y?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(h&&h.length>0)E.Input=JSON.stringify({containerOverrides:h});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:S,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[E]}},logicalId:C}}static scheduleLambda(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,functionArn:u,input:d}=n,m=s||l({slug:r,environment:i,resourceType:"lambda-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,queueArn:u,messageGroupId:d}=n,m=s||l({slug:r,environment:i,resourceType:"sqs-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,n){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:n.id,Arn:n.arn};if(n.roleArn)r.RoleArn=n.roleArn;if(n.input)r.Input=JSON.stringify(n.input);return e.Properties.Targets.push(r),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,n){return`rate(${e} ${n})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(e){let n=e.toLowerCase().trim(),r=n.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(r){let m=parseInt(r[1],10),p=r[2].toLowerCase(),g=p.endsWith("s")&&m===1?p.slice(0,-1):p,y=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:y})`}let i=n.match(/^every\s+(minute|hour|day)$/i);if(i)return`rate(1 ${i[1]})`;let s={"every minute":"rate(1 minute)","every hour":"rate(1 hour)","every day":"rate(1 day)",hourly:"cron(0 * * * ? *)",daily:"cron(0 0 * * ? *)","daily at midnight":"cron(0 0 * * ? *)",weekly:"cron(0 0 ? * SUN *)",monthly:"cron(0 0 1 * ? *)",yearly:"cron(0 0 1 1 ? *)"};if(s[n])return s[n];let a=n.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(a){let m=parseInt(a[1],10),p=a[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=n.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(c){let m=parseInt(c[1],10);return`cron(${parseInt(c[2],10)} ${m} * * ? *)`}let u={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},d=n.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return ye.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:n,handler:r,retries:i=3,backoff:s="exponential",backoffDelay:a=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:n,handler:r,retries:i,backoff:s,backoffDelay:a,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,n)=>{let{backoff:r,backoffDelay:i,maxDelay:s,jitter:a}=n,c;switch(r){case"linear":c=i*e;break;case"exponential":c=i*2**(e-1);break;case"fixed":default:c=i}if(c=Math.min(c,s||Number.MAX_SAFE_INTEGER),a){let u=c*0.25*Math.random();c+=u}return Math.floor(c)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(e){let{containerName:n,jobClass:r,jobData:i,environment:s={}}=e,a=[{name:"JOB_CLASS",value:r}];if(i)a.push({name:"JOB_DATA",value:JSON.stringify(i)});for(let[c,u]of Object.entries(s))a.push({name:c,value:u});return{name:n,command:["bun","run","app/Jobs/runner.ts"],environment:a}}static createScheduledJob(e){let{slug:n,environment:r,schedule:i,jobClass:s,jobData:a,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,y=ye.rateStringToExpression(i),f=ye.createJobContainerOverride({containerName:g,jobClass:s,jobData:a});return ye.scheduleEcsTask(y,p,{slug:n,environment:r,name:`${n}-${s.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${s}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[f]})}static QueuePresets={highThroughput:(e,n)=>ye.createQueue({slug:e,environment:n,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,n)=>ye.createQueue({slug:e,environment:n,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,n)=>ye.createQueue({slug:e,environment:n,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,n,r=60)=>ye.createQueue({slug:e,environment:n,delaySeconds:r})}}class Xt{static async discoverJobs(e){let{projectRoot:n,jobsPath:r="app/Jobs"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Xt.parseJobMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseJobMetadata(e,n,r){let i=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),s=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),a=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),c=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),u=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),d=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:n,path:r,schedule:i?.[1],handler:`${n}.handle`,enabled:s?.[1]!=="false",retries:a?parseInt(a[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:n,actionsPath:r="app/Actions"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Xt.parseActionMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseActionMetadata(e,n,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let s=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:n,path:r,handler:`${n}.handle`,description:s?.[1]}}static generateScheduledJobResources(e){let{slug:n,environment:r,jobs:i,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let y of i){if(!y.schedule||!y.enabled)continue;let{rule:f,logicalId:h}=ye.createScheduledJob({slug:n,environment:r,schedule:y.schedule,jobClass:y.name,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[h]=f,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1627
1627
|
/**
|
|
1628
1628
|
* Job Runner Script
|
|
1629
1629
|
* This script is invoked by ECS scheduled tasks to run jobs
|
|
@@ -2271,14 +2271,14 @@ function resolveTemplate(template, data) {
|
|
|
2271
2271
|
}
|
|
2272
2272
|
return result;
|
|
2273
2273
|
}
|
|
2274
|
-
`;class Re{static LambdaCode={send:ft,receive:cn,deliveryStatus:on};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let n={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)n.SenderId=e.senderId;if(e.shortCode)n.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:n}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-sms-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:e.pinpointAppId,MESSAGE_LOG_TABLE:e.messageLogTable||"",SMS_SENDER_ID:e.senderId||"",SMS_ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static createReceiveLambda(e){return{[`${e.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:e.optOutTable||"",MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createDeliveryStatusLambda(e){return{[`${e.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let n={},r={};Object.assign(n,Re.createPinpointApp({slug:e.slug})),Object.assign(n,Re.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(n,Re.createSmsLambdaRole({slug:e.slug})),Object.assign(n,Re.createMessageLogTable({slug:e.slug})),Object.assign(n,Re.createOptOutTable({slug:e.slug})),Object.assign(n,Re.createNotificationTopic({slug:e.slug}));let i={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},s={Ref:`${e.slug}PinpointApp`},a={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(n,Re.createSendLambda({slug:e.slug,roleArn:i,pinpointAppId:s,messageLogTable:a,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Re.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Re.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:n,outputs:r}}}function ht(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function xr(e,n){let r=(e||n).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${n}`);return r}function kr(e){let n=e.storage;if(n?.type==="efs"){let i="fileSystemId"in n?n.fileSystemId:void 0;if(!i||typeof i==="string"&&!i.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:i,posixProfile:n.posixProfile}}let r=(n?.type==="s3"?n.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function Mr(e,n,r){let i=n.posixProfile??r;if(!i)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let s of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(s)||s<0||s>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${s}`);return{Uid:i.uid,Gid:i.gid,...i.secondaryGids?.length?{SecondaryGids:i.secondaryGids}:{}}}function Lr(e,n){return typeof e==="string"?`/${e}/${n}`:{"Fn::Sub":[`/\${FileSystemId}/${n}`,{FileSystemId:e}]}}function Or(e){return typeof e==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",e)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:e}]}}class ts{static create(e){let n=kr(e),r=n.type==="efs"?"EFS":"S3",i=e.endpointType??"PUBLIC";if(i==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let s=`${ht(e.slug)}${ht(e.environment)}Sftp`,a=`${s}Server`,c={},u;if(e.logging!==!1){let d=`${s}LoggingRole`;c[d]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[a]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:i,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...i==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=ht(d),g=xr(m.homeDirectory,d),y=`${s}${p}User`,f=m.roleArn;if(!f){let h=`${s}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Or(n.fileSystemId)}];else{let C=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:C,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${C}/${g}/*`}]}c[h]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"SftpHomeDirectory",PolicyDocument:{Version:"2012-10-17",Statement:S}}]}},f={"Fn::GetAtt":[h,"Arn"]}}c[y]={Type:"AWS::Transfer::User",DependsOn:[a],Properties:{ServerId:{Ref:a},UserName:d,Role:f,HomeDirectoryType:"PATH",HomeDirectory:n.type==="efs"?Lr(n.fileSystemId,g):`/${n.bucket}/${g}`,...n.type==="efs"?{PosixProfile:Mr(d,m,n.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:a,domain:r}}}class Ge{static createBedrockRole(e,n){let{slug:r,environment:i,name:s,models:a=["*"],allowStreaming:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=a.map((y)=>y==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${y}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:n,environment:r,name:i,models:s=["*"],allowInvoke:a=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(a)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=s.map((f)=>f==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${f}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return Ge.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return Ge.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return Ge.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let s=n.map((a)=>a==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${a}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:s}]}}),e}static Models={Claude3_5_Sonnet:"anthropic.claude-3-5-sonnet-20241022-v2:0",Claude3_5_Haiku:"anthropic.claude-3-5-haiku-20241022-v1:0",Claude3_Opus:"anthropic.claude-3-opus-20240229-v1:0",Claude3_Sonnet:"anthropic.claude-3-sonnet-20240229-v1:0",Claude3_Haiku:"anthropic.claude-3-haiku-20240307-v1:0",TitanTextG1Express:"amazon.titan-text-express-v1",TitanTextG1Lite:"amazon.titan-text-lite-v1",TitanEmbedG1Text:"amazon.titan-embed-text-v1",TitanImageG1:"amazon.titan-image-generator-v1",JurassicUltra:"ai21.j2-ultra-v1",JurassicMid:"ai21.j2-mid-v1",CommandText:"cohere.command-text-v14",CommandLight:"cohere.command-light-text-v14",EmbedEnglish:"cohere.embed-english-v3",EmbedMultilingual:"cohere.embed-multilingual-v3",Llama3_2_1B:"meta.llama3-2-1b-instruct-v1:0",Llama3_2_3B:"meta.llama3-2-3b-instruct-v1:0",Llama3_2_11B:"meta.llama3-2-11b-instruct-v1:0",Llama3_2_90B:"meta.llama3-2-90b-instruct-v1:0",Llama3_1_8B:"meta.llama3-1-8b-instruct-v1:0",Llama3_1_70B:"meta.llama3-1-70b-instruct-v1:0",Llama3_1_405B:"meta.llama3-1-405b-instruct-v1:0",Mistral7B:"mistral.mistral-7b-instruct-v0:2",Mixtral8x7B:"mistral.mixtral-8x7b-instruct-v0:1",MistralLarge:"mistral.mistral-large-2402-v1:0",StableDiffusionXL:"stability.stable-diffusion-xl-v1"};static ModelGroups={AllClaude:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","anthropic.claude-3-opus-20240229-v1:0","anthropic.claude-3-sonnet-20240229-v1:0","anthropic.claude-3-haiku-20240307-v1:0"],AllTitan:["amazon.titan-text-express-v1","amazon.titan-text-lite-v1","amazon.titan-embed-text-v1","amazon.titan-image-generator-v1"],AllLlama:["meta.llama3-2-1b-instruct-v1:0","meta.llama3-2-3b-instruct-v1:0","meta.llama3-2-11b-instruct-v1:0","meta.llama3-2-90b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-405b-instruct-v1:0"],TextModels:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","amazon.titan-text-express-v1","meta.llama3-2-11b-instruct-v1:0","mistral.mistral-7b-instruct-v0:2"],EmbeddingModels:["amazon.titan-embed-text-v1","cohere.embed-english-v3","cohere.embed-multilingual-v3"],ImageModels:["amazon.titan-image-generator-v1","stability.stable-diffusion-xl-v1"]}}class Qt{static createPostgres(e){return Qt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Qt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:s,instanceClass:a="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:y,encrypted:f=!0,kmsKeyId:h,multiAz:S=!1,backupRetentionDays:C=7,publiclyAccessible:E=!1,enableCloudwatchLogs:w=!0,deletionProtection:v=!0}=r,I=l({slug:i,environment:s,resourceType:`${e}-db`}),D=o(I),x,L;if(g&&g.length>0){let O=l({slug:i,environment:s,resourceType:"db-subnet-group"});L=o(O),x={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${I}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:s}]}}}let B={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:I,DBInstanceClass:a,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:C,PubliclyAccessible:E,DeletionProtection:v,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:s}]}};if(p)B.Properties.DBName=p;if(h)B.Properties.KmsKeyId=h;if(L)B.Properties.DBSubnetGroupName=P.Ref(L);if(y&&y.length>0)B.Properties.VPCSecurityGroups=y;if(w)B.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:B,subnetGroup:x,logicalId:D,subnetGroupId:L}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:s="db.t3.micro",securityGroupIds:a,publiclyAccessible:c=!1}=n,u=l({slug:r,environment:i,resourceType:"db-replica"}),d=o(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:s,SourceDBInstanceIdentifier:P.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(a&&a.length>0)m.Properties.VPCSecurityGroups=a;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:s,parameters:a={}}=r,c=l({slug:i,environment:s,resourceType:"db-params"}),u=o(c),d=e==="postgres"?`postgres${n.split(".")[0]}`:`mysql${n.split(".")[0]}.${n.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:s,sortKey:a,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:y,pointInTimeRecovery:f=!0,ttlAttribute:h}=e,S=i||l({slug:n,environment:r,resourceType:"table"}),C=o(S),E=[{AttributeName:s.name,AttributeType:s.type}];if(a)E.push({AttributeName:a.name,AttributeType:a.type});let w=[{AttributeName:s.name,KeyType:"HASH"}];if(a)w.push({AttributeName:a.name,KeyType:"RANGE"});let v={Type:"AWS::DynamoDB::Table",Properties:{TableName:S,BillingMode:c,AttributeDefinitions:E,KeySchema:w,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")v.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)v.Properties.StreamSpecification={StreamViewType:p};if(g)v.Properties.SSESpecification={SSEEnabled:!0,SSEType:y?"KMS":"AES256",KMSMasterKeyId:y};if(f)v.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)v.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:v,logicalId:C}}static addGlobalSecondaryIndex(e,n){let{indexName:r,partitionKey:i,sortKey:s,projectionType:a="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=n;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});if(s&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===s.name))e.Properties.AttributeDefinitions.push({AttributeName:s.name,AttributeType:s.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(s)m.push({AttributeName:s.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:a,NonKeyAttributes:a==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,n="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:n},e}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class ji{static createRedis(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="7.1",port:a=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:y=1,replicasPerNodeGroup:f=1,atRestEncryption:h=!0,transitEncryption:S=!0,authToken:C,kmsKeyId:E,snapshotRetentionDays:w=7,snapshotWindow:v,maintenanceWindow:I}=e,D=l({slug:n,environment:r,resourceType:"redis"}),x=o(D),L,B;if(c&&c.length>0){let F=l({slug:n,environment:r,resourceType:"cache-subnet-group"});B=o(F),L={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:F,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:F},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:s,CacheNodeType:i,Port:a,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit:w,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:r}]}};if(g)O.Properties.NumNodeGroups=y,O.Properties.ReplicasPerNodeGroup=f;else O.Properties.NumCacheClusters=d;if(C)O.Properties.AuthToken=C;if(E)O.Properties.KmsKeyId=E;if(B)O.Properties.CacheSubnetGroupName=P.Ref(B);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(v)O.Properties.SnapshotWindow=v;if(I)O.Properties.PreferredMaintenanceWindow=I;return{replicationGroup:O,subnetGroup:L,logicalId:x,subnetGroupId:B}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="1.6.22",port:a=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,y=l({slug:n,environment:r,resourceType:"memcached"}),f=o(y),h,S;if(u&&u.length>0){let E=l({slug:n,environment:r,resourceType:"cache-subnet-group"});S=o(E),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:E,Description:`Subnet group for ${y}`,SubnetIds:u,Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:r}]}}}let C={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:y,CacheNodeType:i,Engine:"memcached",EngineVersion:s,NumCacheNodes:c,Port:a,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(S)C.Properties.CacheSubnetGroupName=P.Ref(S);if(d&&d.length>0)C.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)C.Properties.PreferredAvailabilityZones=p;if(g)C.Properties.PreferredMaintenanceWindow=g;return{cluster:C,subnetGroup:h,logicalId:f,subnetGroupId:S}}static enableClusterMode(e,n=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=n,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Ie{static createUser(e){let{slug:n,environment:r,userName:i,groups:s,managedPolicyArns:a}=e,c=i||l({slug:n,environment:r,resourceType:"user"}),u=o(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(s&&s.length>0)d.Properties.Groups=s;if(a&&a.length>0)d.Properties.ManagedPolicyArns=a;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:s,awsPrincipal:a,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(s)m.Service=s;if(a)m.AWS=a;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:n,environment:r,groupName:i,managedPolicyArns:s}=e,a=i||l({slug:n,environment:r,resourceType:"group"}),c=o(a),u={Type:"AWS::IAM::Group",Properties:{GroupName:a}};if(s&&s.length>0)u.Properties.ManagedPolicyArns=s;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:s,statements:a}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=a.map((p)=>({Sid:p.sid,Effect:p.effect||"Allow",Action:p.actions,Resource:p.resources,Condition:p.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:s||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToUser(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToGroup(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static addInlinePolicyToRole(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static addInlinePolicyToUser(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static createAccessKey(e,n){let{slug:r,environment:i,status:s="Active"}=n,a=l({slug:r,environment:i,resourceType:"access-key"}),c=o(a);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:P.Ref(e),Status:s}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:s}=n,a=s||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(a);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:a,Roles:[P.Ref(e)]}},logicalId:c}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(e){let{slug:n,environment:r,permissions:i,createAccessKey:s=!0}=e,a={},c=[];if(i.s3Buckets&&i.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...i.s3Buckets,...i.s3Buckets.map((f)=>`${f}/*`)]});if(i.cloudFrontDistributions&&i.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:i.cloudFrontDistributions});if(i.ecrRepositories&&i.ecrRepositories.length>0)c.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:i.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(i.ecsServices&&i.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:i.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(i.cloudFormationStacks&&i.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:i.cloudFormationStacks});if(i.lambdaFunctions&&i.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:i.lambdaFunctions});if(i.secretsManagerSecrets&&i.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:i.secretsManagerSecrets});let{policy:u,logicalId:d}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${n} (${r})`,statements:c});a[d]=u;let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[P.Ref(d)]});a[p]=m;let g,y;if(s){let f=Ie.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,a[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:s,permissions:a,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${n} (${r})`,statements:a});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(s)y.StringEquals={"sts:ExternalId":s};let f={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:i.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(y).length>0?{Condition:y}:{}}]},ManagedPolicyArns:[P.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=f,{role:f,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:n,environment:r,permissions:i="readonly"}=e,s={},a=[],c=[];switch(i){case"readonly":c=[Ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":a=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Ie.ManagedPolicies.AdministratorAccess];break}let u,d;if(a.length>0){let f=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${n} (${r})`,statements:a});u=f.policy,d=f.logicalId,s[d]=u,c=[P.Ref(d)]}let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});s[p]=m;let{accessKey:g,logicalId:y}=Ie.createAccessKey(p,{slug:n,environment:r});return s[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((n)=>`${n}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class rs{static createRestApi(e){let{slug:n,environment:r,name:i,description:s,endpointType:a="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=i||l({slug:n,environment:r,resourceType:"rest-api"}),m=o(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:s||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[a]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:n,environment:r,name:i,description:s,corsEnabled:a=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=i||l({slug:n,environment:r,resourceType:"http-api"}),y=o(g),f={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:s||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(a)f.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:f,logicalId:y}}static createWebSocketApi(e){let{slug:n,environment:r,name:i,description:s}=e,a=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(a);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:a,Description:s||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:a,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:s}=n,a=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(a);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:P.Ref(e),Description:s||`Deployment for ${a}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:s,stageName:a,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:s,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:a||s,RestApiId:P.Ref(e),DeploymentId:P.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:s}]}};if(u)f.Properties.CacheClusterSize=d;if(m)f.Properties.Variables=m;if(p)f.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:f,logicalId:y}}static createAuthorizer(e,n){let{slug:r,environment:i,name:s,type:a,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=s||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:a,RestApiId:P.Ref(e),AuthorizerResultTtlInSeconds:m}};if(a==="TOKEN"||a==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(a==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");y.Properties.ProviderARNs=d,y.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:y,logicalId:g}}static setCors(e,n={}){let{origins:r=["*"],methods:i=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:s=["*"],maxAge:a=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:s,MaxAge:a,AllowCredentials:c},e}static addThrottling(e,n=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:n,ThrottlingRateLimit:r}),e}static enableCaching(e,n="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=n,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),e}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class Le{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:s,encrypted:a=!1,kmsKeyId:c}=e,u=i||l({slug:n,environment:r,resourceType:"topic"}),d=o(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:s||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:s,endpoint:a,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=a.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${s}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:P.Ref(e),Protocol:s,Endpoint:a,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return Le.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return Le.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return Le.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return Le.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return Le.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:s,allowedServices:a,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(s)m.AWS=s;if(a)m.Service=a;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[P.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:P.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,n){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=n,e}static addInlineSubscription(e,n,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:n,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,n,r)=>({[e]:[{numeric:[">=",n,"<=",r]}]}),prefix:(e,n)=>({[e]:[{prefix:n}]}),and:(...e)=>Object.assign({},...e),exists:(e,n)=>({[e]:[{exists:n}]})};static UseCases={createAlertTopic:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class gu{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:s="STANDARD",definition:a,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=i||l({slug:n,environment:r,resourceType:"state-machine"}),p=o(m),g,y,f;if(c)f=c;else{let S=l({slug:n,environment:r,resourceType:"state-machine-role"});y=o(S),g={Type:"AWS::IAM::Role",Properties:{RoleName:S,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"states.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"],Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}},f=P.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:s,DefinitionString:JSON.stringify(a),RoleArn:f,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)h.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((S)=>({CloudWatchLogsLogGroup:{LogGroupArn:S}}))};if(d)h.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:h,logicalId:p,role:g,roleLogicalId:y}}static createLambdaTask(e,n){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:n?.parameters||{"Input.$":"$"}},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createDynamoDBTask(e,n,r,i){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[e],Parameters:{TableName:n,...r},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSNSPublishTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,n){return{Type:"Choice",Choices:e,Default:n}}static createParallelState(e,n){return{Type:"Parallel",Branches:e,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createMapState(e,n){return{Type:"Map",ItemsPath:n?.itemsPath||"$.items",Iterator:e,MaxConcurrency:n?.maxConcurrency,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,n){return{Type:"Fail",Error:e,Cause:n}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(e,n,r,i)=>({ErrorEquals:e,IntervalSeconds:n,MaxAttempts:r,BackoffRate:i})};static CatchPolicies={all:(e,n)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:n||"$.error"}),specific:(e,n,r)=>({ErrorEquals:e,Next:n,ResultPath:r||"$.error"})};static Patterns={sequential:(e,n,r)=>{let i={};return r.forEach((s,a)=>{let c=a===r.length-1;i[s.name]={...s.state,Next:c?void 0:r[a+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:i}},fanout:(e,n,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((i)=>i.definition),End:!0}}}),map:(e,n,r,i)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:i,End:!0}}}),withErrorHandling:(e,n,r,i)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:i,Success:{Type:"Succeed"}}})}}class Vi{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:s,namespace:a,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:y=!0,alarmActions:f,okActions:h,insufficientDataActions:S,dimensions:C,unit:E,datapointsToAlarm:w}=e,v=i||l({slug:n,environment:r,resourceType:"alarm"}),I=o(v),D={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:v,MetricName:s,Namespace:a,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:y}};if(f&&f.length>0)D.Properties.AlarmActions=f;if(h&&h.length>0)D.Properties.OKActions=h;if(S&&S.length>0)D.Properties.InsufficientDataActions=S;if(C)D.Properties.Dimensions=Object.entries(C).map(([x,L])=>({Name:x,Value:L}));if(E)D.Properties.Unit=E;if(w!==void 0)D.Properties.DatapointsToAlarm=w;return{alarm:D,logicalId:I}}static createCompositeAlarm(e){let{slug:n,environment:r,alarmName:i,alarmRule:s,actionsEnabled:a=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=i||l({slug:n,environment:r,resourceType:"composite-alarm"}),p=o(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:s,ActionsEnabled:a}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:n,environment:r,dashboardName:i,widgets:s}=e,a=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(a),u={widgets:s.map((m)=>({type:m.type,x:m.x,y:m.y,width:m.width,height:m.height,properties:m.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:a,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:s,kmsKeyId:a}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(s!==void 0)d.Properties.RetentionInDays=s;if(a)d.Properties.KmsKeyId=a;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:s}=n,a=s||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(a);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:P.Ref(e),LogStreamName:a}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:s,filterPattern:a,metricTransformations:c}=n,u=s||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:P.Ref(e),FilterPattern:a,MetricTransformations:c.map((p)=>({MetricName:p.metricName,MetricNamespace:p.metricNamespace,MetricValue:p.metricValue,DefaultValue:p.defaultValue,Unit:p.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highMemory:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highDisk:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:s?[s]:void 0}),lambdaErrors:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),lambdaThrottles:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),dynamoDBThrottles:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:s?[s]:void 0}),rdsCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:s?[s]:void 0}),albUnhealthyTargets:(e,n,r,i,s=1,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:s,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:a?[a]:void 0}),sesBounceRate:(e,n,r=5,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),sesComplaintRate:(e,n,r=0.1,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),smsDeliveryFailure:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:s?[s]:void 0}),smsSpendLimit:(e,n,r=100,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),connectMissedCalls:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0})};static DashboardWidgets={metric:(e,n,r,i,s,a)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:s,title:a||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,s)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:s}}),log:(e,n,r,i,s,a)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${s.join("' | SOURCE '")}'
|
|
2274
|
+
`;class Re{static LambdaCode={send:ft,receive:cn,deliveryStatus:on};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let n={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)n.SenderId=e.senderId;if(e.shortCode)n.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:n}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-sms-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:e.pinpointAppId,MESSAGE_LOG_TABLE:e.messageLogTable||"",SMS_SENDER_ID:e.senderId||"",SMS_ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static createReceiveLambda(e){return{[`${e.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:e.optOutTable||"",MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createDeliveryStatusLambda(e){return{[`${e.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let n={},r={};Object.assign(n,Re.createPinpointApp({slug:e.slug})),Object.assign(n,Re.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(n,Re.createSmsLambdaRole({slug:e.slug})),Object.assign(n,Re.createMessageLogTable({slug:e.slug})),Object.assign(n,Re.createOptOutTable({slug:e.slug})),Object.assign(n,Re.createNotificationTopic({slug:e.slug}));let i={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},s={Ref:`${e.slug}PinpointApp`},a={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(n,Re.createSendLambda({slug:e.slug,roleArn:i,pinpointAppId:s,messageLogTable:a,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Re.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Re.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:n,outputs:r}}}function ht(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function xr(e,n){let r=(e||n).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${n}`);return r}function kr(e){let n=e.storage;if(n?.type==="efs"){let i="fileSystemId"in n?n.fileSystemId:void 0;if(!i||typeof i==="string"&&!i.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:i,posixProfile:n.posixProfile}}let r=(n?.type==="s3"?n.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function Mr(e,n,r){let i=n.posixProfile??r;if(!i)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let s of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(s)||s<0||s>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${s}`);return{Uid:i.uid,Gid:i.gid,...i.secondaryGids?.length?{SecondaryGids:i.secondaryGids}:{}}}function Lr(e,n){return typeof e==="string"?`/${e}/${n}`:{"Fn::Sub":[`/\${FileSystemId}/${n}`,{FileSystemId:e}]}}function Or(e){return typeof e==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",e)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:e}]}}class ts{static create(e){let n=kr(e),r=n.type==="efs"?"EFS":"S3",i=e.endpointType??"PUBLIC";if(i==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let s=`${ht(e.slug)}${ht(e.environment)}Sftp`,a=`${s}Server`,c={},u;if(e.logging!==!1){let d=`${s}LoggingRole`;c[d]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[a]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:i,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...i==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=ht(d),g=xr(m.homeDirectory,d),y=`${s}${p}User`,f=m.roleArn;if(!f){let h=`${s}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Or(n.fileSystemId)}];else{let C=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:C,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${C}/${g}/*`}]}c[h]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"SftpHomeDirectory",PolicyDocument:{Version:"2012-10-17",Statement:S}}]}},f={"Fn::GetAtt":[h,"Arn"]}}c[y]={Type:"AWS::Transfer::User",DependsOn:[a],Properties:{ServerId:{Ref:a},UserName:d,Role:f,HomeDirectoryType:"PATH",HomeDirectory:n.type==="efs"?Lr(n.fileSystemId,g):`/${n.bucket}/${g}`,...n.type==="efs"?{PosixProfile:Mr(d,m,n.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:a,domain:r}}}class qe{static createBedrockRole(e,n){let{slug:r,environment:i,name:s,models:a=["*"],allowStreaming:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=a.map((y)=>y==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${y}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:n,environment:r,name:i,models:s=["*"],allowInvoke:a=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(a)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=s.map((f)=>f==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${f}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return qe.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return qe.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return qe.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let s=n.map((a)=>a==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${a}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:s}]}}),e}static Models={Claude3_5_Sonnet:"anthropic.claude-3-5-sonnet-20241022-v2:0",Claude3_5_Haiku:"anthropic.claude-3-5-haiku-20241022-v1:0",Claude3_Opus:"anthropic.claude-3-opus-20240229-v1:0",Claude3_Sonnet:"anthropic.claude-3-sonnet-20240229-v1:0",Claude3_Haiku:"anthropic.claude-3-haiku-20240307-v1:0",TitanTextG1Express:"amazon.titan-text-express-v1",TitanTextG1Lite:"amazon.titan-text-lite-v1",TitanEmbedG1Text:"amazon.titan-embed-text-v1",TitanImageG1:"amazon.titan-image-generator-v1",JurassicUltra:"ai21.j2-ultra-v1",JurassicMid:"ai21.j2-mid-v1",CommandText:"cohere.command-text-v14",CommandLight:"cohere.command-light-text-v14",EmbedEnglish:"cohere.embed-english-v3",EmbedMultilingual:"cohere.embed-multilingual-v3",Llama3_2_1B:"meta.llama3-2-1b-instruct-v1:0",Llama3_2_3B:"meta.llama3-2-3b-instruct-v1:0",Llama3_2_11B:"meta.llama3-2-11b-instruct-v1:0",Llama3_2_90B:"meta.llama3-2-90b-instruct-v1:0",Llama3_1_8B:"meta.llama3-1-8b-instruct-v1:0",Llama3_1_70B:"meta.llama3-1-70b-instruct-v1:0",Llama3_1_405B:"meta.llama3-1-405b-instruct-v1:0",Mistral7B:"mistral.mistral-7b-instruct-v0:2",Mixtral8x7B:"mistral.mixtral-8x7b-instruct-v0:1",MistralLarge:"mistral.mistral-large-2402-v1:0",StableDiffusionXL:"stability.stable-diffusion-xl-v1"};static ModelGroups={AllClaude:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","anthropic.claude-3-opus-20240229-v1:0","anthropic.claude-3-sonnet-20240229-v1:0","anthropic.claude-3-haiku-20240307-v1:0"],AllTitan:["amazon.titan-text-express-v1","amazon.titan-text-lite-v1","amazon.titan-embed-text-v1","amazon.titan-image-generator-v1"],AllLlama:["meta.llama3-2-1b-instruct-v1:0","meta.llama3-2-3b-instruct-v1:0","meta.llama3-2-11b-instruct-v1:0","meta.llama3-2-90b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-405b-instruct-v1:0"],TextModels:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","amazon.titan-text-express-v1","meta.llama3-2-11b-instruct-v1:0","mistral.mistral-7b-instruct-v0:2"],EmbeddingModels:["amazon.titan-embed-text-v1","cohere.embed-english-v3","cohere.embed-multilingual-v3"],ImageModels:["amazon.titan-image-generator-v1","stability.stable-diffusion-xl-v1"]}}class Qt{static createPostgres(e){return Qt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Qt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:s,instanceClass:a="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:y,encrypted:f=!0,kmsKeyId:h,multiAz:S=!1,backupRetentionDays:C=7,publiclyAccessible:P=!1,enableCloudwatchLogs:E=!0,deletionProtection:v=!0}=r,w=l({slug:i,environment:s,resourceType:`${e}-db`}),D=o(w),x,L;if(g&&g.length>0){let O=l({slug:i,environment:s,resourceType:"db-subnet-group"});L=o(O),x={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${w}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:s}]}}}let B={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:w,DBInstanceClass:a,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:C,PubliclyAccessible:P,DeletionProtection:v,Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:s}]}};if(p)B.Properties.DBName=p;if(h)B.Properties.KmsKeyId=h;if(L)B.Properties.DBSubnetGroupName=R.Ref(L);if(y&&y.length>0)B.Properties.VPCSecurityGroups=y;if(E)B.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:B,subnetGroup:x,logicalId:D,subnetGroupId:L}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:s="db.t3.micro",securityGroupIds:a,publiclyAccessible:c=!1}=n,u=l({slug:r,environment:i,resourceType:"db-replica"}),d=o(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:s,SourceDBInstanceIdentifier:R.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(a&&a.length>0)m.Properties.VPCSecurityGroups=a;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:s,parameters:a={}}=r,c=l({slug:i,environment:s,resourceType:"db-params"}),u=o(c),d=e==="postgres"?`postgres${n.split(".")[0]}`:`mysql${n.split(".")[0]}.${n.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:s,sortKey:a,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:y,pointInTimeRecovery:f=!0,ttlAttribute:h}=e,S=i||l({slug:n,environment:r,resourceType:"table"}),C=o(S),P=[{AttributeName:s.name,AttributeType:s.type}];if(a)P.push({AttributeName:a.name,AttributeType:a.type});let E=[{AttributeName:s.name,KeyType:"HASH"}];if(a)E.push({AttributeName:a.name,KeyType:"RANGE"});let v={Type:"AWS::DynamoDB::Table",Properties:{TableName:S,BillingMode:c,AttributeDefinitions:P,KeySchema:E,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")v.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)v.Properties.StreamSpecification={StreamViewType:p};if(g)v.Properties.SSESpecification={SSEEnabled:!0,SSEType:y?"KMS":"AES256",KMSMasterKeyId:y};if(f)v.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)v.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:v,logicalId:C}}static addGlobalSecondaryIndex(e,n){let{indexName:r,partitionKey:i,sortKey:s,projectionType:a="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=n;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});if(s&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===s.name))e.Properties.AttributeDefinitions.push({AttributeName:s.name,AttributeType:s.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(s)m.push({AttributeName:s.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:a,NonKeyAttributes:a==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,n="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:n},e}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class ji{static createRedis(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="7.1",port:a=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:y=1,replicasPerNodeGroup:f=1,atRestEncryption:h=!0,transitEncryption:S=!0,authToken:C,kmsKeyId:P,snapshotRetentionDays:E=7,snapshotWindow:v,maintenanceWindow:w}=e,D=l({slug:n,environment:r,resourceType:"redis"}),x=o(D),L,B;if(c&&c.length>0){let F=l({slug:n,environment:r,resourceType:"cache-subnet-group"});B=o(F),L={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:F,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:F},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:s,CacheNodeType:i,Port:a,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit:E,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:r}]}};if(g)O.Properties.NumNodeGroups=y,O.Properties.ReplicasPerNodeGroup=f;else O.Properties.NumCacheClusters=d;if(C)O.Properties.AuthToken=C;if(P)O.Properties.KmsKeyId=P;if(B)O.Properties.CacheSubnetGroupName=R.Ref(B);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(v)O.Properties.SnapshotWindow=v;if(w)O.Properties.PreferredMaintenanceWindow=w;return{replicationGroup:O,subnetGroup:L,logicalId:x,subnetGroupId:B}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="1.6.22",port:a=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,y=l({slug:n,environment:r,resourceType:"memcached"}),f=o(y),h,S;if(u&&u.length>0){let P=l({slug:n,environment:r,resourceType:"cache-subnet-group"});S=o(P),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:P,Description:`Subnet group for ${y}`,SubnetIds:u,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}}}let C={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:y,CacheNodeType:i,Engine:"memcached",EngineVersion:s,NumCacheNodes:c,Port:a,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(S)C.Properties.CacheSubnetGroupName=R.Ref(S);if(d&&d.length>0)C.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)C.Properties.PreferredAvailabilityZones=p;if(g)C.Properties.PreferredMaintenanceWindow=g;return{cluster:C,subnetGroup:h,logicalId:f,subnetGroupId:S}}static enableClusterMode(e,n=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=n,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Ie{static createUser(e){let{slug:n,environment:r,userName:i,groups:s,managedPolicyArns:a}=e,c=i||l({slug:n,environment:r,resourceType:"user"}),u=o(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(s&&s.length>0)d.Properties.Groups=s;if(a&&a.length>0)d.Properties.ManagedPolicyArns=a;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:s,awsPrincipal:a,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(s)m.Service=s;if(a)m.AWS=a;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:n,environment:r,groupName:i,managedPolicyArns:s}=e,a=i||l({slug:n,environment:r,resourceType:"group"}),c=o(a),u={Type:"AWS::IAM::Group",Properties:{GroupName:a}};if(s&&s.length>0)u.Properties.ManagedPolicyArns=s;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:s,statements:a}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=a.map((p)=>({Sid:p.sid,Effect:p.effect||"Allow",Action:p.actions,Resource:p.resources,Condition:p.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:s||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToUser(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToGroup(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static addInlinePolicyToRole(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static addInlinePolicyToUser(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static createAccessKey(e,n){let{slug:r,environment:i,status:s="Active"}=n,a=l({slug:r,environment:i,resourceType:"access-key"}),c=o(a);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:R.Ref(e),Status:s}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:s}=n,a=s||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(a);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:a,Roles:[R.Ref(e)]}},logicalId:c}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(e){let{slug:n,environment:r,permissions:i,createAccessKey:s=!0}=e,a={},c=[];if(i.s3Buckets&&i.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...i.s3Buckets,...i.s3Buckets.map((f)=>`${f}/*`)]});if(i.cloudFrontDistributions&&i.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:i.cloudFrontDistributions});if(i.ecrRepositories&&i.ecrRepositories.length>0)c.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:i.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(i.ecsServices&&i.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:i.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(i.cloudFormationStacks&&i.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:i.cloudFormationStacks});if(i.lambdaFunctions&&i.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:i.lambdaFunctions});if(i.secretsManagerSecrets&&i.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:i.secretsManagerSecrets});let{policy:u,logicalId:d}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${n} (${r})`,statements:c});a[d]=u;let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[R.Ref(d)]});a[p]=m;let g,y;if(s){let f=Ie.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,a[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:s,permissions:a,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${n} (${r})`,statements:a});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(s)y.StringEquals={"sts:ExternalId":s};let f={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:i.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(y).length>0?{Condition:y}:{}}]},ManagedPolicyArns:[R.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=f,{role:f,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:n,environment:r,permissions:i="readonly"}=e,s={},a=[],c=[];switch(i){case"readonly":c=[Ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":a=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Ie.ManagedPolicies.AdministratorAccess];break}let u,d;if(a.length>0){let f=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${n} (${r})`,statements:a});u=f.policy,d=f.logicalId,s[d]=u,c=[R.Ref(d)]}let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});s[p]=m;let{accessKey:g,logicalId:y}=Ie.createAccessKey(p,{slug:n,environment:r});return s[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((n)=>`${n}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class rs{static createRestApi(e){let{slug:n,environment:r,name:i,description:s,endpointType:a="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=i||l({slug:n,environment:r,resourceType:"rest-api"}),m=o(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:s||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[a]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:n,environment:r,name:i,description:s,corsEnabled:a=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=i||l({slug:n,environment:r,resourceType:"http-api"}),y=o(g),f={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:s||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(a)f.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:f,logicalId:y}}static createWebSocketApi(e){let{slug:n,environment:r,name:i,description:s}=e,a=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(a);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:a,Description:s||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:a,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:s}=n,a=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(a);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:R.Ref(e),Description:s||`Deployment for ${a}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:s,stageName:a,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:s,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:a||s,RestApiId:R.Ref(e),DeploymentId:R.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:s}]}};if(u)f.Properties.CacheClusterSize=d;if(m)f.Properties.Variables=m;if(p)f.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:f,logicalId:y}}static createAuthorizer(e,n){let{slug:r,environment:i,name:s,type:a,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=s||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:a,RestApiId:R.Ref(e),AuthorizerResultTtlInSeconds:m}};if(a==="TOKEN"||a==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(a==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");y.Properties.ProviderARNs=d,y.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:y,logicalId:g}}static setCors(e,n={}){let{origins:r=["*"],methods:i=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:s=["*"],maxAge:a=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:s,MaxAge:a,AllowCredentials:c},e}static addThrottling(e,n=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:n,ThrottlingRateLimit:r}),e}static enableCaching(e,n="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=n,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),e}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class Le{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:s,encrypted:a=!1,kmsKeyId:c}=e,u=i||l({slug:n,environment:r,resourceType:"topic"}),d=o(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:s||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:s,endpoint:a,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=a.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${s}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:R.Ref(e),Protocol:s,Endpoint:a,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return Le.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return Le.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return Le.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return Le.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return Le.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:s,allowedServices:a,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(s)m.AWS=s;if(a)m.Service=a;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[R.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:R.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,n){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=n,e}static addInlineSubscription(e,n,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:n,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,n,r)=>({[e]:[{numeric:[">=",n,"<=",r]}]}),prefix:(e,n)=>({[e]:[{prefix:n}]}),and:(...e)=>Object.assign({},...e),exists:(e,n)=>({[e]:[{exists:n}]})};static UseCases={createAlertTopic:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class gu{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:s="STANDARD",definition:a,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=i||l({slug:n,environment:r,resourceType:"state-machine"}),p=o(m),g,y,f;if(c)f=c;else{let S=l({slug:n,environment:r,resourceType:"state-machine-role"});y=o(S),g={Type:"AWS::IAM::Role",Properties:{RoleName:S,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"states.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"],Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}},f=R.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:s,DefinitionString:JSON.stringify(a),RoleArn:f,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)h.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((S)=>({CloudWatchLogsLogGroup:{LogGroupArn:S}}))};if(d)h.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:h,logicalId:p,role:g,roleLogicalId:y}}static createLambdaTask(e,n){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:n?.parameters||{"Input.$":"$"}},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createDynamoDBTask(e,n,r,i){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[e],Parameters:{TableName:n,...r},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSNSPublishTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,n){return{Type:"Choice",Choices:e,Default:n}}static createParallelState(e,n){return{Type:"Parallel",Branches:e,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createMapState(e,n){return{Type:"Map",ItemsPath:n?.itemsPath||"$.items",Iterator:e,MaxConcurrency:n?.maxConcurrency,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,n){return{Type:"Fail",Error:e,Cause:n}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(e,n,r,i)=>({ErrorEquals:e,IntervalSeconds:n,MaxAttempts:r,BackoffRate:i})};static CatchPolicies={all:(e,n)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:n||"$.error"}),specific:(e,n,r)=>({ErrorEquals:e,Next:n,ResultPath:r||"$.error"})};static Patterns={sequential:(e,n,r)=>{let i={};return r.forEach((s,a)=>{let c=a===r.length-1;i[s.name]={...s.state,Next:c?void 0:r[a+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:i}},fanout:(e,n,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((i)=>i.definition),End:!0}}}),map:(e,n,r,i)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:i,End:!0}}}),withErrorHandling:(e,n,r,i)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:i,Success:{Type:"Succeed"}}})}}class Vi{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:s,namespace:a,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:y=!0,alarmActions:f,okActions:h,insufficientDataActions:S,dimensions:C,unit:P,datapointsToAlarm:E}=e,v=i||l({slug:n,environment:r,resourceType:"alarm"}),w=o(v),D={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:v,MetricName:s,Namespace:a,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:y}};if(f&&f.length>0)D.Properties.AlarmActions=f;if(h&&h.length>0)D.Properties.OKActions=h;if(S&&S.length>0)D.Properties.InsufficientDataActions=S;if(C)D.Properties.Dimensions=Object.entries(C).map(([x,L])=>({Name:x,Value:L}));if(P)D.Properties.Unit=P;if(E!==void 0)D.Properties.DatapointsToAlarm=E;return{alarm:D,logicalId:w}}static createCompositeAlarm(e){let{slug:n,environment:r,alarmName:i,alarmRule:s,actionsEnabled:a=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=i||l({slug:n,environment:r,resourceType:"composite-alarm"}),p=o(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:s,ActionsEnabled:a}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:n,environment:r,dashboardName:i,widgets:s}=e,a=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(a),u={widgets:s.map((m)=>({type:m.type,x:m.x,y:m.y,width:m.width,height:m.height,properties:m.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:a,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:s,kmsKeyId:a}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(s!==void 0)d.Properties.RetentionInDays=s;if(a)d.Properties.KmsKeyId=a;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:s}=n,a=s||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(a);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:R.Ref(e),LogStreamName:a}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:s,filterPattern:a,metricTransformations:c}=n,u=s||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:R.Ref(e),FilterPattern:a,MetricTransformations:c.map((p)=>({MetricName:p.metricName,MetricNamespace:p.metricNamespace,MetricValue:p.metricValue,DefaultValue:p.defaultValue,Unit:p.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highMemory:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highDisk:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:s?[s]:void 0}),lambdaErrors:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),lambdaThrottles:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),dynamoDBThrottles:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:s?[s]:void 0}),rdsCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:s?[s]:void 0}),albUnhealthyTargets:(e,n,r,i,s=1,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:s,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:a?[a]:void 0}),sesBounceRate:(e,n,r=5,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),sesComplaintRate:(e,n,r=0.1,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),smsDeliveryFailure:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:s?[s]:void 0}),smsSpendLimit:(e,n,r=100,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),connectMissedCalls:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0})};static DashboardWidgets={metric:(e,n,r,i,s,a)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:s,title:a||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,s)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:s}}),log:(e,n,r,i,s,a)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${s.join("' | SOURCE '")}'
|
|
2275
2275
|
| fields @timestamp, @message
|
|
2276
2276
|
| sort @timestamp desc
|
|
2277
2277
|
| limit 20`,region:"us-east-1",title:a||"Logs"}})};static RetentionPeriods={ONE_DAY:1,THREE_DAYS:3,FIVE_DAYS:5,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,TWO_MONTHS:60,THREE_MONTHS:90,FOUR_MONTHS:120,FIVE_MONTHS:150,SIX_MONTHS:180,ONE_YEAR:365,THIRTEEN_MONTHS:400,EIGHTEEN_MONTHS:545,TWO_YEARS:731,FIVE_YEARS:1827,TEN_YEARS:3653,NEVER_EXPIRE:void 0};static FilterPatterns={errors:"[time, request_id, event_type = ERROR*, ...]",all:"",jsonField:(e,n)=>`{ $.${e} = "${n}" }`,httpStatus:(e)=>`[..., status_code = ${e}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(e){let{slug:n,environment:r,region:i="us-east-1",components:s={}}=e,a=[],c=0;if(a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:`# ${n.toUpperCase()} Dashboard (${r})`}}),c+=1,s.ec2InstanceIds&&s.ec2InstanceIds.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:s.ec2InstanceIds.map((u)=>["AWS/EC2","CPUUtilization","InstanceId",u]),period:300,stat:"Average"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Network Traffic",region:i,metrics:[...s.ec2InstanceIds.flatMap((u)=>[["AWS/EC2","NetworkIn","InstanceId",u,{label:`${u} In`}],["AWS/EC2","NetworkOut","InstanceId",u,{label:`${u} Out`}]])],period:300,stat:"Sum"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Status Checks",region:i,metrics:s.ec2InstanceIds.map((u)=>["AWS/EC2","StatusCheckFailed","InstanceId",u]),period:60,stat:"Maximum"}}),c+=6;if(s.lambdaFunctionNames&&s.lambdaFunctionNames.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Invocations",region:i,metrics:s.lambdaFunctionNames.map((u)=>["AWS/Lambda","Invocations","FunctionName",u]),period:300,stat:"Sum"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Duration",region:i,metrics:s.lambdaFunctionNames.map((u)=>["AWS/Lambda","Duration","FunctionName",u]),period:300,stat:"Average"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Errors",region:i,metrics:s.lambdaFunctionNames.map((u)=>["AWS/Lambda","Errors","FunctionName",u]),period:300,stat:"Sum"}}),c+=6;if(s.ecsClusterName&&s.ecsServiceName)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## ECS Service"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/ECS","CPUUtilization","ClusterName",s.ecsClusterName,"ServiceName",s.ecsServiceName]],period:300,stat:"Average"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Memory Utilization",region:i,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",s.ecsClusterName,"ServiceName",s.ecsServiceName]],period:300,stat:"Average"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Running Tasks",region:i,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",s.ecsClusterName,"ServiceName",s.ecsServiceName]],period:60,stat:"Average"}}),c+=6;if(s.albName)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Request Count",region:i,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",s.albName]],period:60,stat:"Sum"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Response Time",region:i,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",s.albName]],period:60,stat:"Average"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"HTTP Errors",region:i,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",s.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",s.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),c+=6;if(s.rdsInstanceId)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## RDS Database"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",s.rdsInstanceId]],period:300,stat:"Average"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Database Connections",region:i,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",s.rdsInstanceId]],period:60,stat:"Sum"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Free Storage Space",region:i,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",s.rdsInstanceId]],period:300,stat:"Average"}}),c+=6;if(s.sqsQueueNames&&s.sqsQueueNames.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## SQS Queues"}}),c+=1,a.push({type:"metric",x:0,y:c,width:12,height:6,properties:{title:"Messages Visible",region:i,metrics:s.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",u]),period:60,stat:"Sum"}}),a.push({type:"metric",x:12,y:c,width:12,height:6,properties:{title:"Message Age",region:i,metrics:s.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",u]),period:60,stat:"Maximum"}}),c+=6;if(s.logGroupNames&&s.logGroupNames.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Logs"}}),c+=1,a.push({type:"log",x:0,y:c,width:24,height:6,properties:{query:`SOURCE '${s.logGroupNames.join("' | SOURCE '")}'
|
|
2278
2278
|
| fields @timestamp, @message
|
|
2279
2279
|
| filter @message like /ERROR|WARN|Exception/
|
|
2280
2280
|
| sort @timestamp desc
|
|
2281
|
-
| limit 50`,region:i,title:"Recent Errors and Warnings"}}),c+=6;return Vi.createDashboard({slug:n,environment:r,widgets:a})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((n,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${n} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",n],["AWS/Lambda","Duration","FunctionName",n],["AWS/Lambda","Errors","FunctionName",n]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:n,namespace:r,threshold:i,comparisonOperator:s="GreaterThanThreshold",evaluationPeriods:a=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:s,EvaluationPeriods:a,Period:c,Statistic:u,TreatMissingData:d}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Pe{static createUserPool(e){let{slug:n,environment:r,userPoolName:i,aliasAttributes:s,autoVerifiedAttributes:a,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:y}=e,f=i||l({slug:n,environment:r,resourceType:"user-pool"}),h=o(f),S={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:f,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(s&&s.length>0)S.Properties.UsernameAttributes=s;if(a&&a.length>0)S.Properties.AutoVerifiedAttributes=a;if(d)S.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)S.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)S.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)S.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(y)S.Properties.AccountRecoverySetting={RecoveryMechanisms:y.recoveryMechanisms};return{userPool:S,logicalId:h}}static createUserPoolClient(e,n){let{slug:r,environment:i,clientName:s,generateSecret:a=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:C,allowedOAuthFlows:E,allowedOAuthScopes:w,allowedOAuthFlowsUserPoolClient:v,supportedIdentityProviders:I}=n,D=s||l({slug:r,environment:i,resourceType:"user-pool-client"}),x=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:P.Ref(e),GenerateSecret:a,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:C,AllowedOAuthFlows:E,AllowedOAuthScopes:w,AllowedOAuthFlowsUserPoolClient:v,SupportedIdentityProviders:I}},logicalId:x}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:s,customDomainConfig:a}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:s,UserPoolId:P.Ref(e),CustomDomainConfig:a}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:s=!1,cognitoIdentityProviders:a,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=i||l({slug:n,environment:r,resourceType:"identity-pool"}),p=o(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:s,CognitoIdentityProviders:a,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:s,unauthenticatedRole:a,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:s};if(a)m.unauthenticated=a;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:P.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":P.Ref(i)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"authenticated"}}}]},Policies:[{PolicyName:"CognitoAuthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*","cognito-identity:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":P.Ref(i)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}}]},Policies:[{PolicyName:"CognitoUnauthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,n,r)=>{let{userPool:i,logicalId:s}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:a,logicalId:c}=Pe.createUserPoolClient(s,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Pe.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:s,client:a,clientId:c}},mobileApp:(e,n)=>{let{userPool:r,logicalId:i}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=Pe.createUserPoolClient(i,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Pe.createIdentityPool({slug:e,environment:n,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:P.Ref(a),ProviderName:P.GetAtt(i,"ProviderName")}]}),{role:d,logicalId:m}=Pe.createAuthenticatedRole({slug:e,environment:n,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=Pe.createIdentityPoolRoleAttachment(u,{slug:e,environment:n,authenticatedRole:P.GetAtt(m,"Arn")});return{userPool:r,poolId:i,client:s,clientId:a,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as $r}from"node:crypto";import{copyFileSync as Br,existsSync as bt,readdirSync as _r,readFileSync as Xe,statSync as Wr,writeFileSync as et}from"node:fs";import{basename as Ur,dirname as ln,extname as un,join as Ue}from"node:path";class De{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:s}=e,a=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(a);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:a,ComputePlatform:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:s,serviceRoleArn:a,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=s||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:P.Ref(e),DeploymentGroupName:f,ServiceRoleArn:a,AutoScalingGroups:c,Ec2TagFilters:u?.map((C)=>({Key:C.key,Value:C.value,Type:C.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((C)=>({Name:C.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((C)=>({Name:C.name})),ElbInfoList:g.elbInfoList?.map((C)=>({Name:C.name}))}:void 0,BlueGreenDeploymentConfiguration:y?{TerminateBlueInstancesOnDeploymentSuccess:y.terminateBlueInstancesOnDeploymentSuccess?{Action:y.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:y.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:y.deploymentReadyOption?{ActionOnTimeout:y.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:y.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:y.greenFleetProvisioningOption?{Action:y.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:i}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:n,environment:r,deploymentConfigName:i,minimumHealthyHosts:s,trafficRoutingConfig:a}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:s?{Type:s.type,Value:s.value}:void 0,TrafficRoutingConfig:a?{Type:a.type,TimeBasedCanary:a.timeBasedCanary?{CanaryPercentage:a.timeBasedCanary.canaryPercentage,CanaryInterval:a.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:a.timeBasedLinear?{LinearPercentage:a.timeBasedLinear.linearPercentage,LinearInterval:a.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,n)=>({type:e,value:n})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,n)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:n}}),linear:(e,n)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:n}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(e,n,r,i)=>{let{application:s,logicalId:a}=De.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,s=5)=>{let{application:a,logicalId:c}=De.createApplication({slug:e,environment:n,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=De.createDeploymentConfig({slug:e,environment:n,trafficRoutingConfig:De.TrafficRouting.canary(i,s)}),{deploymentGroup:m,logicalId:p}=De.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:P.Ref(d),autoRollbackConfiguration:De.RollbackConfigs.onAlarmOrFailure()});return{application:a,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:s,logicalId:a}=De.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:De.BlueGreenConfigs.standard(),autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,n=5)=>({type:"canary",canaryPercentage:e,canaryInterval:n}),allAtOnce:()=>({type:"all-at-once"})}}class ie{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(e,n="md5"){let r=Xe(e);return $r(n).update(r).digest("hex")}static computeShortHash(e){return ie.computeFileHash(e).slice(0,8)}static getContentType(e){let n=un(e).toLowerCase();return ie.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...ie.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=un(e),i=Ur(e,r),s=ln(e);if(s===".")return`${i}.${n}${r}`;return Ue(s,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!bt(e))return r;let s=_r(e,{withFileTypes:!0});for(let a of s){let c=Ue(e,a.name);if(a.isDirectory())r.push(...ie.collectFiles(c,i));else if(a.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:s="md5",copyUnhashed:a=!0}=e,c=ie.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=ie.shouldHashFile(g,i),f=Wr(p),h=y?ie.computeFileHash(p,s).slice(0,8):"",S=y?ie.generateHashedFilename(g,h):g,C={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:ie.getContentType(p)};if(u.push(C),d[g]=S,r){let E=Ue(r,S),w=ln(E);if(!bt(w)){let{mkdirSync:v}=Gr("node:fs");v(w,{recursive:!0})}if(y||a)Br(p,E)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=Ue(r,"asset-manifest.json");et(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,n){let r=[];if(!e)return["/*"];let i=e.hashMap,s=n.hashMap;for(let[a,c]of Object.entries(s)){let u=i[a];if(!u||u!==c){if(r.push(`/${a}`),u&&u!==c)r.push(`/${u}`)}}for(let[a,c]of Object.entries(i))if(!s[a])r.push(`/${a}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,s=ie.collectFiles(n).filter((a)=>a.endsWith(".html")||a.endsWith(".htm"));for(let a of s){let c=Xe(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${ie.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}et(a,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,s=ie.collectFiles(n).filter((a)=>a.endsWith(".css"));for(let a of s){let c=Xe(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}et(a,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:s={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ie.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=s.unhashed||"public, max-age=3600";if(d)m=s.html||"public, max-age=0, must-revalidate";else if(u)m=s.hashed||"public, max-age=31536000, immutable";return{localPath:Ue(n,c.originalPath),s3Key:r?`${r}/${c.hashedPath}`:c.hashedPath,contentType:c.contentType,cacheControl:m,hash:c.hash}})}static compareManifests(e,n){let r={added:[],removed:[],changed:[],unchanged:[]},i=new Set(Object.keys(e.hashMap)),s=new Set(Object.keys(n.hashMap));for(let a of s)if(!i.has(a))r.added.push(a);for(let a of i)if(!s.has(a))r.removed.push(a);for(let a of s)if(i.has(a))if(e.hashMap[a]!==n.hashMap[a])r.changed.push(a);else r.unchanged.push(a);return r}static loadManifest(e){if(!bt(e))return null;try{let n=Xe(e,"utf-8");return JSON.parse(n)}catch{return null}}static saveManifest(e,n){et(n,JSON.stringify(e,null,2))}}class zi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:s,secretString:a,kmsKeyId:c,tags:u}=e,d=i||l({slug:n,environment:r,resourceType:"secret"}),m=o(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:s,SecretString:a,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,y])=>({Key:g,Value:y})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:n,environment:r,secretName:i,description:s,excludeCharacters:a,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:y,tags:f}=e,h=i||l({slug:n,environment:r,resourceType:"secret"}),S=o(h),C={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:s,GenerateSecretString:{ExcludeCharacters:a,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r},...f?Object.entries(f).map(([E,w])=>({Key:E,Value:w})):[]]}};if(y)C.Properties.KmsKeyId=y;return{secret:C,logicalId:S}}static createDatabaseSecret(e){let{slug:n,environment:r,secretName:i,username:s,dbname:a,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:s};if(a)y.dbname=a;if(c)y.engine=c;if(u)y.host=u;if(d)y.port=d;let f={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${s}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(y),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)f.Properties.KmsKeyId=m;return{secret:f,logicalId:g}}static attachToDatabase(e){let{slug:n,environment:r,secretId:i,targetId:s,targetType:a}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:s,TargetType:a}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:s,automaticallyAfterDays:a,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:n,environment:r,resourceType:"secret-rotation"}),g=o(p),y={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:i,RotationRules:{AutomaticallyAfterDays:a||30}}};if(s)y.Properties.RotationLambdaARN=s;else if(c)y.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:y,logicalId:g}}static SecretTypes={apiKey:(e,n,r)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,n,r)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,n)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class X{static createParameter(e){let{slug:n,environment:r,parameterName:i,value:s,type:a="String",description:c,tier:u="Standard",tags:d}=e,m=i||l({slug:n,environment:r,resourceType:"parameter"}),p=o(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${n}/${r}/${m}`,Type:a,Value:s,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:s})}static createSecureString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:s})}static createStringList(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:s})}static Parameters={databaseUrl:(e,n,r)=>X.createSecureString(e,n,"database-url",r,"Database connection URL"),apiEndpoint:(e,n,r)=>X.createString(e,n,"api-endpoint",r,"API endpoint URL"),appVersion:(e,n,r)=>X.createString(e,n,"app-version",r,"Application version"),featureFlags:(e,n,r)=>X.createStringList(e,n,"feature-flags",r,"Enabled feature flags"),apiKey:(e,n,r,i)=>X.createSecureString(e,n,`${r}-api-key`,i,`API key for ${r}`),oauthCredentials:(e,n,r,i)=>{let s=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),a=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:s,clientSecret:a}},smtpCredentials:(e,n,r,i,s,a)=>{let c=X.createString(e,n,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,n,"smtp-password",i,"SMTP password"),d=X.createString(e,n,"smtp-host",s,"SMTP host"),m=X.createString(e,n,"smtp-port",a.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,n,r)=>X.createSecureString(e,n,"redis-url",r,"Redis connection URL"),s3Bucket:(e,n,r)=>X.createString(e,n,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,n,r)=>X.createString(e,n,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Yt{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:s="OpenSearch_2.11",instanceType:a="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:y=!1,availabilityZoneCount:f=2,vpc:h,encryption:S,enforceHttps:C=!0,tlsSecurityPolicy:E="Policy-Min-TLS-1-2-2019-07",advancedSecurity:w,autoSnapshotHour:v=0,autoTune:I=!0,tags:D={}}=e,x=i||l({slug:n,environment:r,resourceType:"search"}),L=o(x);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:x,EngineVersion:s,ClusterConfig:{InstanceType:a,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||a,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:C,TLSSecurityPolicy:E},SnapshotOptions:{AutomatedSnapshotStartHour:v},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...S&&{EncryptionAtRestOptions:{Enabled:S.atRest??!0,...S.kmsKeyId&&{KmsKeyId:S.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:S.nodeToNode??!0}},...w&&{AdvancedSecurityOptions:{Enabled:w.enabled,InternalUserDatabaseEnabled:w.internalUserDatabase??!0,...w.masterUserName&&w.masterUserPassword&&{MasterUserOptions:{MasterUserName:w.masterUserName,MasterUserPassword:w.masterUserPassword}},...w.masterUserArn&&{MasterUserOptions:{MasterUserARN:w.masterUserArn}}}},...I&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:x},{Key:"Environment",Value:r},...Object.entries(D).map(([O,F])=>({Key:O,Value:F}))]}},logicalId:L}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:s,vpcEndpoint:a}=n;if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(i&&i.length>0)c.push({Effect:"Allow",Principal:{AWS:i},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(a)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,n)=>Yt.createDomain({slug:e,environment:n,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,n,r)=>Yt.createDomain({slug:e,environment:n,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,n)=>Yt.createDomain({slug:e,environment:n,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,n,r)=>Yt.createDomain({slug:e,environment:n,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class kt{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"redirect"}),u=o(c),d=o(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:n,environment:r,rules:i}=e,s=l({slug:n,environment:r,resourceType:"cf-redirect"}),a=o(s),c=kt.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:s,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:a,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2281
|
+
| limit 50`,region:i,title:"Recent Errors and Warnings"}}),c+=6;return Vi.createDashboard({slug:n,environment:r,widgets:a})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((n,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${n} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",n],["AWS/Lambda","Duration","FunctionName",n],["AWS/Lambda","Errors","FunctionName",n]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:n,namespace:r,threshold:i,comparisonOperator:s="GreaterThanThreshold",evaluationPeriods:a=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:s,EvaluationPeriods:a,Period:c,Statistic:u,TreatMissingData:d}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Pe{static createUserPool(e){let{slug:n,environment:r,userPoolName:i,aliasAttributes:s,autoVerifiedAttributes:a,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:y}=e,f=i||l({slug:n,environment:r,resourceType:"user-pool"}),h=o(f),S={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:f,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(s&&s.length>0)S.Properties.UsernameAttributes=s;if(a&&a.length>0)S.Properties.AutoVerifiedAttributes=a;if(d)S.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)S.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)S.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)S.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(y)S.Properties.AccountRecoverySetting={RecoveryMechanisms:y.recoveryMechanisms};return{userPool:S,logicalId:h}}static createUserPoolClient(e,n){let{slug:r,environment:i,clientName:s,generateSecret:a=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:C,allowedOAuthFlows:P,allowedOAuthScopes:E,allowedOAuthFlowsUserPoolClient:v,supportedIdentityProviders:w}=n,D=s||l({slug:r,environment:i,resourceType:"user-pool-client"}),x=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:R.Ref(e),GenerateSecret:a,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:C,AllowedOAuthFlows:P,AllowedOAuthScopes:E,AllowedOAuthFlowsUserPoolClient:v,SupportedIdentityProviders:w}},logicalId:x}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:s,customDomainConfig:a}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:s,UserPoolId:R.Ref(e),CustomDomainConfig:a}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:s=!1,cognitoIdentityProviders:a,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=i||l({slug:n,environment:r,resourceType:"identity-pool"}),p=o(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:s,CognitoIdentityProviders:a,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:s,unauthenticatedRole:a,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:s};if(a)m.unauthenticated=a;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:R.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.Ref(i)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"authenticated"}}}]},Policies:[{PolicyName:"CognitoAuthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*","cognito-identity:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.Ref(i)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}}]},Policies:[{PolicyName:"CognitoUnauthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,n,r)=>{let{userPool:i,logicalId:s}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:a,logicalId:c}=Pe.createUserPoolClient(s,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Pe.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:s,client:a,clientId:c}},mobileApp:(e,n)=>{let{userPool:r,logicalId:i}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=Pe.createUserPoolClient(i,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Pe.createIdentityPool({slug:e,environment:n,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:R.Ref(a),ProviderName:R.GetAtt(i,"ProviderName")}]}),{role:d,logicalId:m}=Pe.createAuthenticatedRole({slug:e,environment:n,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=Pe.createIdentityPoolRoleAttachment(u,{slug:e,environment:n,authenticatedRole:R.GetAtt(m,"Arn")});return{userPool:r,poolId:i,client:s,clientId:a,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as $r}from"node:crypto";import{copyFileSync as Br,existsSync as bt,readdirSync as _r,readFileSync as Xe,statSync as Wr,writeFileSync as et}from"node:fs";import{basename as Ur,dirname as ln,extname as un,join as Ve}from"node:path";class De{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:s}=e,a=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(a);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:a,ComputePlatform:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:s,serviceRoleArn:a,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=s||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:R.Ref(e),DeploymentGroupName:f,ServiceRoleArn:a,AutoScalingGroups:c,Ec2TagFilters:u?.map((C)=>({Key:C.key,Value:C.value,Type:C.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((C)=>({Name:C.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((C)=>({Name:C.name})),ElbInfoList:g.elbInfoList?.map((C)=>({Name:C.name}))}:void 0,BlueGreenDeploymentConfiguration:y?{TerminateBlueInstancesOnDeploymentSuccess:y.terminateBlueInstancesOnDeploymentSuccess?{Action:y.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:y.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:y.deploymentReadyOption?{ActionOnTimeout:y.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:y.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:y.greenFleetProvisioningOption?{Action:y.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:i}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:n,environment:r,deploymentConfigName:i,minimumHealthyHosts:s,trafficRoutingConfig:a}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:s?{Type:s.type,Value:s.value}:void 0,TrafficRoutingConfig:a?{Type:a.type,TimeBasedCanary:a.timeBasedCanary?{CanaryPercentage:a.timeBasedCanary.canaryPercentage,CanaryInterval:a.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:a.timeBasedLinear?{LinearPercentage:a.timeBasedLinear.linearPercentage,LinearInterval:a.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,n)=>({type:e,value:n})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,n)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:n}}),linear:(e,n)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:n}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(e,n,r,i)=>{let{application:s,logicalId:a}=De.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,s=5)=>{let{application:a,logicalId:c}=De.createApplication({slug:e,environment:n,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=De.createDeploymentConfig({slug:e,environment:n,trafficRoutingConfig:De.TrafficRouting.canary(i,s)}),{deploymentGroup:m,logicalId:p}=De.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:R.Ref(d),autoRollbackConfiguration:De.RollbackConfigs.onAlarmOrFailure()});return{application:a,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:s,logicalId:a}=De.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:De.BlueGreenConfigs.standard(),autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,n=5)=>({type:"canary",canaryPercentage:e,canaryInterval:n}),allAtOnce:()=>({type:"all-at-once"})}}class ie{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(e,n="md5"){let r=Xe(e);return $r(n).update(r).digest("hex")}static computeShortHash(e){return ie.computeFileHash(e).slice(0,8)}static getContentType(e){let n=un(e).toLowerCase();return ie.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...ie.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=un(e),i=Ur(e,r),s=ln(e);if(s===".")return`${i}.${n}${r}`;return Ve(s,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!bt(e))return r;let s=_r(e,{withFileTypes:!0});for(let a of s){let c=Ve(e,a.name);if(a.isDirectory())r.push(...ie.collectFiles(c,i));else if(a.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:s="md5",copyUnhashed:a=!0}=e,c=ie.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=ie.shouldHashFile(g,i),f=Wr(p),h=y?ie.computeFileHash(p,s).slice(0,8):"",S=y?ie.generateHashedFilename(g,h):g,C={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:ie.getContentType(p)};if(u.push(C),d[g]=S,r){let P=Ve(r,S),E=ln(P);if(!bt(E)){let{mkdirSync:v}=Gr("node:fs");v(E,{recursive:!0})}if(y||a)Br(p,P)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=Ve(r,"asset-manifest.json");et(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,n){let r=[];if(!e)return["/*"];let i=e.hashMap,s=n.hashMap;for(let[a,c]of Object.entries(s)){let u=i[a];if(!u||u!==c){if(r.push(`/${a}`),u&&u!==c)r.push(`/${u}`)}}for(let[a,c]of Object.entries(i))if(!s[a])r.push(`/${a}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,s=ie.collectFiles(n).filter((a)=>a.endsWith(".html")||a.endsWith(".htm"));for(let a of s){let c=Xe(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${ie.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}et(a,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,s=ie.collectFiles(n).filter((a)=>a.endsWith(".css"));for(let a of s){let c=Xe(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}et(a,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:s={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ie.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=s.unhashed||"public, max-age=3600";if(d)m=s.html||"public, max-age=0, must-revalidate";else if(u)m=s.hashed||"public, max-age=31536000, immutable";return{localPath:Ve(n,c.originalPath),s3Key:r?`${r}/${c.hashedPath}`:c.hashedPath,contentType:c.contentType,cacheControl:m,hash:c.hash}})}static compareManifests(e,n){let r={added:[],removed:[],changed:[],unchanged:[]},i=new Set(Object.keys(e.hashMap)),s=new Set(Object.keys(n.hashMap));for(let a of s)if(!i.has(a))r.added.push(a);for(let a of i)if(!s.has(a))r.removed.push(a);for(let a of s)if(i.has(a))if(e.hashMap[a]!==n.hashMap[a])r.changed.push(a);else r.unchanged.push(a);return r}static loadManifest(e){if(!bt(e))return null;try{let n=Xe(e,"utf-8");return JSON.parse(n)}catch{return null}}static saveManifest(e,n){et(n,JSON.stringify(e,null,2))}}class zi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:s,secretString:a,kmsKeyId:c,tags:u}=e,d=i||l({slug:n,environment:r,resourceType:"secret"}),m=o(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:s,SecretString:a,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,y])=>({Key:g,Value:y})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:n,environment:r,secretName:i,description:s,excludeCharacters:a,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:y,tags:f}=e,h=i||l({slug:n,environment:r,resourceType:"secret"}),S=o(h),C={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:s,GenerateSecretString:{ExcludeCharacters:a,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r},...f?Object.entries(f).map(([P,E])=>({Key:P,Value:E})):[]]}};if(y)C.Properties.KmsKeyId=y;return{secret:C,logicalId:S}}static createDatabaseSecret(e){let{slug:n,environment:r,secretName:i,username:s,dbname:a,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:s};if(a)y.dbname=a;if(c)y.engine=c;if(u)y.host=u;if(d)y.port=d;let f={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${s}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(y),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)f.Properties.KmsKeyId=m;return{secret:f,logicalId:g}}static attachToDatabase(e){let{slug:n,environment:r,secretId:i,targetId:s,targetType:a}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:s,TargetType:a}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:s,automaticallyAfterDays:a,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:n,environment:r,resourceType:"secret-rotation"}),g=o(p),y={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:i,RotationRules:{AutomaticallyAfterDays:a||30}}};if(s)y.Properties.RotationLambdaARN=s;else if(c)y.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:y,logicalId:g}}static SecretTypes={apiKey:(e,n,r)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,n,r)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,n)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>zi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class X{static createParameter(e){let{slug:n,environment:r,parameterName:i,value:s,type:a="String",description:c,tier:u="Standard",tags:d}=e,m=i||l({slug:n,environment:r,resourceType:"parameter"}),p=o(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${n}/${r}/${m}`,Type:a,Value:s,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:s})}static createSecureString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:s})}static createStringList(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:s})}static Parameters={databaseUrl:(e,n,r)=>X.createSecureString(e,n,"database-url",r,"Database connection URL"),apiEndpoint:(e,n,r)=>X.createString(e,n,"api-endpoint",r,"API endpoint URL"),appVersion:(e,n,r)=>X.createString(e,n,"app-version",r,"Application version"),featureFlags:(e,n,r)=>X.createStringList(e,n,"feature-flags",r,"Enabled feature flags"),apiKey:(e,n,r,i)=>X.createSecureString(e,n,`${r}-api-key`,i,`API key for ${r}`),oauthCredentials:(e,n,r,i)=>{let s=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),a=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:s,clientSecret:a}},smtpCredentials:(e,n,r,i,s,a)=>{let c=X.createString(e,n,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,n,"smtp-password",i,"SMTP password"),d=X.createString(e,n,"smtp-host",s,"SMTP host"),m=X.createString(e,n,"smtp-port",a.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,n,r)=>X.createSecureString(e,n,"redis-url",r,"Redis connection URL"),s3Bucket:(e,n,r)=>X.createString(e,n,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,n,r)=>X.createString(e,n,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Yt{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:s="OpenSearch_2.11",instanceType:a="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:y=!1,availabilityZoneCount:f=2,vpc:h,encryption:S,enforceHttps:C=!0,tlsSecurityPolicy:P="Policy-Min-TLS-1-2-2019-07",advancedSecurity:E,autoSnapshotHour:v=0,autoTune:w=!0,tags:D={}}=e,x=i||l({slug:n,environment:r,resourceType:"search"}),L=o(x);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:x,EngineVersion:s,ClusterConfig:{InstanceType:a,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||a,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:C,TLSSecurityPolicy:P},SnapshotOptions:{AutomatedSnapshotStartHour:v},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...S&&{EncryptionAtRestOptions:{Enabled:S.atRest??!0,...S.kmsKeyId&&{KmsKeyId:S.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:S.nodeToNode??!0}},...E&&{AdvancedSecurityOptions:{Enabled:E.enabled,InternalUserDatabaseEnabled:E.internalUserDatabase??!0,...E.masterUserName&&E.masterUserPassword&&{MasterUserOptions:{MasterUserName:E.masterUserName,MasterUserPassword:E.masterUserPassword}},...E.masterUserArn&&{MasterUserOptions:{MasterUserARN:E.masterUserArn}}}},...w&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:x},{Key:"Environment",Value:r},...Object.entries(D).map(([O,F])=>({Key:O,Value:F}))]}},logicalId:L}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:s,vpcEndpoint:a}=n;if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(i&&i.length>0)c.push({Effect:"Allow",Principal:{AWS:i},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(a)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,n)=>Yt.createDomain({slug:e,environment:n,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,n,r)=>Yt.createDomain({slug:e,environment:n,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,n)=>Yt.createDomain({slug:e,environment:n,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,n,r)=>Yt.createDomain({slug:e,environment:n,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class kt{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"redirect"}),u=o(c),d=o(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:R.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[R.Join("",[R.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:n,environment:r,rules:i}=e,s=l({slug:n,environment:r,resourceType:"cf-redirect"}),a=o(s),c=kt.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:s,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:a,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2282
2282
|
const request = event.request;
|
|
2283
2283
|
const uri = request.uri;
|
|
2284
2284
|
const querystring = request.querystring;
|
|
@@ -2332,7 +2332,7 @@ ${e.map((r)=>{let i=r.preserveQueryString!==!1,s=r.statusCode||301;return` '${r
|
|
|
2332
2332
|
}
|
|
2333
2333
|
|
|
2334
2334
|
return request;
|
|
2335
|
-
}`}static CommonRedirects={wwwToApex:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:n,preservePath:!0}),apexToWww:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:n,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")?n.slice(0,-1):n,target:n.endsWith("/")?n:`${n}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")&&n!=="/"?n:`${n}/`,target:n.endsWith("/")&&n!=="/"?n.slice(0,-1):n,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:n,newPath:r})=>({source:n,target:r,statusCode:301,preserveQueryString:!0})),categoryRename:(e,n)=>[{source:`/${e}`,target:`/${n}`,statusCode:301},{source:`/${e}/`,target:`/${n}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:n,newSlug:r})=>({source:`/products/${n}`,target:`/products/${r}`,statusCode:301})),apiVersionRedirect:(e,n,r)=>r.map((i)=>({source:`/api/${e}/${i}`,target:`/api/${n}/${i}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((n)=>({source:n,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:n,environment:r,domainRedirects:i=[],pathRedirects:s=[]}=e,a={},c=[];for(let d of i){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:y}=kt.createDomainRedirectBucket({...d,slug:n,environment:r});a[g]=m,a[y]=p,c.push(g)}let u=null;if(s.length>0){let{function:d,logicalId:m}=kt.createPathRedirectFunction({slug:n,environment:r,rules:s});a[m]=d,u=m}return{resources:a,outputs:{domainRedirectBuckets:c,pathRedirectFunctionLogicalId:u}}}static fromMapping(e,n){return Object.entries(e).map(([r,i])=>({source:r,target:i,statusCode:n?.statusCode||301,preserveQueryString:n?.preserveQueryString??!0}))}static validateRules(e){let n=[],r=[],i=new Set;for(let s of e){if(i.has(s.source))n.push(`Duplicate source path: ${s.source}`);if(i.add(s.source),s.source===s.target)n.push(`Redirect loop detected: ${s.source} -> ${s.target}`);if(!s.target.startsWith("/")&&!s.target.startsWith("http"))r.push(`Target URL should start with / or http: ${s.target}`);if(!s.source||s.source.trim()==="")n.push("Source path cannot be empty");if(!s.target||s.target.trim()==="")n.push("Target path cannot be empty")}for(let s of e){let a=e.find((c)=>c.source===s.target);if(a)r.push(`Potential redirect chain: ${s.source} -> ${s.target} -> ${a.target}`)}return{valid:n.length===0,errors:n,warnings:r}}}class ke{static generate(e){let n={},{slug:r,environment:i,region:s="us-east-1"}=e,a=ke.createLambdaExecutionRole(r,i);if(Object.assign(n,a.resources),e.email?.enabled){let c=ke.generateEmailResources(e,a.roleArn);Object.assign(n,c)}if(e.phone?.enabled){let c=ke.generatePhoneResources(e,a.roleArn);Object.assign(n,c)}if(e.sms?.enabled){let c=ke.generateSmsResources(e,a.roleArn);Object.assign(n,c)}return n}static createLambdaExecutionRole(e,n){let r=`${e}-${n}-communication-role`,i=o(r);return{resources:{[i]:{Type:"AWS::IAM::Role",Properties:{RoleName:r,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:P.GetAtt(i,"Arn"),roleName:r}}static generateEmailResources(e,n){let{slug:r,environment:i,email:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=`${c}-email-storage`,d=o(u);a[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:s.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:s.server.storage.archiveAfterDays}]:[],ExpirationInDays:s.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let m=o(`${c}-ses-identity`);if(a[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:s.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},s.notifications?.bounces||s.notifications?.complaints){let p=o(`${c}-bounce-topic`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=o(`${c}-complaint-topic`);a[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(s.server?.enabled){let p=o(`${c}-inbound-email`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:ke.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}};let g=o(`${c}-outbound-email`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}}}if(s.advanced?.analytics){let p=o(`${c}-email-analytics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.scheduling){let p=o(`${c}-email-scheduler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:300,MemorySize:256,Code:{ZipFile:ke.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:u}}}};let g=o(`${c}-email-scheduler-rule`);a[g]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:P.GetAtt(p,"Arn")}]}}}if(s.advanced?.threading){let p=o(`${c}-email-threading`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:ke.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:u}}}}}if(s.advanced?.rules){let p=o(`${c}-email-rules`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(s.advanced?.sharedMailboxes){let p=o(`${c}-shared-mailboxes`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(s.advanced?.search){let p=o(`${c}-email-search`);a[p]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${c}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return a}static generatePhoneResources(e,n){let{slug:r,environment:i,phone:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-call-log`);if(a[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.voicemail?.enabled){let p=o(`${c}-voicemail`);a[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=o(`${c}-phone-notifications`);a[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=o(`${c}-incoming-call`);if(a[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${c}-call-log`,NOTIFICATION_TOPIC_ARN:P.Ref(d)}}}},s.voicemail?.enabled){let p=o(`${c}-voicemail-handler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:s.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ke.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(s.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:P.Ref(d)}}}}}if(s.advanced?.recording){let p=o(`${c}-call-recordings`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.callbacks){let p=o(`${c}-callbacks`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.analytics){let p=o(`${c}-call-metrics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return a}static generateSmsResources(e,n){let{slug:r,environment:i,sms:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-pinpoint-app`);a[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=o(`${c}-sms-channel`);a[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:P.Ref(u),Enabled:!0,SenderId:s.senderId}};let m=o(`${c}-sms-log`);if(a[m]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.optOut?.enabled){let f=o(`${c}-sms-optout`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let p=o(`${c}-sms-notifications`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=o(`${c}-send-sms`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:P.Ref(u),MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:s.messageType||"TRANSACTIONAL"}}}};let y=o(`${c}-receive-sms`);if(a[y]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:P.Ref(p)}}}},s.advanced?.campaigns){let f=o(`${c}-sms-campaigns`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.analytics){let f=o(`${c}-sms-analytics`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.linkTracking){let f=o(`${c}-short-links`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.chatbot){let f=o(`${c}-chatbot-sessions`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let h=o(`${c}-chatbot-rules`);a[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.abTesting){let f=o(`${c}-ab-tests`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.mms){let f=o(`${c}-mms-media`);a[f]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return a}static InboundEmailCode=`
|
|
2335
|
+
}`}static CommonRedirects={wwwToApex:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:n,preservePath:!0}),apexToWww:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:n,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")?n.slice(0,-1):n,target:n.endsWith("/")?n:`${n}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")&&n!=="/"?n:`${n}/`,target:n.endsWith("/")&&n!=="/"?n.slice(0,-1):n,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:n,newPath:r})=>({source:n,target:r,statusCode:301,preserveQueryString:!0})),categoryRename:(e,n)=>[{source:`/${e}`,target:`/${n}`,statusCode:301},{source:`/${e}/`,target:`/${n}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:n,newSlug:r})=>({source:`/products/${n}`,target:`/products/${r}`,statusCode:301})),apiVersionRedirect:(e,n,r)=>r.map((i)=>({source:`/api/${e}/${i}`,target:`/api/${n}/${i}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((n)=>({source:n,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:n,environment:r,domainRedirects:i=[],pathRedirects:s=[]}=e,a={},c=[];for(let d of i){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:y}=kt.createDomainRedirectBucket({...d,slug:n,environment:r});a[g]=m,a[y]=p,c.push(g)}let u=null;if(s.length>0){let{function:d,logicalId:m}=kt.createPathRedirectFunction({slug:n,environment:r,rules:s});a[m]=d,u=m}return{resources:a,outputs:{domainRedirectBuckets:c,pathRedirectFunctionLogicalId:u}}}static fromMapping(e,n){return Object.entries(e).map(([r,i])=>({source:r,target:i,statusCode:n?.statusCode||301,preserveQueryString:n?.preserveQueryString??!0}))}static validateRules(e){let n=[],r=[],i=new Set;for(let s of e){if(i.has(s.source))n.push(`Duplicate source path: ${s.source}`);if(i.add(s.source),s.source===s.target)n.push(`Redirect loop detected: ${s.source} -> ${s.target}`);if(!s.target.startsWith("/")&&!s.target.startsWith("http"))r.push(`Target URL should start with / or http: ${s.target}`);if(!s.source||s.source.trim()==="")n.push("Source path cannot be empty");if(!s.target||s.target.trim()==="")n.push("Target path cannot be empty")}for(let s of e){let a=e.find((c)=>c.source===s.target);if(a)r.push(`Potential redirect chain: ${s.source} -> ${s.target} -> ${a.target}`)}return{valid:n.length===0,errors:n,warnings:r}}}class ke{static generate(e){let n={},{slug:r,environment:i,region:s="us-east-1"}=e,a=ke.createLambdaExecutionRole(r,i);if(Object.assign(n,a.resources),e.email?.enabled){let c=ke.generateEmailResources(e,a.roleArn);Object.assign(n,c)}if(e.phone?.enabled){let c=ke.generatePhoneResources(e,a.roleArn);Object.assign(n,c)}if(e.sms?.enabled){let c=ke.generateSmsResources(e,a.roleArn);Object.assign(n,c)}return n}static createLambdaExecutionRole(e,n){let r=`${e}-${n}-communication-role`,i=o(r);return{resources:{[i]:{Type:"AWS::IAM::Role",Properties:{RoleName:r,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:R.GetAtt(i,"Arn"),roleName:r}}static generateEmailResources(e,n){let{slug:r,environment:i,email:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=`${c}-email-storage`,d=o(u);a[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:s.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:s.server.storage.archiveAfterDays}]:[],ExpirationInDays:s.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let m=o(`${c}-ses-identity`);if(a[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:s.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},s.notifications?.bounces||s.notifications?.complaints){let p=o(`${c}-bounce-topic`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=o(`${c}-complaint-topic`);a[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(s.server?.enabled){let p=o(`${c}-inbound-email`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:ke.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}};let g=o(`${c}-outbound-email`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}}}if(s.advanced?.analytics){let p=o(`${c}-email-analytics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.scheduling){let p=o(`${c}-email-scheduler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:300,MemorySize:256,Code:{ZipFile:ke.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:u}}}};let g=o(`${c}-email-scheduler-rule`);a[g]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:R.GetAtt(p,"Arn")}]}}}if(s.advanced?.threading){let p=o(`${c}-email-threading`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:ke.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:u}}}}}if(s.advanced?.rules){let p=o(`${c}-email-rules`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(s.advanced?.sharedMailboxes){let p=o(`${c}-shared-mailboxes`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(s.advanced?.search){let p=o(`${c}-email-search`);a[p]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${c}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return a}static generatePhoneResources(e,n){let{slug:r,environment:i,phone:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-call-log`);if(a[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.voicemail?.enabled){let p=o(`${c}-voicemail`);a[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=o(`${c}-phone-notifications`);a[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=o(`${c}-incoming-call`);if(a[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${c}-call-log`,NOTIFICATION_TOPIC_ARN:R.Ref(d)}}}},s.voicemail?.enabled){let p=o(`${c}-voicemail-handler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:s.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ke.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(s.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:R.Ref(d)}}}}}if(s.advanced?.recording){let p=o(`${c}-call-recordings`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.callbacks){let p=o(`${c}-callbacks`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.analytics){let p=o(`${c}-call-metrics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return a}static generateSmsResources(e,n){let{slug:r,environment:i,sms:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-pinpoint-app`);a[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=o(`${c}-sms-channel`);a[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:R.Ref(u),Enabled:!0,SenderId:s.senderId}};let m=o(`${c}-sms-log`);if(a[m]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.optOut?.enabled){let f=o(`${c}-sms-optout`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let p=o(`${c}-sms-notifications`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=o(`${c}-send-sms`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:R.Ref(u),MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:s.messageType||"TRANSACTIONAL"}}}};let y=o(`${c}-receive-sms`);if(a[y]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:R.Ref(p)}}}},s.advanced?.campaigns){let f=o(`${c}-sms-campaigns`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.analytics){let f=o(`${c}-sms-analytics`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.linkTracking){let f=o(`${c}-short-links`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.chatbot){let f=o(`${c}-chatbot-sessions`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let h=o(`${c}-chatbot-rules`);a[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.abTesting){let f=o(`${c}-ab-tests`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.mms){let f=o(`${c}-mms-media`);a[f]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return a}static InboundEmailCode=`
|
|
2336
2336
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
2337
2337
|
const s3 = new S3Client({});
|
|
2338
2338
|
exports.handler = async (event) => {
|
|
@@ -2456,9 +2456,9 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
|
|
|
2456
2456
|
# Configure application server (PM2, Nginx, Apache)
|
|
2457
2457
|
# Mount EFS for shared file storage
|
|
2458
2458
|
`}},storage:{uploads:{type:"efs",performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30}},backups:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldBackups",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},static:{public:!0,versioning:!1,encryption:!1,cors:[{allowedOrigins:[i||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${r}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:i?{domain:i,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:u==="mysql"?{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",innodb_buffer_pool_size:"{DBInstanceClassMemory*3/4}",slow_query_log:"1",long_query_time:"2"}}}:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",shared_buffers:"{DBInstanceClassMemory/4}",log_min_duration_statement:"2000"}}},cache:d==="redis"?{redis:{nodeType:"cache.t3.medium",numCacheNodes:2,engine:"redis",engineVersion:"7.0",port:6379,parameterGroup:{maxmemoryPolicy:"allkeys-lru",timeout:"300"},snapshotRetentionLimit:5,snapshotWindow:"03:00-05:00",automaticFailoverEnabled:!0}}:void 0,queues:{jobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:345600,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3},emails:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},functions:{"job-worker":{runtime:"nodejs20.x",handler:"dist/workers/jobs.handler",memory:2048,timeout:900,events:[{type:"sqs",queueName:`${r}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${r}-emails`,batchSize:10}]},cleanup:{runtime:"nodejs20.x",handler:"dist/tasks/cleanup.handler",memory:512,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},monitoring:{dashboard:{name:`${r}-web-app`,widgets:[{type:"metric",metrics:["EC2CPUUtilization","ALBRequestCount","ALBTargetResponseTime","RDSCPUUtilization","RDSDatabaseConnections","RDSReadLatency","RDSWriteLatency"]}]},alarms:[{metric:"EC2CPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSCPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSDatabaseConnections",threshold:400,evaluationPeriods:1},{metric:"ALBTargetResponseTime",threshold:2000,evaluationPeriods:2},{metric:"ALBUnhealthyHostCount",threshold:1,evaluationPeriods:1}],logs:{retention:14,groups:[`${r}-app`,`${r}-nginx`,`${r}-workers`]}},security:{certificate:i?{domain:i,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","knownBadInputs"]},securityGroups:{alb:{ingress:[{port:80,protocol:"tcp",cidr:"0.0.0.0/0"},{port:443,protocol:"tcp",cidr:"0.0.0.0/0"}]},app:{ingress:[{port:3000,protocol:"tcp",source:"alb-sg"}]},database:{ingress:[{port:u==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...d==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function qm(e){let{name:n,slug:r,domain:i,repository:s,phpVersion:a="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:i}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[a],default:a},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:i,phpVersion:a,repository:{...s,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function Wm(e){let{name:n,slug:r,domain:i,layers:s,phpVersion:a="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:y="us-east-1"}=e;return{project:{name:n,slug:r,region:y},mode:"serverless",environments:{production:{type:"production",domain:i,app:{kind:"php",runtime:"provided.al2023",phpVersion:a,architecture:c,layers:s,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:i}}}}}function Km(e){return{root:e.root??"packages/ui/dist",deploy:"server",type:"static",domain:e.domain,build:e.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:e.username??"admin",password:e.password}}}var fu=da,hu="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function Si(e){let n=e.split(".").filter(Boolean);return n.length<=2?e:n.slice(-2).join(".")}function Ai(e){let n=2166136261;for(let r=0;r<e.length;r++)n^=e.charCodeAt(r),n=Math.imul(n,16777619);return n>>>0}var yu=20000,bu=12000;function Su(e){return yu+Ai(e)%bu}function Ln(e,n){let r=Si(e);if(r===e)return`dashboard.${r}`;for(let i of n)if(i===r)return`dashboard.${r}`;return`dashboard.${e}`}function On(e,n){let r=[],i=e.infrastructure?.dns?.domain;if(i&&!e.cloud?.attachTo)r.push(i);if(n&&e.environments?.[n]?.domain)r.push(e.environments[n].domain);for(let s of Object.values(e.sites??{})){let a=s;if(!a||a.redirect)continue;let c=a.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((s)=>s&&!s.startsWith("dashboard."))}function vu(e,n,r){if(r)return r;let i=On(e,n),s=i[0];if(!s)return null;return Ln(s,i)}function Cu(e,n,r){if(r)return[r];let i=On(e,n),s=[];for(let a of i){let c=Ln(a,i);if(!s.includes(c))s.push(c)}return s}function Zt(e){return Object.entries(e.sites??{}).some(([n,r])=>{if(!r)return!1;let i=r.root??"";return Vr(n)||i==="ui/dist"||i.endsWith("/ui/dist")||i.endsWith("/dist/ui")})}var fl="dashboard-";function hl(e){return fl+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Vr(e){return e==="dashboard"||e.startsWith(fl)}function Hi(e,n,r){if(Zt(e))return[];if(e.cloud?.attachTo)return[];let i=r.password?{auth:{username:r.username||"admin",password:r.password,realm:r.realm}}:{},s=r.build===!1||r.build===void 0?{}:{build:r.build};if(r.live!==!1){let c=vu(e,n,r.domain);if(!c)return[];let u=r.port??Su(c),d=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,m={root:r.uiRoot,deploy:"server",domain:c,preStart:["bun install --production --no-save"],start:`bun ${hu} --box --host 127.0.0.1 --port ${u}`,port:u,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...d?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:d.password}:{}},zeroDowntime:!1,sharedPaths:[fu],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:hl(c),site:m}]}return Cu(e,n,r.domain).map((c)=>({name:hl(c),site:{root:r.uiRoot,deploy:"server",type:"static",domain:c,ssl:{provider:"letsencrypt"},...s,...i}}))}function Jm(e,n,r){return Hi(e,n,r)[0]??null}function Ct(e,n){let r={...e};for(let i in n){let s=n[i],a=r[i];if(s===void 0)continue;if(Array.isArray(s)&&Array.isArray(a))r[i]=[...a,...s];else if(typeof s==="object"&&s!==null&&!Array.isArray(s)&&typeof a==="object"&&a!==null&&!Array.isArray(a))r[i]=Ct(a,s);else r[i]=s}return r}function yl(e,n){return Ct(e,n)}function Xm(...e){return e.reduce((n,r)=>Ct(n,r),{})}function Qm(e,n){return(r)=>{let i=e(r);if(typeof n==="function")return yl(i,n(i,r));return yl(i,n)}}function In(e){return{infrastructure:e}}function Ym(e){return In({monitoring:e})}function Zm(e){return In({security:e})}function eg(e){return In({databases:e})}function tg(e){return In({cache:e})}function rg(e){return In({cdn:e})}function ng(e){return In({queues:e})}import{existsSync as $n,readFileSync as vt}from"node:fs";import{homedir as Bn}from"node:os";import{join as Fn}from"node:path";function Tu(){let e=process.env.AWS_ACCESS_KEY_ID,n=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!n)return null;return{accessKeyId:e,secretAccessKey:n,sessionToken:process.env.AWS_SESSION_TOKEN}}function Eu(e){let n=e?.profile||process.env.AWS_PROFILE||"default",r=e?.credentialsFile||Fn(Bn(),".aws","credentials");if(!$n(r))return null;try{let i=vt(r,"utf-8");return Ci(i,n)}catch{return null}}function Ci(e,n){let r=e.split(`
|
|
2459
|
-
`),i=null,s,a,c;for(let u of r){let d=u.trim();if(!d||d.startsWith("#")||d.startsWith(";"))continue;let m=d.match(/^\[([^\]]+)\]$/);if(m){if(i===n&&s&&a)return{accessKeyId:s,secretAccessKey:a,sessionToken:c};i=m[1],s=void 0,a=void 0,c=void 0;continue}if(i===n){let[p,...g]=d.split("="),y=g.join("=").trim();switch(p.trim().toLowerCase()){case"aws_access_key_id":s=y;break;case"aws_secret_access_key":a=y;break;case"aws_session_token":c=y;break}}}if(i===n&&s&&a)return{accessKeyId:s,secretAccessKey:a,sessionToken:c};return null}async function wu(e){let n=e?.timeout??1000,r="http://169.254.169.254";try{let i=await
|
|
2460
|
-
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===a;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function bl(e){let n=e||await Gi(),r=Iu(),{signRequest:i}=await import("./chunk-8cxdvpzy.js"),s=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,a="Action=GetCallerIdentity&Version=2011-06-15",c=i({method:"POST",url:s,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...n,service:"sts",region:r}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:c.body});if(!u.ok)throw Error(`Failed to get account ID: ${await u.text()}`);let d=await u.text(),m=
|
|
2461
|
-
Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,n,r){let s={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!s)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,s,r)}async createChangeSet(e){let n={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=s,n[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=s;return(await this.request("CreateChangeSet",n)).ChangeSetId}async executeChangeSet(e,n){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:n})}async describeStacks(e){let n=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(n)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,s=Array.isArray(i)?i[0]:i;if(!s)return{};let a={},c=s.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)a[d.OutputKey]=d.OutputValue}return a}}function Tt(e,n=""){let r={};for(let[i,s]of Object.entries(e)){let a=n?`${n}.${i}`:i;if(Array.isArray(s))s.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Tt(c,`${a}.${u+1}`));else r[`${a}.${u+1}`]=String(c)});else if(typeof s==="object"&&s!==null)Object.assign(r,Tt(s,a));else if(s!==void 0&&s!==null)r[a]=String(s)}return r}function vi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(s,a,c){let u=1,d=c,m=`<${a}`,p=`</${a}>`;while(d<s.length&&u>0){let g=s.indexOf(m,d),y=s.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=s[g+m.length];if(f===">"||f===" "||f==="/"){let h=s.indexOf(">",g);if(h!==-1&&s[h-1]==="/")d=h+1;else u++,d=h+1}else d=g+m.length}else{if(u--,u===0)return y;d=y+p.length}}return-1}function r(s,a){while(a<s.length&&/\s/.test(s[a]))a++;if(a>=s.length||s[a]!=="<"){let S=s.indexOf("<",a);if(S===-1)return{value:s.slice(a).trim(),end:s.length};return{value:s.slice(a,S).trim(),end:S}}if(s[a+1]==="/")return{value:void 0,end:a};let c=s.slice(a).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:a+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:a+c[0].length};let m=a+c[0].length,p=`</${u}>`,g=n(s,u,m);if(g===-1)return{value:void 0,end:a+c[0].length};let y=s.slice(m,g).trim();if(!y.includes("<"))return{value:y,end:g+p.length};let f={},h=m;while(h<g){while(h<g&&/\s/.test(s[h]))h++;if(h>=g)break;if(s[h]!=="<"||s[h+1]==="/")break;let S=s.slice(h).match(/^<(\w+)/);if(!S)break;let C=S[1],E=r(s,h);if(E.value===void 0){h++;continue}if(C==="member"||f[C]!==void 0){if(!Array.isArray(f[C]))f[C]=f[C]!==void 0?[f[C]]:[];f[C].push(E.value)}else f[C]=E.value;h=E.end}return{value:f,end:g+p.length}}return r(e,0).value||{}}function Ti(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Ri(e){let r=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackName:s.StackName||"",StackId:s.StackId,StackStatus:s.StackStatus,CreationTime:s.CreationTime,LastUpdatedTime:s.LastUpdatedTime,StackStatusReason:s.StackStatusReason,Description:s.Description}))}function Pi(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackId:s.StackId||"",EventId:s.EventId||"",StackName:s.StackName||"",LogicalResourceId:s.LogicalResourceId||"",PhysicalResourceId:s.PhysicalResourceId,ResourceType:s.ResourceType||"",Timestamp:s.Timestamp||"",ResourceStatus:s.ResourceStatus||"",ResourceStatusReason:s.ResourceStatusReason}))}var Ei=5242880,Rt=5242880;var wi=5242880;class Da{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(e={}){this.region=e.region||process.env.AWS_REGION||"us-east-1",this.endpoint=e.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=e.forcePathStyle||!1,this.credentials=e.credentials,this.credentialOptions=e.credentialOptions,this.retryOptions=e.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return Gi(this.credentialOptions)}buildUrl(e,n){let r=n?encodeURIComponent(n).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return n?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let i=new URL(this.endpoint);return i.hostname=`${e}.${i.hostname}`,n?`${i.origin}/${r}`:i.origin}async get(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n),a={};if(r.range)a.Range=r.range;if(r.ifModifiedSince)a["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)a["If-Match"]=r.ifMatch;if(r.ifNoneMatch)a["If-None-Match"]=r.ifNoneMatch;let c=new URL(s);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=Y({method:"GET",url:c.toString(),headers:a,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new be(`Failed to get object: ${m}`,d.status,e,n)}return d}async getText(e,n,r={}){return(await this.get(e,n,r)).text()}async getJSON(e,n,r={}){return(await this.get(e,n,r)).json()}async getBuffer(e,n,r={}){return(await this.get(e,n,r)).arrayBuffer()}async put(e,n,r,i={}){let s,a;if(typeof r==="string")s=new TextEncoder().encode(r).length,a=r;else if(r instanceof ArrayBuffer)s=r.byteLength,a=r;else if(r instanceof Uint8Array)s=r.byteLength,a=r;else if(r instanceof Blob)s=r.size,a=r;else return this.uploadMultipart(e,n,r,{...i,partSize:Rt});if(s>wi){let c=Ni(a).stream();return this.uploadMultipart(e,n,c,{...i,partSize:Rt})}return this.putSimple(e,n,a,s,i)}async putSimple(e,n,r,i,s){let a=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":s.contentType||Gn(n)};if(s.contentEncoding)u["Content-Encoding"]=s.contentEncoding;if(s.cacheControl)u["Cache-Control"]=s.cacheControl;if(s.contentDisposition)u["Content-Disposition"]=s.contentDisposition;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)u["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)u["x-amz-acl"]=s.acl;if(s.tagging)u["x-amz-tagging"]=s.tagging;if(s.metadata)for(let[y,f]of Object.entries(s.metadata))u[`x-amz-meta-${y.toLowerCase()}`]=f;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=Y({method:"PUT",url:c,headers:u,body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let y=await p.text();throw new be(`Failed to put object: ${y}`,p.status,e,n)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=Y({method:"DELETE",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok&&a.status!==204){let c=await a.text();throw new be(`Failed to delete object: ${c}`,a.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,a=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${Di(h)}</Key></Object>`).join("")}</Delete>`,c=Y({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:a,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:a});if(!u.ok){let h=await u.text();throw new be(`Failed to delete objects: ${h}`,u.status,e)}let d=await u.text(),m=[],p=[],g=/<Deleted><Key>([^<]+)<\/Key>/g,y;while((y=g.exec(d))!==null)m.push(y[1]);let f=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((y=f.exec(d))!==null)p.push({key:y[1],error:`${y[2]}: ${y[3]}`});return{deleted:m,errors:p}}async list(e,n={}){let r=await this.getCredentials(),i=new URL(this.buildUrl(e));if(i.searchParams.set("list-type","2"),n.prefix)i.searchParams.set("prefix",n.prefix);if(n.delimiter)i.searchParams.set("delimiter",n.delimiter);if(n.maxKeys)i.searchParams.set("max-keys",String(n.maxKeys));if(n.continuationToken)i.searchParams.set("continuation-token",n.continuationToken);if(n.startAfter)i.searchParams.set("start-after",n.startAfter);let s=Y({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok){let u=await a.text();throw new be(`Failed to list objects: ${u}`,a.status,e)}let c=await a.text();return Ii(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let s of i.contents)yield s;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=Y({method:"HEAD",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(a.status===404)return null;if(!a.ok){let u=await a.text();throw new be(`Failed to head object: ${u}`,a.status,e,n)}let c={};return a.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(a.headers.get("Content-Length")||0),contentType:a.headers.get("Content-Type")||"application/octet-stream",etag:(a.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(a.headers.get("Last-Modified")||0),metadata:c,storageClass:a.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:a.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,n){return await this.head(e,n)!==null}async copy(e,n,r,i,s={}){let a=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(s.metadataDirective)u["x-amz-metadata-directive"]=s.metadataDirective;if(s.contentType)u["Content-Type"]=s.contentType;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.acl)u["x-amz-acl"]=s.acl;if(s.metadata)for(let[f,h]of Object.entries(s.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=Y({method:"PUT",url:c,headers:u,...a,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let f=await m.text();throw new be(`Failed to copy object: ${f}`,m.status,r,i)}let g=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:g?g[1]:""}}async getPresignedUrl(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n);return cs({url:s,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let s=await this.getCredentials(),a=Math.max(i.partSize||Rt,Ei),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,n,i);try{let p=await this.uploadParts(e,n,m,d,c,a,s,u,i.concurrency||4,i.onProgress);return await this.completeMultipartUpload(e,n,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,n,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,n,r){let i=await this.getCredentials(),s=this.buildUrl(e,n),a=`${s}?uploads`,c={"Content-Type":r.contentType||Gn(n)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[y,f]of Object.entries(r.metadata))c[`x-amz-meta-${y.toLowerCase()}`]=f;let u=Y({method:"POST",url:a,headers:c,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let y=await d.text();throw new be(`Failed to initiate multipart upload: ${y}`,d.status,e,n)}let p=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!p)throw new be("Failed to parse upload ID from response",0,e,n);let g=s;if(d.url)try{let y=new URL(d.url);y.search="",g=y.toString()}catch{}return{uploadId:p[1],baseUrl:g}}async uploadParts(e,n,r,i,s,a,c,u,d,m){let p=[],g=s.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/a):void 0,C=new Map,E=async(v,I)=>{let D=`${r}?partNumber=${I}&uploadId=${encodeURIComponent(i)}`,x={"Content-Length":String(v.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},L=Y({method:"PUT",url:D,headers:x,...c,service:"s3",region:this.region}),B=await fetch(L.url,{method:L.method,headers:L.headers,body:v,redirect:"error"});if(!B.ok){let F=await B.text();throw new be(`Failed to upload part ${I}: ${F}`,B.status,e,n)}let O=(B.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new be(`Missing ETag for part ${I}`,B.status,e,n);return{partNumber:I,etag:O}},w=async()=>{let v=await Promise.race(C.values());C.delete(v.partNumber),p.push(v)};while(!0){let{done:v,value:I}=await g.read();if(I){let D=new Uint8Array(f.length+I.length);D.set(f),D.set(I,f.length),f=D}while(f.length>=a||v&&f.length>0){let D=f.slice(0,a);f=f.slice(a);let x=y++;if(C.size>=d)await w();if(C.set(x,E(D,x)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:x,totalParts:S||x})}if(v)break}while(C.size>0)await w();return p.sort((v,I)=>v.partNumber-I.partNumber),p}async completeMultipartUpload(e,n,r,i,s){let a=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${s.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=Y({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:d});if(!p.ok){let h=await p.text();throw new be(`Failed to complete multipart upload: ${h}`,p.status,e,n)}let y=(await p.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:y?y[1]:""}}async abortMultipartUpload(e,n,r,i){let s=await this.getCredentials(),a=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=Y({method:"DELETE",url:a,...s,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let r=[];for await(let c of this.listAll(e,{}))if(r.push(c.key),r.length>=1000)await this.deleteMany(e,r),r=[];if(r.length>0)await this.deleteMany(e,r);let i=await this.getCredentials(),s=this.buildUrl(e),a=Y({method:"DELETE",url:s,...i,service:"s3",region:this.region});await fetch(a.url,{method:a.method,headers:a.headers})}}class be extends Error{statusCode;bucket;key;constructor(e,n,r,i){super(e);this.statusCode=n;this.bucket=r;this.key=i;this.name="S3Error"}}function Ii(e){let n=[],r=[],i=/<Contents>([\s\S]*?)<\/Contents>/g,s;while((s=i.exec(e))!==null){let c=s[1];n.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let a=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((s=a.exec(e))!==null)r.push(s[1]);return{contents:n,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,n){let r=new RegExp(`<${n}>([^<]*)</${n}>`),i=e.match(r);return i?i[1]:null}function Di(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Gn(e){let n=e.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[n||""]||"application/octet-stream"}function Ni(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function Du(e){return new Da(e)}class ku{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Pn(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let n=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,i=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2459
|
+
`),i=null,s,a,c;for(let u of r){let d=u.trim();if(!d||d.startsWith("#")||d.startsWith(";"))continue;let m=d.match(/^\[([^\]]+)\]$/);if(m){if(i===n&&s&&a)return{accessKeyId:s,secretAccessKey:a,sessionToken:c};i=m[1],s=void 0,a=void 0,c=void 0;continue}if(i===n){let[p,...g]=d.split("="),y=g.join("=").trim();switch(p.trim().toLowerCase()){case"aws_access_key_id":s=y;break;case"aws_secret_access_key":a=y;break;case"aws_session_token":c=y;break}}}if(i===n&&s&&a)return{accessKeyId:s,secretAccessKey:a,sessionToken:c};return null}async function wu(e){let n=e?.timeout??1000,r="http://169.254.169.254";try{let i=await je("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},n);if(!i.ok)return null;let s=await i.text(),a=await je("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":s}},n);if(!a.ok)return null;let c=(await a.text()).trim(),u=await je(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":s}},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Au(e){let n=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,i=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,s=null;if(r)s=`http://169.254.170.2${r}`;else if(i)s=i;if(!s)return null;try{let a={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)a.Authorization=c;let u=await je(s,{headers:a},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Ru(e){let n=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,i=process.env.AWS_ROLE_ARN,s=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!i)return null;try{let a=vt(r,"utf-8").trim(),c=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",u=c.startsWith("us-gov")?`https://sts.${c}.amazonaws.com`:c==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${c}.amazonaws.com`,d=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:i,RoleSessionName:s,WebIdentityToken:a}),m=await je(`${u}/?${d.toString()}`,{method:"POST"},n);if(!m.ok)return null;let p=await m.text(),g=Ue(p,"AccessKeyId"),y=Ue(p,"SecretAccessKey"),f=Ue(p,"SessionToken"),h=Ue(p,"Expiration");if(!g||!y)return null;return{accessKeyId:g,secretAccessKey:y,sessionToken:f??void 0,expiration:h?new Date(h):void 0}}catch{return null}}async function Gi(e){let n=Tu();if(n)return n;let r=Eu(e);if(r)return r;let i=await Ru(e);if(i)return i;let s=await Au(e);if(s)return s;let a=await wu(e);if(a)return a;throw Error("Could not find AWS credentials. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or configure ~/.aws/credentials, or run on an EC2 instance with an IAM role.")}function ig(e){let n=null,r=null;return async()=>{if(n){if(!n.expiration)return n;let i=300000;if(n.expiration.getTime()-Date.now()>i)return n}if(r)return r;return r=Gi(e).then((i)=>(n=i,r=null,i)).catch((i)=>{throw r=null,i}),r}}async function je(e,n,r){let i=new AbortController,s=setTimeout(()=>i.abort(),r);try{let a=await fetch(e,{...n,signal:i.signal});return clearTimeout(s),a}catch(a){throw clearTimeout(s),a}}function Ue(e,n){let r=new RegExp(`<${n}>([^<]+)</${n}>`),i=e.match(r);return i?i[1]:null}async function Pn(e){return Gi({profile:e})}function Iu(e){let n=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(n)return n;let r=Fn(Bn(),".aws","config");if($n(r))try{let i=vt(r,"utf-8"),s=e||process.env.AWS_PROFILE||"default",a=s==="default"?"[default]":`[profile ${s}]`,c=i.split(`
|
|
2460
|
+
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===a;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function bl(e){let n=e||await Gi(),r=Iu(),{signRequest:i}=await import("./chunk-8cxdvpzy.js"),s=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,a="Action=GetCallerIdentity&Version=2011-06-15",c=i({method:"POST",url:s,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...n,service:"sts",region:r}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:c.body});if(!u.ok)throw Error(`Failed to get account ID: ${await u.text()}`);let d=await u.text(),m=Ue(d,"Account");if(!m)throw Error("Failed to parse account ID from response");return m}class Pu{profile;credentials=null;region;constructor(e="us-east-1",n="default"){this.profile=n;this.region=e}async init(){if(this.credentials=await Pn(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,n){let r=await this.ensureCredentials(),i={Action:e,Version:"2010-05-15",...Tt(n)},s=new URLSearchParams(i).toString(),c=await(await _t({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken})).text();return vi(c)}async createStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[s,[a,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${s+1}.ParameterKey`]=a,n[`Parameters.member.${s+1}.ParameterValue`]=c;if(e.capabilities)for(let[s,a]of e.capabilities.entries())n[`Capabilities.member.${s+1}`]=a;if(e.tags)for(let[s,[a,c]]of Object.entries(e.tags).entries())n[`Tags.member.${s+1}.Key`]=a,n[`Tags.member.${s+1}.Value`]=c;if(e.timeoutInMinutes)n.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)n.OnFailure=e.onFailure;let r=await this.request("CreateStack",n);return(r?.CreateStackResult||r?.CreateStackResponse?.CreateStackResult||r)?.StackId}async updateStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[s,[a,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${s+1}.ParameterKey`]=a,n[`Parameters.member.${s+1}.ParameterValue`]=c;if(e.capabilities)for(let[s,a]of e.capabilities.entries())n[`Capabilities.member.${s+1}`]=a;if(e.tags)for(let[s,[a,c]]of Object.entries(e.tags).entries())n[`Tags.member.${s+1}.Key`]=a,n[`Tags.member.${s+1}.Value`]=c;let r=await this.request("UpdateStack",n);return(r?.UpdateStackResult||r?.UpdateStackResponse?.UpdateStackResult||r)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,s=Array.isArray(i)?i[0]:i;if(!s)throw Error(`Stack ${e} not found`);return Ti(s)}async listStacks(e){let n={};if(e)for(let[i,s]of e.entries())n[`StackStatusFilter.member.${i+1}`]=s;let r=await this.request("ListStacks",n);return Ri(r)}async describeStackEvents(e){let n=await this.request("DescribeStackEvents",{StackName:e});return Pi(n)}async waitForStack(e,n,r){let a=0,c=null;while(a<360){a++;let u=await this.describeStack(e);if(r)try{let d=await this.describeStackEvents(e),m=[];if(c){for(let p of d){if(p.EventId===c)break;m.push(p)}m.reverse()}else if(d.length>0)m=[d[0]];for(let p of m)r(p);if(d.length>0)c=d[0].EventId}catch{}if(u.StackStatus&&n.includes(u.StackStatus))return u;if(u.StackStatus?.includes("FAILED")||u.StackStatus?.includes("ROLLBACK"))throw Error(`Stack reached failed state: ${u.StackStatus}
|
|
2461
|
+
Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,n,r){let s={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!s)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,s,r)}async createChangeSet(e){let n={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=s,n[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=s;return(await this.request("CreateChangeSet",n)).ChangeSetId}async executeChangeSet(e,n){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:n})}async describeStacks(e){let n=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(n)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,s=Array.isArray(i)?i[0]:i;if(!s)return{};let a={},c=s.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)a[d.OutputKey]=d.OutputValue}return a}}function Tt(e,n=""){let r={};for(let[i,s]of Object.entries(e)){let a=n?`${n}.${i}`:i;if(Array.isArray(s))s.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Tt(c,`${a}.${u+1}`));else r[`${a}.${u+1}`]=String(c)});else if(typeof s==="object"&&s!==null)Object.assign(r,Tt(s,a));else if(s!==void 0&&s!==null)r[a]=String(s)}return r}function vi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(s,a,c){let u=1,d=c,m=`<${a}`,p=`</${a}>`;while(d<s.length&&u>0){let g=s.indexOf(m,d),y=s.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=s[g+m.length];if(f===">"||f===" "||f==="/"){let h=s.indexOf(">",g);if(h!==-1&&s[h-1]==="/")d=h+1;else u++,d=h+1}else d=g+m.length}else{if(u--,u===0)return y;d=y+p.length}}return-1}function r(s,a){while(a<s.length&&/\s/.test(s[a]))a++;if(a>=s.length||s[a]!=="<"){let S=s.indexOf("<",a);if(S===-1)return{value:s.slice(a).trim(),end:s.length};return{value:s.slice(a,S).trim(),end:S}}if(s[a+1]==="/")return{value:void 0,end:a};let c=s.slice(a).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:a+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:a+c[0].length};let m=a+c[0].length,p=`</${u}>`,g=n(s,u,m);if(g===-1)return{value:void 0,end:a+c[0].length};let y=s.slice(m,g).trim();if(!y.includes("<"))return{value:y,end:g+p.length};let f={},h=m;while(h<g){while(h<g&&/\s/.test(s[h]))h++;if(h>=g)break;if(s[h]!=="<"||s[h+1]==="/")break;let S=s.slice(h).match(/^<(\w+)/);if(!S)break;let C=S[1],P=r(s,h);if(P.value===void 0){h++;continue}if(C==="member"||f[C]!==void 0){if(!Array.isArray(f[C]))f[C]=f[C]!==void 0?[f[C]]:[];f[C].push(P.value)}else f[C]=P.value;h=P.end}return{value:f,end:g+p.length}}return r(e,0).value||{}}function Ti(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Ri(e){let r=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackName:s.StackName||"",StackId:s.StackId,StackStatus:s.StackStatus,CreationTime:s.CreationTime,LastUpdatedTime:s.LastUpdatedTime,StackStatusReason:s.StackStatusReason,Description:s.Description}))}function Pi(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackId:s.StackId||"",EventId:s.EventId||"",StackName:s.StackName||"",LogicalResourceId:s.LogicalResourceId||"",PhysicalResourceId:s.PhysicalResourceId,ResourceType:s.ResourceType||"",Timestamp:s.Timestamp||"",ResourceStatus:s.ResourceStatus||"",ResourceStatusReason:s.ResourceStatusReason}))}var Ei=5242880,Rt=5242880;var wi=5242880;class Da{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(e={}){this.region=e.region||process.env.AWS_REGION||"us-east-1",this.endpoint=e.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=e.forcePathStyle||!1,this.credentials=e.credentials,this.credentialOptions=e.credentialOptions,this.retryOptions=e.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return Gi(this.credentialOptions)}buildUrl(e,n){let r=n?encodeURIComponent(n).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return n?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let i=new URL(this.endpoint);return i.hostname=`${e}.${i.hostname}`,n?`${i.origin}/${r}`:i.origin}async get(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n),a={};if(r.range)a.Range=r.range;if(r.ifModifiedSince)a["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)a["If-Match"]=r.ifMatch;if(r.ifNoneMatch)a["If-None-Match"]=r.ifNoneMatch;let c=new URL(s);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=Y({method:"GET",url:c.toString(),headers:a,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new be(`Failed to get object: ${m}`,d.status,e,n)}return d}async getText(e,n,r={}){return(await this.get(e,n,r)).text()}async getJSON(e,n,r={}){return(await this.get(e,n,r)).json()}async getBuffer(e,n,r={}){return(await this.get(e,n,r)).arrayBuffer()}async put(e,n,r,i={}){let s,a;if(typeof r==="string")s=new TextEncoder().encode(r).length,a=r;else if(r instanceof ArrayBuffer)s=r.byteLength,a=r;else if(r instanceof Uint8Array)s=r.byteLength,a=r;else if(r instanceof Blob)s=r.size,a=r;else return this.uploadMultipart(e,n,r,{...i,partSize:Rt});if(s>wi){let c=Ni(a).stream();return this.uploadMultipart(e,n,c,{...i,partSize:Rt})}return this.putSimple(e,n,a,s,i)}async putSimple(e,n,r,i,s){let a=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":s.contentType||Gn(n)};if(s.contentEncoding)u["Content-Encoding"]=s.contentEncoding;if(s.cacheControl)u["Cache-Control"]=s.cacheControl;if(s.contentDisposition)u["Content-Disposition"]=s.contentDisposition;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)u["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)u["x-amz-acl"]=s.acl;if(s.tagging)u["x-amz-tagging"]=s.tagging;if(s.metadata)for(let[y,f]of Object.entries(s.metadata))u[`x-amz-meta-${y.toLowerCase()}`]=f;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=Y({method:"PUT",url:c,headers:u,body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let y=await p.text();throw new be(`Failed to put object: ${y}`,p.status,e,n)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=Y({method:"DELETE",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok&&a.status!==204){let c=await a.text();throw new be(`Failed to delete object: ${c}`,a.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,a=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${Di(h)}</Key></Object>`).join("")}</Delete>`,c=Y({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:a,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:a});if(!u.ok){let h=await u.text();throw new be(`Failed to delete objects: ${h}`,u.status,e)}let d=await u.text(),m=[],p=[],g=/<Deleted><Key>([^<]+)<\/Key>/g,y;while((y=g.exec(d))!==null)m.push(y[1]);let f=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((y=f.exec(d))!==null)p.push({key:y[1],error:`${y[2]}: ${y[3]}`});return{deleted:m,errors:p}}async list(e,n={}){let r=await this.getCredentials(),i=new URL(this.buildUrl(e));if(i.searchParams.set("list-type","2"),n.prefix)i.searchParams.set("prefix",n.prefix);if(n.delimiter)i.searchParams.set("delimiter",n.delimiter);if(n.maxKeys)i.searchParams.set("max-keys",String(n.maxKeys));if(n.continuationToken)i.searchParams.set("continuation-token",n.continuationToken);if(n.startAfter)i.searchParams.set("start-after",n.startAfter);let s=Y({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok){let u=await a.text();throw new be(`Failed to list objects: ${u}`,a.status,e)}let c=await a.text();return Ii(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let s of i.contents)yield s;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=Y({method:"HEAD",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(a.status===404)return null;if(!a.ok){let u=await a.text();throw new be(`Failed to head object: ${u}`,a.status,e,n)}let c={};return a.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(a.headers.get("Content-Length")||0),contentType:a.headers.get("Content-Type")||"application/octet-stream",etag:(a.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(a.headers.get("Last-Modified")||0),metadata:c,storageClass:a.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:a.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,n){return await this.head(e,n)!==null}async copy(e,n,r,i,s={}){let a=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(s.metadataDirective)u["x-amz-metadata-directive"]=s.metadataDirective;if(s.contentType)u["Content-Type"]=s.contentType;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.acl)u["x-amz-acl"]=s.acl;if(s.metadata)for(let[f,h]of Object.entries(s.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=Y({method:"PUT",url:c,headers:u,...a,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let f=await m.text();throw new be(`Failed to copy object: ${f}`,m.status,r,i)}let g=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:g?g[1]:""}}async getPresignedUrl(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n);return cs({url:s,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let s=await this.getCredentials(),a=Math.max(i.partSize||Rt,Ei),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,n,i);try{let p=await this.uploadParts(e,n,m,d,c,a,s,u,i.concurrency||4,i.onProgress);return await this.completeMultipartUpload(e,n,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,n,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,n,r){let i=await this.getCredentials(),s=this.buildUrl(e,n),a=`${s}?uploads`,c={"Content-Type":r.contentType||Gn(n)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[y,f]of Object.entries(r.metadata))c[`x-amz-meta-${y.toLowerCase()}`]=f;let u=Y({method:"POST",url:a,headers:c,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let y=await d.text();throw new be(`Failed to initiate multipart upload: ${y}`,d.status,e,n)}let p=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!p)throw new be("Failed to parse upload ID from response",0,e,n);let g=s;if(d.url)try{let y=new URL(d.url);y.search="",g=y.toString()}catch{}return{uploadId:p[1],baseUrl:g}}async uploadParts(e,n,r,i,s,a,c,u,d,m){let p=[],g=s.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/a):void 0,C=new Map,P=async(v,w)=>{let D=`${r}?partNumber=${w}&uploadId=${encodeURIComponent(i)}`,x={"Content-Length":String(v.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},L=Y({method:"PUT",url:D,headers:x,...c,service:"s3",region:this.region}),B=await fetch(L.url,{method:L.method,headers:L.headers,body:v,redirect:"error"});if(!B.ok){let F=await B.text();throw new be(`Failed to upload part ${w}: ${F}`,B.status,e,n)}let O=(B.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new be(`Missing ETag for part ${w}`,B.status,e,n);return{partNumber:w,etag:O}},E=async()=>{let v=await Promise.race(C.values());C.delete(v.partNumber),p.push(v)};while(!0){let{done:v,value:w}=await g.read();if(w){let D=new Uint8Array(f.length+w.length);D.set(f),D.set(w,f.length),f=D}while(f.length>=a||v&&f.length>0){let D=f.slice(0,a);f=f.slice(a);let x=y++;if(C.size>=d)await E();if(C.set(x,P(D,x)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:x,totalParts:S||x})}if(v)break}while(C.size>0)await E();return p.sort((v,w)=>v.partNumber-w.partNumber),p}async completeMultipartUpload(e,n,r,i,s){let a=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${s.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=Y({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:d});if(!p.ok){let h=await p.text();throw new be(`Failed to complete multipart upload: ${h}`,p.status,e,n)}let y=(await p.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:y?y[1]:""}}async abortMultipartUpload(e,n,r,i){let s=await this.getCredentials(),a=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=Y({method:"DELETE",url:a,...s,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let r=[];for await(let c of this.listAll(e,{}))if(r.push(c.key),r.length>=1000)await this.deleteMany(e,r),r=[];if(r.length>0)await this.deleteMany(e,r);let i=await this.getCredentials(),s=this.buildUrl(e),a=Y({method:"DELETE",url:s,...i,service:"s3",region:this.region});await fetch(a.url,{method:a.method,headers:a.headers})}}class be extends Error{statusCode;bucket;key;constructor(e,n,r,i){super(e);this.statusCode=n;this.bucket=r;this.key=i;this.name="S3Error"}}function Ii(e){let n=[],r=[],i=/<Contents>([\s\S]*?)<\/Contents>/g,s;while((s=i.exec(e))!==null){let c=s[1];n.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let a=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((s=a.exec(e))!==null)r.push(s[1]);return{contents:n,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,n){let r=new RegExp(`<${n}>([^<]*)</${n}>`),i=e.match(r);return i?i[1]:null}function Di(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Gn(e){let n=e.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[n||""]||"application/octet-stream"}function Ni(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function Du(e){return new Da(e)}class ku{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Pn(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let n=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,i=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2462
2462
|
<InvalidationBatch>
|
|
2463
2463
|
<Paths>
|
|
2464
2464
|
<Quantity>${e.paths.length}</Quantity>
|
|
@@ -2482,7 +2482,7 @@ Stack trace:`),console.error(n.stack)}}static success(e){console.log(`✔ ${e}`)
|
|
|
2482
2482
|
`,r=e.reduce((i,s)=>{if(!i[s.service])i[s.service]=[];return i[s.service].push(s),i},{});for(let[i,s]of Object.entries(r)){n+=`${i}:
|
|
2483
2483
|
`;for(let a of s){let c=a.warning?"⚠":"✓";n+=` ${c} ${a.quotaName}: ${a.currentValue}/${a.limit} (${a.percentage.toFixed(1)}%)
|
|
2484
2484
|
`}n+=`
|
|
2485
|
-
`}return n}function pg(e){let n=[];for(let r of e)if(r.percentage>=100)n.push(`Request quota increase for ${r.service} - ${r.quotaName} (currently ${r.limit})`);else if(r.warning)n.push(`Consider requesting quota increase for ${r.service} - ${r.quotaName} (${r.percentage.toFixed(1)}% used)`);return n}import{createHash as Vn}from"node:crypto";import{existsSync as nt,mkdirSync as xi,readdirSync as _n,readFileSync as Wn,unlinkSync as
|
|
2485
|
+
`}return n}function pg(e){let n=[];for(let r of e)if(r.percentage>=100)n.push(`Request quota increase for ${r.service} - ${r.quotaName} (currently ${r.limit})`);else if(r.warning)n.push(`Consider requesting quota increase for ${r.service} - ${r.quotaName} (${r.percentage.toFixed(1)}% used)`);return n}import{createHash as Vn}from"node:crypto";import{existsSync as nt,mkdirSync as xi,readdirSync as _n,readFileSync as Wn,unlinkSync as Ke,writeFileSync as ki}from"node:fs";import{join as Et}from"node:path";class ka{cacheDir;ttl;constructor(e,n={}){this.cacheDir=e,this.ttl=n.ttl||86400000}ensureCacheDir(){if(!nt(this.cacheDir))xi(this.cacheDir,{recursive:!0})}getCachePath(e){let n=Vn("sha256").update(e).digest("hex");return Et(this.cacheDir,`${n}.json`)}get(e){let n=this.getCachePath(e);if(!nt(n))return;try{let r=Wn(n,"utf-8"),i=JSON.parse(r);if(Date.now()-i.timestamp>this.ttl){Ke(n);return}return i.value}catch{Ke(n);return}}set(e,n,r){this.ensureCacheDir();let i=this.getCachePath(e),s={value:n,timestamp:Date.now(),hash:r};ki(i,JSON.stringify(s),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!nt(this.cacheDir))return;let e=_n(this.cacheDir);for(let n of e)Ke(Et(this.cacheDir,n))}prune(){if(!nt(this.cacheDir))return;let e=_n(this.cacheDir),n=Date.now();for(let r of e){let i=Et(this.cacheDir,r);try{let s=Wn(i,"utf-8"),a=JSON.parse(s);if(n-a.timestamp>this.ttl)Ke(i)}catch{Ke(i)}}}}class Na{cache;constructor(e=ze("cache","templates")){this.cache=new ka(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,n){let r=this.hashTemplate(n);this.cache.set(`template:${e}`,n,r)}hasChanged(e,n){let r=this.cache.get(`template:${e}`);if(!r)return!0;let i=this.hashTemplate(r),s=this.hashTemplate(n);return i!==s}hashTemplate(e){return Vn("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var wt=null;function Lu(){if(!wt)wt=new Na;return wt}import{createHash as It}from"node:crypto";import{createReadStream as Mi,readdirSync as Li,statSync as rt}from"node:fs";import{join as Oi,relative as $i}from"node:path";async function Cl(e,n={}){let r=n.algorithm||"sha256",i=n.chunkSize||65536;return new Promise((s,a)=>{let c=It(r),u=Mi(e,{highWaterMark:i});u.on("data",(d)=>c.update(d)),u.on("end",()=>s(c.digest("hex"))),u.on("error",a)})}function Tl(e,n="sha256"){return It(n).update(e).digest("hex")}function mg(e,n="sha256"){return It(n).update(e).digest("hex")}async function gg(e,n={}){let r=n.ignorePatterns||["node_modules",".git","dist","build",En()],i=[];async function s(a){let c=Li(a,{withFileTypes:!0});for(let u of c){let d=Oi(a,u.name),m=$i(e,d);if(r.some((p)=>m.includes(p)))continue;if(u.isDirectory())await s(d);else if(u.isFile()){let p=rt(d),g=await Cl(d,n);i.push({path:m,hash:g,size:p.size,mtime:p.mtimeMs})}}}return await s(e),i}function fg(e){let r=[...e].sort((i,s)=>i.path.localeCompare(s.path)).map((i)=>`${i.path}:${i.hash}`).join(`
|
|
2486
2486
|
`);return Tl(r)}function hg(e){let n=rt(e);return Tl(`${e}:${n.size}:${n.mtimeMs}`)}function yg(e,n){let r=new Map(e.map((u)=>[u.path,u])),i=new Map(n.map((u)=>[u.path,u])),s=[],a=[],c=[];for(let[u,d]of i){let m=r.get(u);if(!m)s.push(d);else if(m.hash!==d.hash)a.push(d)}for(let[u,d]of r)if(!i.has(u))c.push(d);return{added:s,modified:a,deleted:c}}class Mu{cache;constructor(){this.cache=new Map}get(e){let n=rt(e),r=this.cache.get(e);if(r&&r.mtime===n.mtimeMs&&r.size===n.size)return r.hash;return}set(e,n){let r=rt(e);this.cache.set(e,{hash:n,mtime:r.mtimeMs,size:r.size})}async getOrCompute(e,n={}){let r=this.get(e);if(r)return r;let i=await Cl(e,n);return this.set(e,i),i}clear(){this.cache.clear()}}async function xa(e,n={}){let r=n.concurrency||5,i=n.stopOnError??!0,s=[],a=[],c=Date.now(),u=[...e],d=[];async function m(y,f){try{let h=await y();s[f]=h}catch(h){let S=h instanceof Error?h:Error(String(h));if(a.push(S),i)throw u.length=0,S}}let p=0;while(u.length>0||d.length>0){while(d.length<r&&u.length>0){let y=u.shift(),f=p++,h=m(y,f);d.push(h)}if(d.length>0){await Promise.race(d);for(let y=d.length-1;y>=0;y--)if(await Promise.race([d[y].then(()=>!0),Promise.resolve(!1)]))d.splice(y,1)}if(i&&a.length>0)break}let g=Date.now()-c;return{results:s.filter((y)=>y!==void 0),errors:a,duration:g}}async function bg(e,n,r={}){let i=e.map((s)=>()=>n(s));return xa(i,r)}async function Sg(e,n,r=5){let i=e.map((a,c)=>()=>n(a,c)),s=await xa(i,{concurrency:r,stopOnError:!1});if(s.errors.length>0)throw AggregateError(s.errors,"Parallel map failed");return s.results}async function vg(e,n={}){let r=n.retries||3,i=n.retryDelay||1000,s=e.map((a)=>async()=>{let c;for(let u=0;u<=r;u++)try{return await a()}catch(d){if(c=d instanceof Error?d:Error(String(d)),u<r)await Un(i*(u+1))}throw c});return xa(s,n)}async function Cg(e){let n=[];for(let r of e){let i=await r();n.push(i)}return n}function Un(e){return new Promise((n)=>setTimeout(n,e))}async function Tg(e,n,r="Operation timed out"){return Promise.race([e(),new Promise((i,s)=>setTimeout(()=>s(Error(r)),n))])}class Uu{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(e=5,n=100){this.maxConcurrent=e;this.minInterval=n}async execute(e){await this.waitForSlot(),this.running++,this.lastExecution=Date.now();try{return await e()}finally{this.running--,this.processQueue()}}waitForSlot(){if(this.running<this.maxConcurrent){let e=Date.now()-this.lastExecution;if(e>=this.minInterval)return Promise.resolve();return Un(this.minInterval-e)}return new Promise((e)=>this.queue.push(e))}processQueue(){if(this.queue.length>0&&this.running<this.maxConcurrent)this.queue.shift()()}stats(){return{running:this.running,queued:this.queue.length}}}function Bu(e,n){let r=[];for(let i=0;i<e.length;i+=n)r.push(e.slice(i,i+n));return r}async function Eg(e,n,r){let i=Bu(e,n),s=[];for(let a of i){let c=await r(a);s.push(...c)}return s}function wg(e,n){let r=[],i=[],s=[],a=[],c=e.Resources||{},u=n.Resources||{},d=new Set(Object.keys(c)),m=new Set(Object.keys(u));for(let y of m)if(!d.has(y))r.push(y);for(let y of d)if(!m.has(y))s.push(y);for(let y of m)if(d.has(y)){let f=c[y],h=u[y];if(JSON.stringify(f)!==JSON.stringify(h))i.push(y);else a.push(y)}let p=JSON.stringify(e.Parameters||{})!==JSON.stringify(n.Parameters||{}),g=JSON.stringify(e.Outputs||{})!==JSON.stringify(n.Outputs||{});return{added:r,modified:i,deleted:s,unchanged:a,parametersChanged:p,outputsChanged:g,hasChanges:r.length>0||i.length>0||s.length>0||p||g}}function Ag(e){let n=[];if(!e.hasChanges)return"No changes detected";if(e.added.length>0){n.push(`Added resources (${e.added.length}):`);for(let r of e.added)n.push(` + ${r}`)}if(e.modified.length>0){n.push(`Modified resources (${e.modified.length}):`);for(let r of e.modified)n.push(` ~ ${r}`)}if(e.deleted.length>0){n.push(`Deleted resources (${e.deleted.length}):`);for(let r of e.deleted)n.push(` - ${r}`)}if(e.parametersChanged)n.push("Parameters changed");if(e.outputsChanged)n.push("Outputs changed");return n.join(`
|
|
2487
2487
|
`)}function Rg(e,n,r){if(e.deleted.length>0)return!0;for(let i of e.modified){let s=n.Resources[i],a=r.Resources[i];if(s.Type!==a.Type)return!0;let c=_i(a.Type);for(let u of c){let d=s.Properties?.[u],m=a.Properties?.[u];if(JSON.stringify(d)!==JSON.stringify(m))return!0}}return!1}function _i(e){return{"AWS::S3::Bucket":["BucketName"],"AWS::EC2::Instance":["ImageId","InstanceType","KeyName"],"AWS::RDS::DBInstance":["DBInstanceIdentifier","Engine"],"AWS::DynamoDB::Table":["TableName","KeySchema"],"AWS::Lambda::Function":["FunctionName"],"AWS::ECS::Service":["ServiceName"],"AWS::ElasticLoadBalancingV2::LoadBalancer":["Name","Type"]}[e]||[]}function Ig(e){let n=[],r=[],i=[];n.push(...e.added);for(let s of e.modified)r.push(s);return i.push(...e.deleted),{safe:n,caution:r,dangerous:i}}function Pg(e){if(!e.hasChanges)return{strategy:"skip",reason:"No changes detected"};if(e.deleted.length>0)return{strategy:"replace",reason:"Resources will be deleted"};if(e.added.length>0&&e.modified.length===0)return{strategy:"update",reason:"Only new resources added"};return{strategy:"update",reason:"Resources will be updated"}}function Dg(e){let n=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,r=e.added.length+e.modified.length+e.deleted.length,i=n>0?r/n*100:0;return{total:n,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:i}}var Fu={$schema:"http://json-schema.org/draft-07/schema#",title:"ts-cloud Configuration",description:"Configuration schema for ts-cloud infrastructure-as-code",type:"object",required:["project"],properties:{project:{type:"object",description:"Project configuration",required:["name","slug"],properties:{name:{type:"string",description:"Human-readable project name",minLength:1},slug:{type:"string",description:"URL-safe project identifier (lowercase, alphanumeric, hyphens only)",pattern:"^[a-z0-9-]+$",minLength:1,maxLength:63},region:{type:"string",description:"Default AWS region",enum:["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"]}}},mode:{type:"string",description:"Deployment mode (server and serverless are mutually exclusive; auto-detected when omitted)",enum:["server","serverless"]},environments:{type:"object",description:"Environment-specific configurations",properties:{production:{$ref:"#/definitions/environment"},staging:{$ref:"#/definitions/environment"},development:{$ref:"#/definitions/environment"}}},infrastructure:{type:"object",description:"Infrastructure configuration",properties:{network:{$ref:"#/definitions/network"},storage:{type:"object",description:"S3 storage configuration",additionalProperties:{$ref:"#/definitions/storage"}},compute:{$ref:"#/definitions/compute"},database:{$ref:"#/definitions/database"},cache:{$ref:"#/definitions/cache"},cdn:{$ref:"#/definitions/cdn"},sftp:{$ref:"#/definitions/sftp"},functions:{type:"object",description:"Lambda functions configuration",additionalProperties:{type:"array",items:{$ref:"#/definitions/function"}}},monitoring:{$ref:"#/definitions/monitoring"},security:{$ref:"#/definitions/security"},queue:{type:"object",description:"SQS queue configuration",additionalProperties:{$ref:"#/definitions/queue"}}}}},definitions:{environment:{type:"object",properties:{domain:{type:"string",description:"Custom domain for this environment"},region:{type:"string",description:"AWS region override for this environment"},app:{type:"object",description:"Serverless application manifest (Laravel-Vapor-equivalent). Defining this opts the environment into the serverless app deploy pipeline (http/queue/cli Lambda functions, assets, build/deploy hooks).",properties:{runtime:{type:"string",description:"Lambda runtime override (usually derived from kind + runtimeVersion)"},runtimeVersion:{type:"string",description:"Node major (18/20/22 managed, 24+ custom layer) or Bun release for node/bun apps"},kind:{type:"string",enum:["node","bun","php"],description:"Application kind (drives packaging + runtime)"},entry:{type:"string",description:"Entry file exporting the request handler"},memory:{type:"number",description:"HTTP function memory in MB"},timeout:{type:"number",description:"HTTP request timeout in seconds"},gatewayVersion:{type:"number",enum:[1,2],description:"API Gateway version (2 = HTTP API, 1 = REST)"},warm:{type:"number",description:"Keep-warm / provisioned concurrency count"},lambdaInsights:{type:"object",description:"CloudWatch Lambda Insights extension configuration for zip deployments",required:["layerArn"],properties:{layerArn:{type:"string",description:"Region- and architecture-specific Lambda Insights extension layer ARN"}}},queues:{description:"Queue names (true = single default queue, false = disabled)"},scheduler:{type:"string",enum:["off","on","sub-minute"],description:"Task scheduler mode"},build:{type:"array",items:{type:"string"},description:"Commands run locally before packaging"},deploy:{type:"array",items:{type:"string"},description:"Commands run remotely after activation (e.g. migrations)"},octane:{type:"boolean",description:"Persistent application mode (Laravel Octane)"},packaging:{type:"string",enum:["zip","image"],description:"Deployment package format (zip or container image)"},phpVersion:{type:"string",description:"PHP version for the runtime layer (kind: php)"},architecture:{type:"string",enum:["x86_64","arm64"],description:"CPU architecture"}}}}},network:{type:"object",properties:{vpc:{type:"object",properties:{cidr:{type:"string",description:"VPC CIDR block",pattern:"^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$",default:"10.0.0.0/16"},availabilityZones:{type:"number",description:"Number of availability zones",minimum:1,maximum:3,default:2},natGateways:{type:"number",description:"Number of NAT gateways (0 for no NAT, saves cost)",minimum:0,maximum:3,default:1}}}}},storage:{type:"object",properties:{public:{type:"boolean",description:"Allow public access",default:!1},versioning:{type:"boolean",description:"Enable versioning",default:!1},encryption:{type:"boolean",description:"Enable server-side encryption",default:!0},website:{type:"boolean",description:"Enable static website hosting",default:!1},cors:{type:"object",description:"CORS configuration",properties:{allowedOrigins:{type:"array",items:{type:"string"}},allowedMethods:{type:"array",items:{type:"string",enum:["GET","PUT","POST","DELETE","HEAD"]}}}}}},compute:{type:"object",properties:{server:{type:"object",description:"EC2 server configuration",properties:{instanceType:{type:"string",description:"EC2 instance type",enum:["t3.micro","t3.small","t3.medium","t3.large","t3.xlarge","t3.2xlarge"]},autoScaling:{type:"object",properties:{min:{type:"number",minimum:1},max:{type:"number",minimum:1},desired:{type:"number",minimum:1}}}}},fargate:{type:"object",description:"ECS Fargate configuration",properties:{cpu:{type:"number",description:"CPU units (256, 512, 1024, 2048, 4096)",enum:[256,512,1024,2048,4096]},memory:{type:"number",description:"Memory in MB"},desiredCount:{type:"number",description:"Desired number of tasks",minimum:1}}}}},database:{type:"object",properties:{postgres:{type:"object",properties:{instanceClass:{type:"string",description:"RDS instance class",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"postgres"},version:{type:"string",description:"PostgreSQL version"},multiAZ:{type:"boolean",description:"Enable Multi-AZ deployment",default:!1},backupRetentionDays:{type:"number",description:"Backup retention period in days",minimum:0,maximum:35,default:7}}},mysql:{type:"object",properties:{instanceClass:{type:"string",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"mysql"},version:{type:"string"},multiAZ:{type:"boolean",default:!1},backupRetentionDays:{type:"number",minimum:0,maximum:35,default:7}}},dynamodb:{type:"object",properties:{tables:{type:"array",items:{type:"object",required:["name","partitionKey"],properties:{name:{type:"string"},partitionKey:{type:"string"},sortKey:{type:"string"},billingMode:{type:"string",enum:["PAY_PER_REQUEST","PROVISIONED"],default:"PAY_PER_REQUEST"}}}}}}}},cache:{type:"object",properties:{redis:{type:"object",properties:{nodeType:{type:"string",description:"ElastiCache node type",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1},engineVersion:{type:"string",description:"Redis engine version"}}},memcached:{type:"object",properties:{nodeType:{type:"string",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1}}}}},cdn:{type:"object",properties:{enabled:{type:"boolean",default:!0},originShield:{type:"boolean",description:"Enable CloudFront Origin Shield",default:!1},originShieldRegion:{type:"string",description:"AWS region used by CloudFront Origin Shield"},compress:{type:"boolean",description:"Enable automatic compression",default:!0},http3:{type:"boolean",description:"Enable HTTP/3 support",default:!0},customDomain:{type:"object",properties:{domain:{type:"string"},certificateArn:{type:"string"}}},cachePolicy:{type:"object",properties:{minTTL:{type:"number",minimum:0},defaultTTL:{type:"number",minimum:0},maxTTL:{type:"number",minimum:0}}}}},sftp:{type:"object",required:["bucket","users"],properties:{bucket:{type:"string",description:"S3 bucket backing the SFTP server"},endpointType:{type:"string",enum:["PUBLIC","VPC"],default:"PUBLIC"},endpointDetails:{type:"object",required:["vpcId","subnetIds"],properties:{vpcId:{type:"string"},subnetIds:{type:"array",items:{type:"string"},minItems:1},securityGroupIds:{type:"array",items:{type:"string"}},addressAllocationIds:{type:"array",items:{type:"string"}}}},securityPolicyName:{type:"string"},logging:{type:"boolean",default:!0},users:{type:"object",additionalProperties:{type:"object",required:["sshPublicKeys"],properties:{sshPublicKeys:{type:"array",items:{type:"string"},minItems:1},homeDirectory:{type:"string"},roleArn:{type:"string"}}}}}},function:{type:"object",required:["name","runtime"],properties:{name:{type:"string"},runtime:{type:"string",enum:["nodejs18.x","nodejs20.x","python3.10","python3.11","python3.12"]},handler:{type:"string",default:"index.handler"},timeout:{type:"number",minimum:1,maximum:900,default:30},memory:{type:"number",minimum:128,maximum:10240,default:1024}}},monitoring:{type:"object",properties:{alarms:{type:"array",items:{type:"object",required:["metric","threshold"],properties:{metric:{type:"string"},threshold:{type:"number"},evaluationPeriods:{type:"number",minimum:1,default:2}}}},dashboard:{type:"object",properties:{name:{type:"string"},widgets:{type:"array"}}}}},security:{type:"object",properties:{waf:{type:"boolean",description:"Enable AWS WAF",default:!1},certificates:{type:"array",items:{type:"object",required:["domain"],properties:{domain:{type:"string"},subdomains:{type:"array",items:{type:"string"}}}}}}},queue:{type:"object",properties:{fifo:{type:"boolean",default:!1},deadLetterQueue:{type:"boolean",default:!0},visibilityTimeout:{type:"number",minimum:0,maximum:43200,default:30},messageRetentionPeriod:{type:"number",minimum:60,maximum:1209600,default:345600}}}}};function kg(e){let n=[];if(!e.project)n.push("Missing required field: project");else{if(!e.project.name)n.push("Missing required field: project.name");if(!e.project.slug)n.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))n.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let r=["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"];if(e.project?.region&&!r.includes(e.project.region))n.push(`Invalid region: ${e.project.region}. Must be one of: ${r.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))n.push("Invalid mode: must be one of server or serverless");return{valid:n.length===0,errors:n}}var El={enabled:process.env.TS_CLOUD_LOCAL==="true"||!1,localstackEndpoint:process.env.LOCALSTACK_ENDPOINT||"http://localhost:4566",postgresUrl:process.env.POSTGRES_URL||"postgresql://tscloud:tscloud@localhost:5432/tscloud",redisUrl:process.env.REDIS_URL||"redis://localhost:6379",dynamodbEndpoint:process.env.DYNAMODB_ENDPOINT||"http://localhost:8000",s3Endpoint:process.env.S3_ENDPOINT||"http://localhost:9000",emailEndpoint:process.env.EMAIL_ENDPOINT||"smtp://localhost:1025",awsRegion:process.env.AWS_REGION||"us-east-1",awsAccessKeyId:process.env.AWS_ACCESS_KEY_ID||"test",awsSecretAccessKey:process.env.AWS_SECRET_ACCESS_KEY||"test"};function _a(){return El}function Ng(){return El.enabled}function xg(e){let n=_a();if(!n.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return n.dynamodbEndpoint;case"s3":return n.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return n.localstackEndpoint;default:return n.localstackEndpoint}}function _g(){let e=_a();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Og(){let e=_a();if(!e.enabled)return{};return{AWS_ACCESS_KEY_ID:e.awsAccessKeyId,AWS_SECRET_ACCESS_KEY:e.awsSecretAccessKey,AWS_REGION:e.awsRegion,AWS_ENDPOINT_URL:e.localstackEndpoint,LOCALSTACK_ENDPOINT:e.localstackEndpoint,TS_CLOUD_LOCAL:"true"}}class wl{stacks=new Map;stackEvents=new Map;async createStack(e){let n=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:n,StackName:e.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:e.TemplateBody,Parameters:e.Parameters||[]}),this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let r=this.stacks.get(e.StackName);if(r)r.StackStatus="CREATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:n}}async updateStack(e){let n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);return n.StackStatus="UPDATE_IN_PROGRESS",n.TemplateBody=e.TemplateBody||n.TemplateBody,this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_IN_PROGRESS"}),setTimeout(()=>{n.StackStatus="UPDATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_COMPLETE"})},100),{StackId:n.StackId}}async deleteStack(e){let n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);n.StackStatus="DELETE_IN_PROGRESS",this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_IN_PROGRESS"}),setTimeout(()=>{this.stacks.delete(e.StackName),this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_COMPLETE"})},100)}async describeStacks(e){if(e.StackName){let n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[n]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,n){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(n)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class Al{buckets=new Map;async createBucket(e){return this.buckets.set(e.Bucket,new Map),{Location:`/${e.Bucket}`}}async deleteBucket(e){this.buckets.delete(e.Bucket)}async putObject(e){let n=this.buckets.get(e.Bucket);if(!n)n=new Map,this.buckets.set(e.Bucket,n);return n.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let n=this.buckets.get(e.Bucket);if(!n)throw Error(`Bucket ${e.Bucket} does not exist`);let r=n.get(e.Key);if(!r)throw Error(`Object ${e.Key} does not exist`);return{Body:r,ContentLength:r.length}}async deleteObject(e){let n=this.buckets.get(e.Bucket);if(n)n.delete(e.Key)}async listObjects(e){let n=this.buckets.get(e.Bucket);if(!n)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(n.keys()).map((i)=>({Key:i,Size:n.get(i).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class Rl{tables=new Map;data=new Map;async createTable(e){return this.tables.set(e.TableName,{TableName:e.TableName,KeySchema:e.KeySchema,AttributeDefinitions:e.AttributeDefinitions,TableStatus:"ACTIVE",CreationDateTime:new Date().toISOString()}),this.data.set(e.TableName,new Map),{TableDescription:this.tables.get(e.TableName)}}async deleteTable(e){this.tables.delete(e.TableName),this.data.delete(e.TableName)}async putItem(e){let n=this.data.get(e.TableName);if(!n)n=new Map,this.data.set(e.TableName,n);let r=JSON.stringify(e.Item);n.set(r,e.Item)}async getItem(e){let n=this.data.get(e.TableName);if(!n)return{};let r=JSON.stringify(e.Key),i=n.get(r);return i?{Item:i}:{}}async deleteItem(e){let n=this.data.get(e.TableName);if(n){let r=JSON.stringify(e.Key);n.delete(r)}}async scan(e){let n=this.data.get(e.TableName);if(!n)return{Items:[]};return{Items:Array.from(n.values())}}reset(){this.tables.clear(),this.data.clear()}}function $g(e){return{cloudformation:new wl,s3:new Al,dynamodb:new Rl}}class Oa{environments=new Map;async createPreviewEnvironment(e){let{branch:n,pr:r,commitSha:i,ttl:s=24,baseConfig:a,region:c="us-east-1"}=e,u=this.generatePreviewId(n,r,i),d=this.generatePreviewName(n,r),m=`preview-${d}`,p=new Date,g=new Date(p.getTime()+s*60*60*1000),y={id:u,name:d,branch:n,pr:r,commitSha:i,createdAt:p,expiresAt:g,status:"creating",stackName:m,region:c,resources:[]};this.environments.set(u,y);try{let f=this.createPreviewConfig(a,d);return y.status="active",y.url=`https://${d}.preview.example.com`,y}catch(f){throw y.status="failed",f}}async destroyPreviewEnvironment(e){let n=this.environments.get(e);if(!n)throw Error(`Preview environment ${e} not found`);n.status="destroying";try{n.status="destroyed",this.environments.delete(e)}catch(r){throw Error(`Failed to destroy preview environment: ${r}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((n)=>n.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((n)=>n.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:n,keepCount:r,dryRun:i=!1}=e,s=[],a=[],c=new Date,u=this.listPreviewEnvironments().sort((d,m)=>m.createdAt.getTime()-d.createdAt.getTime());for(let d=0;d<u.length;d++){let m=u[d];if(m.status!=="active")continue;let p=!1;if(m.expiresAt<c)p=!0;if(n){if((c.getTime()-m.createdAt.getTime())/3600000>n)p=!0}if(r&&d>=r)p=!0;if(p)if(i)s.push(m.id);else try{await this.destroyPreviewEnvironment(m.id),s.push(m.id)}catch(g){a.push(m.id)}}return{destroyed:s,failed:a}}async updatePreviewEnvironment(e,n){let r=this.environments.get(e);if(!r)throw Error(`Preview environment ${e} not found`);r.commitSha=n,r.status="creating";try{return r.status="active",r}catch(i){throw r.status="failed",i}}async getPreviewEnvironmentsCost(){let e={},n=0;for(let r of this.environments.values())e[r.id]=0,n+=0;return{total:n,byEnvironment:e}}generatePreviewId(e,n,r){let i=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),s=r?.substring(0,7)||Date.now().toString();return n?`pr-${n}-${s}`:`${i}-${s}`}generatePreviewName(e,n){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return n?`pr-${n}`:r}createPreviewConfig(e,n){return{...e,project:{...e.project,name:`${e.project.name} Preview (${n})`,slug:`${e.project.slug}-preview-${n}`}}}}var ju=new Oa;function Vu(e={}){let{workflowName:n="Preview Environment",trigger:r="pull_request",branches:i=["main","develop"],awsRegion:s="us-east-1",awsRole:a,configFile:c="cloud.config.ts",ttl:u=24}=e;return`name: ${n}
|
|
2488
2488
|
|
|
@@ -2736,8 +2736,8 @@ ${n.map((r)=>` • ${r}`).join(`
|
|
|
2736
2736
|
`))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((n)=>n.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class Qu{variables=new Map;workingDirectory=process.cwd();set(e,n){this.variables.set(e,n)}get(e){return this.variables.get(e)}has(e){return this.variables.has(e)}delete(e){this.variables.delete(e)}getAll(){return Object.fromEntries(this.variables)}clear(){this.variables.clear()}setWorkingDirectory(e){this.workingDirectory=e}getWorkingDirectory(){return this.workingDirectory}}class Yu{command={};name(e){return this.command.name=e,this}description(e){return this.command.description=e,this}aliases(...e){return this.command.aliases=e,this}handler(e){return this.command.handler=e,this}autocomplete(e){return this.command.autocomplete=e,this}build(){if(!this.command.name||!this.command.description||!this.command.handler)throw Error("Command must have name, description, and handler");return this.command}}class Zu{entries=[];maxSize;persistFile;trackOutput;constructor(e={}){this.maxSize=e.maxSize||1000,this.persistFile=e.persistFile,this.trackOutput=e.trackOutput||!1}add(e){if(this.entries.push({...e,timestamp:new Date}),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}getAll(){return[...this.entries]}getRecent(e=10){return this.entries.slice(-e)}search(e){let n=e.toLowerCase();return this.entries.filter((r)=>r.command.toLowerCase().includes(n))}searchByDate(e,n){return this.entries.filter((r)=>r.timestamp>=e&&r.timestamp<=n)}getSuccessful(){return this.entries.filter((e)=>e.success)}getFailed(){return this.entries.filter((e)=>!e.success)}getMostUsed(e=10){let n=new Map;for(let r of this.entries){let i=r.command.split(" ")[0];n.set(i,(n.get(i)||0)+1)}return Array.from(n.entries()).map(([r,i])=>({command:r,count:i})).sort((r,i)=>i.count-r.count).slice(0,e)}getStats(){let e=this.entries.length,n=this.entries.filter((u)=>u.success).length,r=this.entries.filter((u)=>!u.success).length,i=this.entries.filter((u)=>u.duration!==void 0),s=i.length>0?i.reduce((u,d)=>u+(d.duration||0),0)/i.length:0,a=this.getMostUsed(1),c=a.length>0?a[0].command:"N/A";return{total:e,successful:n,failed:r,averageDuration:s,mostUsed:c}}clear(){this.entries=[]}getByIndex(e){if(e<0||e>=this.entries.length)return;return this.entries[e]}removeByIndex(e){if(e>=0&&e<this.entries.length)this.entries.splice(e,1)}async save(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),n=JSON.stringify(this.entries,null,2);await e.writeFile(this.persistFile,n,"utf-8")}catch(e){throw Error(`Failed to save history: ${e}`)}}async load(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),n=await e.readFile(this.persistFile,"utf-8"),r=JSON.parse(n);this.entries=r.map((i)=>({...i,timestamp:new Date(i.timestamp)}))}catch{this.entries=[]}}exportJSON(){return JSON.stringify(this.entries,null,2)}exportCSV(){return["Timestamp,Command,Success,Duration",...this.entries.map((r)=>[r.timestamp.toISOString(),`"${r.command.replace(/"/g,'""')}"`,r.success,r.duration||""].join(","))].join(`
|
|
2737
2737
|
`)}importJSON(e){let r=JSON.parse(e).map((i)=>({...i,timestamp:new Date(i.timestamp)}));if(this.entries.push(...r),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let n of this.entries){let r=n.timestamp.toISOString().split("T")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(n)}return e}groupByCommand(){let e=new Map;for(let n of this.entries){let r=n.command.split(" ")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(n)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,n=5){let r=e.toLowerCase(),i=this.entries.filter((s)=>s.command.toLowerCase().startsWith(r)).map((s)=>s.command);return[...new Set(i)].slice(0,n)}analyzePatterns(){let e=new Map,n=new Map;for(let i of this.entries){let s=i.timestamp.getHours(),a=i.timestamp.getDay();e.set(s,(e.get(s)||0)+1),n.set(a,(n.get(a)||0)+1)}let r=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:n,successRate:r}}}function Yg(e,n={}){let{maxWidth:r=100}=n;if(e.length===0)return"No command history";let i=[];for(let s=0;s<e.length;s++){let a=e[s],c=(s+1).toString().padStart(4),u=a.timestamp.toLocaleString(),d=a.success?"✓":"✗",m=a.command;if(m.length>r-30)m=m.substring(0,r-33)+"...";let p=`${c} ${u} ${d} ${m}`;if(a.duration)p+=` (${a.duration}ms)`;i.push(p)}return i.join(`
|
|
2738
2738
|
`)}function Zg(e){let n=[];return n.push("Command History Statistics"),n.push("─".repeat(30)),n.push(`Total commands: ${e.total}`),n.push(`Successful: ${e.successful}`),n.push(`Failed: ${e.failed}`),n.push(`Success rate: ${(e.successful/e.total*100).toFixed(1)}%`),n.push(`Average duration: ${e.averageDuration.toFixed(0)}ms`),n.push(`Most used: ${e.mostUsed}`),n.join(`
|
|
2739
|
-
`)}class Pl{deployments=new Map;async deploy(e,n){let r=this.generateDeploymentId(),i={id:r,regions:n.regions.map((s)=>({region:s.code,stackName:this.getStackName(e,s.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,i);try{let s=n.regions.find((c)=>c.isPrimary)||n.regions[0];await this.deployToRegion(e,s,i);let a=n.regions.filter((c)=>c.code!==s.code);if(await Promise.all(a.map((c)=>this.deployToRegion(e,c,i))),n.globalResources)await this.deployGlobalResources(i,n);if(n.replication)await this.setupReplication(i,n);if(n.failover?.enabled)await this.setupFailover(i,n);return i.status="deployed",i.endTime=new Date,i}catch(s){throw i.status="failed",i.endTime=new Date,s}}async deployToRegion(e,n,r){let i=r.regions.find((s)=>s.region===n.code);if(!i)throw Error(`Region deployment not found: ${n.code}`);i.status="deploying",i.startTime=new Date;try{let s=this.createRegionConfig(e,n);await this.deployStack(i.stackName,s,n.code),i.status="deployed",i.endTime=new Date,i.outputs={stackId:`arn:aws:cloudformation:${n.code}:123456789012:stack/${i.stackName}/guid`,endpoint:`https://${i.stackName}.${n.code}.example.com`}}catch(s){throw i.status="failed",i.endTime=new Date,i.error=s instanceof Error?s.message:String(s),s}}async deployGlobalResources(e,n){let r={};if(n.globalResources?.route53)r.route53=await this.deployRoute53(e,n);if(n.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,n);if(n.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,n){let r=[],i=[];for(let s of e.regions){if(s.status!=="deployed")continue;let a={id:`health-${s.region}`,endpoint:s.outputs?.endpoint,path:n.failover?.healthCheckPath||"/health",region:s.region};r.push(a);let c={name:"example.com",type:"A",region:s.region,setIdentifier:s.region,healthCheckId:a.id,resourceRecords:[s.outputs?.endpoint]};i.push(c)}return{healthChecks:r,recordSets:i,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,n){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((i)=>i.status==="deployed").map((i,s)=>{let a=n.regions[s];return{id:`origin-${i.region}`,domainName:i.outputs?.endpoint,weight:a?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,n){if(n.replication?.s3)await this.setupS3Replication(e);if(n.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(n.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let n=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<n.length-1;r++){let i=n[r],s=n[r+1];console.log(`Setting up S3 replication: ${i.region} -> ${s.region}`)}}async setupDynamoDBReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${n.join(", ")}`)}async setupSecretsReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${n.join(", ")}`)}async setupFailover(e,n){let r=e.regions.find((s,a)=>n.regions[a]?.isPrimary)||e.regions[0],i=e.regions.filter((s)=>s.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${i.map((s)=>s.region).join(", ")}`)}async destroy(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);n.status="rolling-back";try{if(n.globalResources)await this.destroyGlobalResources(n.globalResources);await Promise.all(n.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw n.status="failed",r}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(n){throw e.status="failed",e.error=n instanceof Error?n.message:String(n),n}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,n){return`${e.project.slug}-${n}`}createRegionConfig(e,n){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,n,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var ef=new Pl;class Dl{references=[];exports=new Map;addExport(e){let n=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,n){let r=this.exports.get(e);if(!r)return;return r.find((s)=>s.exportName===n)?.value}createReference(e,n,r,i){let s=`/cross-region/${e}/${r}/${i}`;return this.references.push({sourceRegion:e,targetRegion:n,resourceType:r,resourceId:i,value:s}),s}async resolveReference(e,n){let r=this.references.find((i)=>i.targetRegion===e&&i.value===n);if(!r)throw Error(`Reference not found: ${n}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((n)=>n.sourceRegion===e||n.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class kl{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((n)=>n.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class Nl{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let n=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!n)return;return n.primary===e?n.secondary:n.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,n){return this.pairs.some((r)=>r.primary===e&&r.secondary===n||r.primary===n&&r.secondary===e)}clear(){this.pairs=[]}}class xl{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,n){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===n)}getDependents(e,n){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===n)}hasDependencies(e,n){return this.getDependencies(e,n).length>0}getDeploymentOrder(e){let n=new Set,r=[],i=(s)=>{let a=`${s.name}:${s.region}`;if(n.has(a))return;n.add(a);let c=this.getDependencies(s.name,s.region);for(let u of c)i({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(s)};for(let s of e)i(s);return r}detectCircularDependencies(){let e=new Set,n=new Set,r=(i,s)=>{let a=`${i}:${s}`;if(n.has(a))return!0;if(e.has(a))return!1;e.add(a),n.add(a);let c=this.getDependencies(i,s);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return n.delete(a),!1};for(let i of this.dependencies)if(r(i.dependentStack,i.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var tf=new Dl,rf=new kl,nf=new Nl,of=new xl;var at=[{code:"us-east-1",name:"US East (N. Virginia)",location:"Virginia, USA",launchYear:2006,availabilityZones:6,localZones:16,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO","FedRAMP"]},{code:"us-east-2",name:"US East (Ohio)",location:"Ohio, USA",launchYear:2016,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-1",name:"US West (N. California)",location:"California, USA",launchYear:2009,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-2",name:"US West (Oregon)",location:"Oregon, USA",launchYear:2011,availabilityZones:4,localZones:2,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"eu-west-1",name:"Europe (Ireland)",location:"Dublin, Ireland",launchYear:2007,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1.05},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"eu-central-1",name:"Europe (Frankfurt)",location:"Frankfurt, Germany",launchYear:2014,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"ap-southeast-1",name:"Asia Pacific (Singapore)",location:"Singapore",launchYear:2010,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.12},compliance:["PCI-DSS","SOC","ISO","MTCS"]},{code:"ap-northeast-1",name:"Asia Pacific (Tokyo)",location:"Tokyo, Japan",launchYear:2011,availabilityZones:4,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.15},compliance:["PCI-DSS","SOC","ISO"]}];function qi(e){return at.find((n)=>n.code===e)}function sf(){return at}function af(e){let n=e.toLowerCase();return at.filter((r)=>r.location.toLowerCase().includes(n))}function cf(e){return at.filter((n)=>n.compliance.includes(e))}function lf(e){return at.filter((n)=>n.pricing.tier===e)}function df(e){return at.some((n)=>n.code===e)}function uf(e){if(e.continent==="North America")return qi("us-east-1");if(e.continent==="Europe")return qi("eu-west-1");if(e.continent==="Asia")return qi("ap-southeast-1");return qi("us-east-1")}function pf(e){let n=[...at];if(e.compliance)n=n.filter((r)=>e.compliance.every((i)=>r.compliance.includes(i)));if(e.requiredServices)n=n.filter((r)=>e.requiredServices.every((i)=>r.services[i]));if(e.pricingSensitive)n.sort((r,i)=>r.pricing.multiplier-i.pricing.multiplier);return n.slice(0,5)}function mf(e){let n=qi(e);if(!n)throw Error(`Invalid region: ${e}`);let r=[];for(let i of at){if(i.code===e)continue;let s=ls(n,i),a=us(n,i);r.push({primary:n,secondary:i,distance:s,sameContinent:a})}return r.sort((i,s)=>{if(i.sameContinent!==s.sameContinent)return i.sameContinent?1:-1;return i.distance-s.distance}),r.slice(0,3)}function ls(e,n){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},i=Qe(e.location),s=Qe(n.location);return Math.abs((r[i]||0)-(r[s]||0))}function us(e,n){return Qe(e.location)===Qe(n.location)}function Qe(e){if(e.includes("USA")||e.includes("Canada"))return"North America";if(e.includes("Europe")||e.includes("Ireland")||e.includes("Germany"))return"Europe";if(e.includes("Asia")||e.includes("Singapore")||e.includes("Japan"))return"Asia";if(e.includes("Brazil"))return"South America";if(e.includes("Australia"))return"Oceania";return"Unknown"}function ep(e){return`${e.name} (${e.code})`}function gf(e){return e.map((n)=>ep(n)).join(`
|
|
2740
|
-
`)}function ff(){let e={total:at.length,byContinent:{},byPricingTier:{}};for(let n of at){let r=Qe(n.location);e.byContinent[r]=(e.byContinent[r]||0)+1,e.byPricingTier[n.pricing.tier]=(e.byPricingTier[n.pricing.tier]||0)+1}return e}class _l{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((n)=>n.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((n)=>n.role===e)}createCrossAccountRole(e,n,r,i,s){let a={roleArn:`arn:aws:iam::${n}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:n,permissions:i,externalId:s?.externalId,sessionDuration:s?.sessionDuration||3600};return this.crossAccountRoles.push(a),a}getAssumeRolePolicyDocument(e,n){let r={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(n)r.Statement[0].Condition={StringEquals:{"sts:ExternalId":n}};return r}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,n,r){this.accountMappings.push({environment:e,accountId:n,region:r})}getAccountForEnvironment(e){return this.accountMappings.find((n)=>n.environment===e)}async assumeRole(e,n,r){return console.log(`Assuming role: ${e} with session: ${n}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let n=this.accounts.get(e);if(!n)throw Error(`Account not found: ${e}`);if(n.assumeRoleArn){let r=await this.assumeRole(n.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((n)=>n.sourceAccountId===e||n.targetAccountId===e)}async validateAccountAccess(e){try{let n=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let r of this.accounts.values())e[r.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((r,i)=>r+i,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Ol{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,n){let r={id:`ou-${Date.now()}`,name:e,parentId:n,accounts:[]};return this.organizationalUnits.set(r.id,r),r}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);if(!r.accounts.includes(n))r.accounts.push(n)}removeAccountFromOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);r.accounts=r.accounts.filter((i)=>i!==n)}getAccountsInOU(e){let n=this.organizationalUnits.get(e);if(!n)return[];return[...n.accounts]}applyServiceControlPolicy(e,n){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:n}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var hf=new _l,yf=new Ol;var tp={basic:{name:"Basic (3 Accounts)",description:"Simple structure for small teams",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account for AWS Organizations"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production workloads"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development and testing"}],organizationalUnits:[{name:"root"},{name:"workloads",parent:"root"}]},standard:{name:"Standard (5 Accounts)",description:"Recommended for most organizations",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"security",email:"aws+security@example.com",role:"security",ou:"security",description:"Security tooling and audit logs"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared services (CI/CD, monitoring)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production environment"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"workloads",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root"},{name:"infrastructure",parent:"root"},{name:"workloads",parent:"root"}]},enterprise:{name:"Enterprise (7+ Accounts)",description:"For large organizations with strict compliance requirements",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"audit",email:"aws+audit@example.com",role:"security",ou:"security",description:"Audit and compliance"},{alias:"log-archive",email:"aws+logs@example.com",role:"security",ou:"security",description:"Centralized log storage"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared infrastructure"},{alias:"network",email:"aws+network@example.com",role:"shared-services",ou:"infrastructure",description:"Network infrastructure (Transit Gateway)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"production-ou",description:"Production workloads"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"non-production-ou",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"non-production-ou",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root",policies:["deny-root-access"]},{name:"infrastructure",parent:"root"},{name:"production-ou",parent:"root",policies:["require-mfa"]},{name:"non-production-ou",parent:"root"}]}},bf={denyRootAccess:{name:"Deny Root User Access",description:"Prevent root user from performing any actions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyRootUser",Effect:"Deny",Action:"*",Resource:"*",Condition:{StringLike:{"aws:PrincipalArn":"arn:aws:iam::*:root"}}}]}},requireMFA:{name:"Require MFA for All Actions",description:"Require MFA for console and API access",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"RequireMFA",Effect:"Deny",Action:"*",Resource:"*",Condition:{BoolIfExists:{"aws:MultiFactorAuthPresent":"false"}}}]}},denyRegions:{name:"Deny Access to Non-Approved Regions",description:"Restrict operations to specific regions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyNonApprovedRegions",Effect:"Deny",NotAction:["iam:*","organizations:*","route53:*","cloudfront:*","support:*","s3:*"],Resource:"*",Condition:{StringNotEquals:{"aws:RequestedRegion":["us-east-1","us-west-2"]}}}]}},preventLeaving:{name:"Prevent Leaving Organization",description:"Prevent accounts from leaving the organization",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"PreventLeaving",Effect:"Deny",Action:"organizations:LeaveOrganization",Resource:"*"}]}},denyS3Unencrypted:{name:"Deny Unencrypted S3 Uploads",description:"Require encryption for all S3 uploads",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyUnencryptedS3Uploads",Effect:"Deny",Action:"s3:PutObject",Resource:"*",Condition:{StringNotEquals:{"s3:x-amz-server-side-encryption":["AES256","aws:kms"]}}}]}}},Sf={deploymentRole:{name:"CrossAccountDeploymentRole",description:"Role for deploying infrastructure from CI/CD",permissions:["cloudformation:*","s3:*","ec2:*","ecs:*","lambda:*","iam:GetRole","iam:PassRole","logs:*","events:*"]},readOnlyRole:{name:"CrossAccountReadOnlyRole",description:"Read-only access for monitoring and auditing",permissions:["cloudformation:Describe*","cloudformation:List*","ec2:Describe*","ecs:Describe*","lambda:Get*","lambda:List*","s3:Get*","s3:List*","logs:Get*","logs:Describe*"]},securityAuditRole:{name:"CrossAccountSecurityAuditRole",description:"Security audit and compliance checks",permissions:["iam:Get*","iam:List*","iam:Generate*","access-analyzer:*","guardduty:Get*","guardduty:List*","securityhub:Get*","securityhub:List*","config:Describe*","config:Get*","config:List*"]},breakGlassRole:{name:"CrossAccountBreakGlassRole",description:"Emergency access role (use with caution)",permissions:["*"]}};function vf(e){return tp[e]}function Cf(e,n){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...n&&{ManagedPolicyArns:n},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Tf(e){let n=[],r=[],i=e.accounts.filter((d)=>d.role==="management");if(i.length===0)n.push("No management account defined");if(i.length>1)n.push("Multiple management accounts defined");let s=e.accounts.map((d)=>d.email),a=s.filter((d,m)=>s.indexOf(d)!==m);if(a.length>0)n.push(`Duplicate email addresses: ${a.join(", ")}`);let c=e.accounts.map((d)=>d.alias),u=c.filter((d,m)=>c.indexOf(d)!==m);if(u.length>0)n.push(`Duplicate aliases: ${u.join(", ")}`);if(!e.accounts.some((d)=>d.role==="security"))r.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)r.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((d)=>d.role==="production"))r.push("No production account defined");return{valid:n.length===0,errors:n,warnings:r}}function Ef(e){let n=[];if(n.push(`${e.name}`),n.push("─".repeat(e.name.length)),n.push(e.description),n.push(""),e.organizationalUnits){n.push("Organizational Units:");for(let r of e.organizationalUnits){let i=r.parent?" └─ ":" ";n.push(`${i}${r.name}`)}n.push("")}n.push("Accounts:");for(let r of e.accounts)n.push(` ${r.alias.padEnd(20)} ${r.role.padEnd(15)} ${r.email}`),n.push(` ${"".padEnd(20)} ${r.description}`),n.push("");return n.join(`
|
|
2739
|
+
`)}class Pl{deployments=new Map;async deploy(e,n){let r=this.generateDeploymentId(),i={id:r,regions:n.regions.map((s)=>({region:s.code,stackName:this.getStackName(e,s.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,i);try{let s=n.regions.find((c)=>c.isPrimary)||n.regions[0];await this.deployToRegion(e,s,i);let a=n.regions.filter((c)=>c.code!==s.code);if(await Promise.all(a.map((c)=>this.deployToRegion(e,c,i))),n.globalResources)await this.deployGlobalResources(i,n);if(n.replication)await this.setupReplication(i,n);if(n.failover?.enabled)await this.setupFailover(i,n);return i.status="deployed",i.endTime=new Date,i}catch(s){throw i.status="failed",i.endTime=new Date,s}}async deployToRegion(e,n,r){let i=r.regions.find((s)=>s.region===n.code);if(!i)throw Error(`Region deployment not found: ${n.code}`);i.status="deploying",i.startTime=new Date;try{let s=this.createRegionConfig(e,n);await this.deployStack(i.stackName,s,n.code),i.status="deployed",i.endTime=new Date,i.outputs={stackId:`arn:aws:cloudformation:${n.code}:123456789012:stack/${i.stackName}/guid`,endpoint:`https://${i.stackName}.${n.code}.example.com`}}catch(s){throw i.status="failed",i.endTime=new Date,i.error=s instanceof Error?s.message:String(s),s}}async deployGlobalResources(e,n){let r={};if(n.globalResources?.route53)r.route53=await this.deployRoute53(e,n);if(n.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,n);if(n.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,n){let r=[],i=[];for(let s of e.regions){if(s.status!=="deployed")continue;let a={id:`health-${s.region}`,endpoint:s.outputs?.endpoint,path:n.failover?.healthCheckPath||"/health",region:s.region};r.push(a);let c={name:"example.com",type:"A",region:s.region,setIdentifier:s.region,healthCheckId:a.id,resourceRecords:[s.outputs?.endpoint]};i.push(c)}return{healthChecks:r,recordSets:i,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,n){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((i)=>i.status==="deployed").map((i,s)=>{let a=n.regions[s];return{id:`origin-${i.region}`,domainName:i.outputs?.endpoint,weight:a?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,n){if(n.replication?.s3)await this.setupS3Replication(e);if(n.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(n.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let n=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<n.length-1;r++){let i=n[r],s=n[r+1];console.log(`Setting up S3 replication: ${i.region} -> ${s.region}`)}}async setupDynamoDBReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${n.join(", ")}`)}async setupSecretsReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${n.join(", ")}`)}async setupFailover(e,n){let r=e.regions.find((s,a)=>n.regions[a]?.isPrimary)||e.regions[0],i=e.regions.filter((s)=>s.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${i.map((s)=>s.region).join(", ")}`)}async destroy(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);n.status="rolling-back";try{if(n.globalResources)await this.destroyGlobalResources(n.globalResources);await Promise.all(n.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw n.status="failed",r}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(n){throw e.status="failed",e.error=n instanceof Error?n.message:String(n),n}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,n){return`${e.project.slug}-${n}`}createRegionConfig(e,n){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,n,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var ef=new Pl;class Dl{references=[];exports=new Map;addExport(e){let n=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,n){let r=this.exports.get(e);if(!r)return;return r.find((s)=>s.exportName===n)?.value}createReference(e,n,r,i){let s=`/cross-region/${e}/${r}/${i}`;return this.references.push({sourceRegion:e,targetRegion:n,resourceType:r,resourceId:i,value:s}),s}async resolveReference(e,n){let r=this.references.find((i)=>i.targetRegion===e&&i.value===n);if(!r)throw Error(`Reference not found: ${n}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((n)=>n.sourceRegion===e||n.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class kl{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((n)=>n.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class Nl{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let n=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!n)return;return n.primary===e?n.secondary:n.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,n){return this.pairs.some((r)=>r.primary===e&&r.secondary===n||r.primary===n&&r.secondary===e)}clear(){this.pairs=[]}}class xl{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,n){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===n)}getDependents(e,n){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===n)}hasDependencies(e,n){return this.getDependencies(e,n).length>0}getDeploymentOrder(e){let n=new Set,r=[],i=(s)=>{let a=`${s.name}:${s.region}`;if(n.has(a))return;n.add(a);let c=this.getDependencies(s.name,s.region);for(let u of c)i({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(s)};for(let s of e)i(s);return r}detectCircularDependencies(){let e=new Set,n=new Set,r=(i,s)=>{let a=`${i}:${s}`;if(n.has(a))return!0;if(e.has(a))return!1;e.add(a),n.add(a);let c=this.getDependencies(i,s);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return n.delete(a),!1};for(let i of this.dependencies)if(r(i.dependentStack,i.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var tf=new Dl,rf=new kl,nf=new Nl,of=new xl;var ct=[{code:"us-east-1",name:"US East (N. Virginia)",location:"Virginia, USA",launchYear:2006,availabilityZones:6,localZones:16,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO","FedRAMP"]},{code:"us-east-2",name:"US East (Ohio)",location:"Ohio, USA",launchYear:2016,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-1",name:"US West (N. California)",location:"California, USA",launchYear:2009,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-2",name:"US West (Oregon)",location:"Oregon, USA",launchYear:2011,availabilityZones:4,localZones:2,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"eu-west-1",name:"Europe (Ireland)",location:"Dublin, Ireland",launchYear:2007,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1.05},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"eu-central-1",name:"Europe (Frankfurt)",location:"Frankfurt, Germany",launchYear:2014,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"ap-southeast-1",name:"Asia Pacific (Singapore)",location:"Singapore",launchYear:2010,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.12},compliance:["PCI-DSS","SOC","ISO","MTCS"]},{code:"ap-northeast-1",name:"Asia Pacific (Tokyo)",location:"Tokyo, Japan",launchYear:2011,availabilityZones:4,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.15},compliance:["PCI-DSS","SOC","ISO"]}];function qi(e){return ct.find((n)=>n.code===e)}function sf(){return ct}function af(e){let n=e.toLowerCase();return ct.filter((r)=>r.location.toLowerCase().includes(n))}function cf(e){return ct.filter((n)=>n.compliance.includes(e))}function lf(e){return ct.filter((n)=>n.pricing.tier===e)}function df(e){return ct.some((n)=>n.code===e)}function uf(e){if(e.continent==="North America")return qi("us-east-1");if(e.continent==="Europe")return qi("eu-west-1");if(e.continent==="Asia")return qi("ap-southeast-1");return qi("us-east-1")}function pf(e){let n=[...ct];if(e.compliance)n=n.filter((r)=>e.compliance.every((i)=>r.compliance.includes(i)));if(e.requiredServices)n=n.filter((r)=>e.requiredServices.every((i)=>r.services[i]));if(e.pricingSensitive)n.sort((r,i)=>r.pricing.multiplier-i.pricing.multiplier);return n.slice(0,5)}function mf(e){let n=qi(e);if(!n)throw Error(`Invalid region: ${e}`);let r=[];for(let i of ct){if(i.code===e)continue;let s=ls(n,i),a=us(n,i);r.push({primary:n,secondary:i,distance:s,sameContinent:a})}return r.sort((i,s)=>{if(i.sameContinent!==s.sameContinent)return i.sameContinent?1:-1;return i.distance-s.distance}),r.slice(0,3)}function ls(e,n){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},i=Qe(e.location),s=Qe(n.location);return Math.abs((r[i]||0)-(r[s]||0))}function us(e,n){return Qe(e.location)===Qe(n.location)}function Qe(e){if(e.includes("USA")||e.includes("Canada"))return"North America";if(e.includes("Europe")||e.includes("Ireland")||e.includes("Germany"))return"Europe";if(e.includes("Asia")||e.includes("Singapore")||e.includes("Japan"))return"Asia";if(e.includes("Brazil"))return"South America";if(e.includes("Australia"))return"Oceania";return"Unknown"}function ep(e){return`${e.name} (${e.code})`}function gf(e){return e.map((n)=>ep(n)).join(`
|
|
2740
|
+
`)}function ff(){let e={total:ct.length,byContinent:{},byPricingTier:{}};for(let n of ct){let r=Qe(n.location);e.byContinent[r]=(e.byContinent[r]||0)+1,e.byPricingTier[n.pricing.tier]=(e.byPricingTier[n.pricing.tier]||0)+1}return e}class _l{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((n)=>n.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((n)=>n.role===e)}createCrossAccountRole(e,n,r,i,s){let a={roleArn:`arn:aws:iam::${n}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:n,permissions:i,externalId:s?.externalId,sessionDuration:s?.sessionDuration||3600};return this.crossAccountRoles.push(a),a}getAssumeRolePolicyDocument(e,n){let r={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(n)r.Statement[0].Condition={StringEquals:{"sts:ExternalId":n}};return r}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,n,r){this.accountMappings.push({environment:e,accountId:n,region:r})}getAccountForEnvironment(e){return this.accountMappings.find((n)=>n.environment===e)}async assumeRole(e,n,r){return console.log(`Assuming role: ${e} with session: ${n}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let n=this.accounts.get(e);if(!n)throw Error(`Account not found: ${e}`);if(n.assumeRoleArn){let r=await this.assumeRole(n.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((n)=>n.sourceAccountId===e||n.targetAccountId===e)}async validateAccountAccess(e){try{let n=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let r of this.accounts.values())e[r.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((r,i)=>r+i,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Ol{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,n){let r={id:`ou-${Date.now()}`,name:e,parentId:n,accounts:[]};return this.organizationalUnits.set(r.id,r),r}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);if(!r.accounts.includes(n))r.accounts.push(n)}removeAccountFromOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);r.accounts=r.accounts.filter((i)=>i!==n)}getAccountsInOU(e){let n=this.organizationalUnits.get(e);if(!n)return[];return[...n.accounts]}applyServiceControlPolicy(e,n){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:n}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var hf=new _l,yf=new Ol;var tp={basic:{name:"Basic (3 Accounts)",description:"Simple structure for small teams",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account for AWS Organizations"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production workloads"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development and testing"}],organizationalUnits:[{name:"root"},{name:"workloads",parent:"root"}]},standard:{name:"Standard (5 Accounts)",description:"Recommended for most organizations",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"security",email:"aws+security@example.com",role:"security",ou:"security",description:"Security tooling and audit logs"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared services (CI/CD, monitoring)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production environment"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"workloads",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root"},{name:"infrastructure",parent:"root"},{name:"workloads",parent:"root"}]},enterprise:{name:"Enterprise (7+ Accounts)",description:"For large organizations with strict compliance requirements",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"audit",email:"aws+audit@example.com",role:"security",ou:"security",description:"Audit and compliance"},{alias:"log-archive",email:"aws+logs@example.com",role:"security",ou:"security",description:"Centralized log storage"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared infrastructure"},{alias:"network",email:"aws+network@example.com",role:"shared-services",ou:"infrastructure",description:"Network infrastructure (Transit Gateway)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"production-ou",description:"Production workloads"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"non-production-ou",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"non-production-ou",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root",policies:["deny-root-access"]},{name:"infrastructure",parent:"root"},{name:"production-ou",parent:"root",policies:["require-mfa"]},{name:"non-production-ou",parent:"root"}]}},bf={denyRootAccess:{name:"Deny Root User Access",description:"Prevent root user from performing any actions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyRootUser",Effect:"Deny",Action:"*",Resource:"*",Condition:{StringLike:{"aws:PrincipalArn":"arn:aws:iam::*:root"}}}]}},requireMFA:{name:"Require MFA for All Actions",description:"Require MFA for console and API access",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"RequireMFA",Effect:"Deny",Action:"*",Resource:"*",Condition:{BoolIfExists:{"aws:MultiFactorAuthPresent":"false"}}}]}},denyRegions:{name:"Deny Access to Non-Approved Regions",description:"Restrict operations to specific regions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyNonApprovedRegions",Effect:"Deny",NotAction:["iam:*","organizations:*","route53:*","cloudfront:*","support:*","s3:*"],Resource:"*",Condition:{StringNotEquals:{"aws:RequestedRegion":["us-east-1","us-west-2"]}}}]}},preventLeaving:{name:"Prevent Leaving Organization",description:"Prevent accounts from leaving the organization",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"PreventLeaving",Effect:"Deny",Action:"organizations:LeaveOrganization",Resource:"*"}]}},denyS3Unencrypted:{name:"Deny Unencrypted S3 Uploads",description:"Require encryption for all S3 uploads",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyUnencryptedS3Uploads",Effect:"Deny",Action:"s3:PutObject",Resource:"*",Condition:{StringNotEquals:{"s3:x-amz-server-side-encryption":["AES256","aws:kms"]}}}]}}},Sf={deploymentRole:{name:"CrossAccountDeploymentRole",description:"Role for deploying infrastructure from CI/CD",permissions:["cloudformation:*","s3:*","ec2:*","ecs:*","lambda:*","iam:GetRole","iam:PassRole","logs:*","events:*"]},readOnlyRole:{name:"CrossAccountReadOnlyRole",description:"Read-only access for monitoring and auditing",permissions:["cloudformation:Describe*","cloudformation:List*","ec2:Describe*","ecs:Describe*","lambda:Get*","lambda:List*","s3:Get*","s3:List*","logs:Get*","logs:Describe*"]},securityAuditRole:{name:"CrossAccountSecurityAuditRole",description:"Security audit and compliance checks",permissions:["iam:Get*","iam:List*","iam:Generate*","access-analyzer:*","guardduty:Get*","guardduty:List*","securityhub:Get*","securityhub:List*","config:Describe*","config:Get*","config:List*"]},breakGlassRole:{name:"CrossAccountBreakGlassRole",description:"Emergency access role (use with caution)",permissions:["*"]}};function vf(e){return tp[e]}function Cf(e,n){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...n&&{ManagedPolicyArns:n},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Tf(e){let n=[],r=[],i=e.accounts.filter((d)=>d.role==="management");if(i.length===0)n.push("No management account defined");if(i.length>1)n.push("Multiple management accounts defined");let s=e.accounts.map((d)=>d.email),a=s.filter((d,m)=>s.indexOf(d)!==m);if(a.length>0)n.push(`Duplicate email addresses: ${a.join(", ")}`);let c=e.accounts.map((d)=>d.alias),u=c.filter((d,m)=>c.indexOf(d)!==m);if(u.length>0)n.push(`Duplicate aliases: ${u.join(", ")}`);if(!e.accounts.some((d)=>d.role==="security"))r.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)r.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((d)=>d.role==="production"))r.push("No production account defined");return{valid:n.length===0,errors:n,warnings:r}}function Ef(e){let n=[];if(n.push(`${e.name}`),n.push("─".repeat(e.name.length)),n.push(e.description),n.push(""),e.organizationalUnits){n.push("Organizational Units:");for(let r of e.organizationalUnits){let i=r.parent?" └─ ":" ";n.push(`${i}${r.name}`)}n.push("")}n.push("Accounts:");for(let r of e.accounts)n.push(` ${r.alias.padEnd(20)} ${r.role.padEnd(15)} ${r.email}`),n.push(` ${"".padEnd(20)} ${r.description}`),n.push("");return n.join(`
|
|
2741
2741
|
`)}function wf(e={}){let{workflowName:n="Deploy",trigger:r="push",branches:i=["main"],environments:s=["production"],awsRegion:a="us-east-1",awsRole:c,bunVersion:u="latest",deployCommand:d="bun run cloud deploy",testCommand:m="bun test",buildCommand:p="bun run build"}=e,g=!!c;return`name: ${n}
|
|
2742
2742
|
|
|
2743
2743
|
on:
|
|
@@ -3748,7 +3748,7 @@ Scanning image: ${r}`),console.log(`Scanner: ${n.scanner}`);let i=`scan-result-$
|
|
|
3748
3748
|
Scan Results:`),console.log(` Total vulnerabilities: ${a.total}`),console.log(` Critical: ${a.critical}`),console.log(` High: ${a.high}`),console.log(` Medium: ${a.medium}`),console.log(` Low: ${a.low}`),console.log(` Status: ${c?"✓ PASSED":"✗ FAILED"}`),u}simulateVulnerabilities(e){let n=[];if(e.scanner==="trivy"||e.scanner==="ecr")n.push({id:"vuln-1",cve:"CVE-2024-1234",severity:"HIGH",packageName:"openssl",installedVersion:"1.1.1k",fixedVersion:"1.1.1l",title:"OpenSSL buffer overflow",description:"Buffer overflow vulnerability in OpenSSL",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-1234"],cvss:7.5}),n.push({id:"vuln-2",cve:"CVE-2024-5678",severity:"MEDIUM",packageName:"curl",installedVersion:"7.68.0",fixedVersion:"7.79.0",title:"curl remote code execution",description:"Remote code execution in curl",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-5678"],cvss:5.3});return n}evaluateScanResult(e,n){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return n.critical===0;case"HIGH":return n.critical===0&&n.high===0;case"MEDIUM":return n.critical===0&&n.high===0&&n.medium===0;case"LOW":return n.total===0;default:return!0}}createPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,...e};return this.policies.set(n,r),r}createStrictPolicy(e){return this.createPolicy({name:e,allowedSeverities:[],maxCritical:0,maxHigh:0,blockOnFailure:!0,exemptions:[]})}createPermissivePolicy(e){return this.createPolicy({name:e,allowedSeverities:["CRITICAL","HIGH","MEDIUM","LOW"],maxCritical:5,maxHigh:10,blockOnFailure:!1,exemptions:[]})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getResult(e){return this.results.get(e)}listResults(){return Array.from(this.results.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.repository,ImageScanningConfiguration:{ScanOnPush:e.scanOnPush},ImageTagMutability:"IMMUTABLE",EncryptionConfiguration:{EncryptionType:"AES256"}}}}clear(){this.configs.clear(),this.results.clear(),this.policies.clear(),this.configCounter=0,this.resultCounter=0,this.policyCounter=0}}var Wf=new zl;class Hl{configs=new Map;multiStageConfigs=new Map;optimizations=new Map;analyses=new Map;configCounter=0;multiStageCounter=0;optimizationCounter=0;analysisCounter=0;createBuildConfig(e){let n=`build-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.configs.set(n,r),r}createOptimizedBuildConfig(e){let n={type:e.enableCache?"registry":"inline",cacheFrom:e.registry?[`${e.registry}/cache`]:void 0,cacheTo:e.registry?`${e.registry}/cache`:void 0,maxCacheAge:7};return this.createBuildConfig({name:e.name,dockerfile:e.dockerfile,context:".",cacheStrategy:n,buildArgs:{BUILDKIT_INLINE_CACHE:"1"}})}createMultiStageConfig(e){let n=`multi-stage-${Date.now()}-${this.multiStageCounter++}`,r={id:n,...e};return this.multiStageConfigs.set(n,r),r}createNodeMultiStageBuild(e){let n=e.nodeVersion||"18-alpine";return this.createMultiStageConfig({name:e.name,targetStage:e.targetStage||"production",stages:[{name:"dependencies",baseImage:`node:${n}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci --only=production"]},{name:"build",baseImage:`node:${n}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci","COPY . .","RUN npm run build"]},{name:"production",baseImage:`node:${n}`,workdir:"/app",copyFrom:["dependencies:/app/node_modules","build:/app/dist"],commands:["COPY package*.json ./","ENV NODE_ENV=production",'CMD ["node", "dist/index.js"]']}]})}generateDockerfile(e){let n=this.multiStageConfigs.get(e);if(!n)throw Error(`Multi-stage config not found: ${e}`);let r=[];for(let i of n.stages){if(r.push(`# Stage: ${i.name}`),r.push(`FROM ${i.baseImage} AS ${i.name}`),i.workdir)r.push(`WORKDIR ${i.workdir}`);if(i.env)for(let[s,a]of Object.entries(i.env))r.push(`ENV ${s}=${a}`);for(let s of i.commands)r.push(s);r.push("")}return r.join(`
|
|
3749
3749
|
`)}analyzeImage(e,n){let r=`analysis-${Date.now()}-${this.analysisCounter++}`,i=n.map((u)=>({...u,cacheable:this.isLayerCacheable(u.command)})),s=i.reduce((u,d)=>u+d.size,0),a=i.filter((u)=>!u.cacheable&&u.size>100).length,c={id:r,imageId:e,layers:i,totalSize:s,unnecessaryLayers:a};return this.analyses.set(r,c),c}isLayerCacheable(e){let n=["FROM","RUN","COPY","ADD","WORKDIR","ENV"],r=["CMD","ENTRYPOINT","LABEL"];for(let i of n)if(e.startsWith(i))return!0;for(let i of r)if(e.startsWith(i))return!1;return!1}generateOptimizations(e){let n=this.analyses.get(e);if(!n)throw Error(`Analysis not found: ${e}`);let r=`optimization-${Date.now()}-${this.optimizationCounter++}`,i=[],s=n.layers.filter((m)=>m.command.startsWith("RUN"));if(s.length>5)i.push({type:"layer_reduction",priority:"high",title:"Combine RUN commands",description:`${s.length} RUN commands found. Combine them to reduce layers.`,example:"RUN apt-get update && apt-get install -y package1 package2",impact:"Reduce image size by 20-30% and improve build time"});let a=n.layers[0];if(a.command.includes("ubuntu")||a.command.includes("debian"))i.push({type:"base_image",priority:"medium",title:"Use Alpine base image",description:"Switch to Alpine Linux for smaller image size",example:"FROM node:18-alpine",impact:"Reduce image size by 50-70%"});let c=n.layers.filter((m)=>m.command.startsWith("COPY"));if(c.length>0&&c[0].index>3)i.push({type:"cache_optimization",priority:"high",title:"Copy dependencies first",description:"Copy package files before source code to leverage layer caching",example:`COPY package*.json ./
|
|
3750
3750
|
RUN npm install
|
|
3751
|
-
COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let u={sizeBefore:n.totalSize,sizeAfter:n.totalSize*0.6,timeBefore:300,timeAfter:120},d={id:r,name:`Optimization for ${n.imageId}`,recommendations:i,estimatedSavings:u};return this.optimizations.set(r,d),d}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var Kf=new Hl;class Wa{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let n=`registry-${Date.now()}-${this.registryCounter++}`,r={id:n,...e};return this.registries.set(n,r),r}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let n=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return n.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},n}enableReplication(e,n){let r=this.registries.get(e);if(!r)throw Error(`Registry not found: ${e}`);return r.replication={enabled:!0,destinations:n},r}createCredentials(e){let n=`creds-${Date.now()}-${this.credentialsCounter++}`,r={id:n,...e};return this.credentials.set(n,r),r}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((n)=>({Destinations:[{Region:n.region,...n.registryId&&{RegistryId:n.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var hp=new Wa;class Ka{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let n=`mesh-${Date.now()}-${this.meshCounter++}`,r={id:n,...e};return this.meshes.set(n,r),r}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let n=`vnode-${Date.now()}-${this.nodeCounter++}`,r={id:n,...e};return this.virtualNodes.set(n,r),r}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let n=`vrouter-${Date.now()}-${this.routerCounter++}`,r={id:n,...e};return this.virtualRouters.set(n,r),r}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let n=`vgateway-${Date.now()}-${this.gatewayCounter++}`,r={id:n,...e};return this.virtualGateways.set(n,r),r}createIngressGateway(e){let n={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)n.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[n],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(e){return this.meshes.get(e)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(e){return this.virtualNodes.get(e)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(e){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:e.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(e,n){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:n,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol},...r.healthCheck&&{HealthCheck:{Protocol:r.healthCheck.protocol,...r.healthCheck.path&&{Path:r.healthCheck.path},IntervalMillis:r.healthCheck.interval*1000,TimeoutMillis:r.healthCheck.timeout*1000,HealthyThreshold:r.healthCheck.healthyThreshold,UnhealthyThreshold:r.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,n){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:n,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol}}))}}}}clear(){this.meshes.clear(),this.virtualNodes.clear(),this.virtualRouters.clear(),this.virtualGateways.clear(),this.meshCounter=0,this.nodeCounter=0,this.routerCounter=0,this.gatewayCounter=0}}var yp=new Ka;class Gl{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let n=`layer-${Date.now()}-${this.layerCounter++}`,r=1,i={id:n,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(n,i),i}createNodeDependenciesLayer(e){return this.createLayer({layerName:e.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${e.nodeVersion}`],content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:5242880})}createUtilitiesLayer(e){return this.createLayer({layerName:e.layerName,description:"Shared utilities and helpers",compatibleRuntimes:e.runtimes,content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:1048576})}publishVersion(e){let n=this.layers.get(e);if(!n)throw Error(`Layer not found: ${e}`);let r=`version-${Date.now()}-${this.versionCounter++}`,i=n.version+1,s={id:r,layerName:n.layerName,version:i,createdAt:new Date,compatibleRuntimes:n.compatibleRuntimes,size:n.size,codeHash:this.generateHash()};return this.versions.set(r,s),n.version=i,n.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${i}`,s}addPermission(e){let n=`permission-${Date.now()}-${this.permissionCounter++}`,r={id:n,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(n,r),r}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((n)=>n.layerName===e)}generateLayerCF(e){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:e.layerName,Description:e.description,Content:e.content.type==="s3"?{S3Bucket:e.content.s3Bucket,S3Key:e.content.s3Key,...e.content.s3ObjectVersion&&{S3ObjectVersion:e.content.s3ObjectVersion}}:{ZipFile:e.content.zipFile},CompatibleRuntimes:e.compatibleRuntimes,...e.licenseInfo&&{LicenseInfo:e.licenseInfo}}}}generateLayerPermissionCF(e){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:${e.version}`,Action:e.action,Principal:e.principal,...e.organizationId&&{OrganizationId:e.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var Jf=new Gl;class ql{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let n=`version-${Date.now()}-${this.versionCounter++}`,r=this.getNextVersionNumber(e.functionName),i={id:n,functionName:e.functionName,version:r.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${r}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(n,i),i}getNextVersionNumber(e){let n=Array.from(this.versions.values()).filter((r)=>r.functionName===e).map((r)=>parseInt(r.version));return n.length>0?Math.max(...n)+1:1}createAlias(e){let n=`alias-${Date.now()}-${this.aliasCounter++}`,r={id:n,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(n,r),r}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.functionVersion=n,r.revisionId=this.generateHash(),r}configureWeightedRouting(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.routingConfig={additionalVersionWeights:n},r}createCanaryDeployment(e){let n=`deployment-${Date.now()}-${this.deploymentCounter++}`,r=Array.from(this.aliases.values()).find((s)=>s.functionName===e.functionName&&s.aliasName===e.aliasName);if(!r)r=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(r.id,{[e.toVersion]:e.canaryWeight});let i={id:n,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(n,i),i}completeDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.toVersion,r.routingConfig=void 0;return n.status="completed",n.completedAt=new Date,n}rollbackDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.fromVersion,r.routingConfig=void 0;return n.status="failed",n.completedAt=new Date,n}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let n=Array.from(this.versions.values());return e?n.filter((r)=>r.functionName===e):n}getAlias(e){return this.aliases.get(e)}listAliases(e){let n=Array.from(this.aliases.values());return e?n.filter((r)=>r.functionName===e):n}generateVersionCF(e){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:e.functionName,Description:e.description}}}generateAliasCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.aliasName,FunctionVersion:e.functionVersion,Description:e.description,...e.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(e.routingConfig.additionalVersionWeights||{}).map(([n,r])=>({FunctionVersion:n,FunctionWeight:r}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Xf=new ql;class Wl{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let n=`concurrency-${Date.now()}-${this.configCounter++}`,r={id:n,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(n,r),r}setProvisionedConcurrency(e){let n=`provisioned-${Date.now()}-${this.provisionedCounter++}`,r={id:n,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(n,r),setTimeout(()=>{r.status="ready",r.allocatedConcurrency=e.provisionedConcurrentExecutions,r.availableConcurrency=e.provisionedConcurrentExecutions},100),r}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let n=`schedule-${Date.now()}-${this.scheduleCounter++}`,r={id:n,...e};return this.schedules.set(n,r),r}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let n=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,r={id:n,...e};return this.autoScalingConfigs.set(n,r),r}configurePredictiveScaling(e){return this.configureAutoScaling({functionName:e.functionName,qualifier:e.qualifier,minCapacity:e.baselineCapacity,maxCapacity:e.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(e){return this.provisionedConfigs.get(e)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,ReservedConcurrentExecutions:e.reservedConcurrency}}}generateProvisionedConcurrencyCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:e.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${e.functionName}:${e.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:e.minCapacity,MaxCapacity:e.maxCapacity}}}generateAutoScalingPolicyCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${e.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:e.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:e.scaleInCooldown||300,ScaleOutCooldown:e.scaleOutCooldown||60}}}}clear(){this.configs.clear(),this.provisionedConfigs.clear(),this.schedules.clear(),this.autoScalingConfigs.clear(),this.configCounter=0,this.provisionedCounter=0,this.scheduleCounter=0,this.autoScalingCounter=0}}var Qf=new Wl;class Kl{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let n=`destination-${Date.now()}-${this.destinationCounter++}`,r={id:n,...e};return this.destinations.set(n,r),r}configureSQSDestination(e){let n={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let n={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let n={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let n={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(e){return this.configureDestinations({functionName:e.functionName,failureDestination:{type:"sqs",arn:e.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(e){let n=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,r={id:n,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(n,r),r}sendToDestination(e){let n=Array.from(this.destinations.values()).find((a)=>a.functionName===e.functionName);if(!n)return null;let r=e.status==="success"?n.successDestination:n.failureDestination;if(!r)return null;let i=`record-${Date.now()}-${this.recordCounter++}`,s={id:i,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:r.type,destinationArn:r.arn,payload:e.payload,error:e.error};return this.records.set(i,s),s}getDestination(e){return this.destinations.get(e)}listDestinations(e){let n=Array.from(this.destinations.values());return e?n.filter((r)=>r.functionName===e):n}getDestinationRecords(e){let n=Array.from(this.records.values());return e?n.filter((r)=>r.functionName===e):n}generateEventInvokeConfigCF(e){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:e.functionName,Qualifier:e.qualifier||"$LATEST",MaximumEventAgeInSeconds:e.maxEventAge||21600,MaximumRetryAttempts:e.maxRetries??2,...e.successDestination&&{DestinationConfig:{OnSuccess:{Destination:e.successDestination.arn}}},...e.failureDestination&&{DestinationConfig:{OnFailure:{Destination:e.failureDestination.arn}}}}}}generateEventBridgeRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{EventBusName:e.eventBusArn.split("/").pop(),EventPattern:{source:[e.source],"detail-type":[e.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}`,Id:e.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var Yf=new Kl;class Jl{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let n=`vpc-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};this.vpcConfigs.set(n,r);for(let i of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:i});return r}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,...e};return this.endpoints.set(n,r),r}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let n=`eni-${Date.now()}-${this.eniCounter++}`,r={id:n,functionName:e.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:e.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(n,r),setTimeout(()=>{r.status="available"},100),r}analyzeConnectivity(e){let n=`connectivity-${Date.now()}-${this.connectivityCounter++}`,r=Array.from(this.vpcConfigs.values()).find((d)=>d.functionName===e.functionName),i=Array.from(this.endpoints.values()).filter((d)=>d.vpcId===r?.vpcId).map((d)=>d.serviceName),s=[],a=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!a&&!c)s.push("Add NAT Gateway for internet access");if(!i.includes("com.amazonaws.us-east-1.s3"))s.push("Add S3 VPC endpoint to reduce NAT costs");if(!i.includes("com.amazonaws.us-east-1.dynamodb"))s.push("Add DynamoDB VPC endpoint for private access");let u={id:n,functionName:e.functionName,hasInternetAccess:a||c,hasNATGateway:a,hasVPCEndpoints:i.length>0,endpoints:i,recommendations:s};return this.connectivity.set(n,u),u}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let n=Array.from(this.vpcConfigs.values());return e?n.filter((r)=>r.functionName===e):n}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((n)=>n.functionName===e)}listVPCEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.vpcId===e):n}generateVPCConfigCF(e){return{VpcConfig:{SubnetIds:e.subnetIds,SecurityGroupIds:e.securityGroupIds,...e.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(e){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:e.vpcId,ServiceName:e.serviceName,VpcEndpointType:e.endpointType,...e.subnetIds&&{SubnetIds:e.subnetIds},...e.securityGroupIds&&{SecurityGroupIds:e.securityGroupIds},...e.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:e.privateDnsEnabled}}}}generateSecurityGroupCF(e){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:e.groupName,GroupDescription:`Security group for Lambda ${e.groupName}`,VpcId:e.vpcId,...e.ingressRules&&{SecurityGroupIngress:e.ingressRules.map((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,...n.cidrIp&&{CidrIp:n.cidrIp},...n.sourceSecurityGroupId&&{SourceSecurityGroupId:n.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,CidrIp:n.cidrIp||"0.0.0.0/0"}))}}}}clear(){this.vpcConfigs.clear(),this.endpoints.clear(),this.networkInterfaces.clear(),this.connectivity.clear(),this.configCounter=0,this.endpointCounter=0,this.eniCounter=0,this.connectivityCounter=0}}var Zf=new Jl;class Xl{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let n=`dlq-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.dlqConfigs.set(n,r),r}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let n=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:n.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),n}sendToDLQ(e){let n=`message-${Date.now()}-${this.messageCounter++}`,r={id:n,timestamp:new Date,...e};return this.messages.set(n,r),r}createDLQAlarm(e){let n=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:n,...e};return this.alarms.set(n,r),r}createAgeAlarm(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${n.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let n=this.messages.get(e);if(!n)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((a)=>a.functionName===n.functionName);if(!r)throw Error(`DLQ config not found for function: ${n.functionName}`);let i=`reprocess-${Date.now()}-${this.reprocessCounter++}`,s={id:i,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(i,s),setTimeout(()=>{s.status="processing",setTimeout(()=>{let a=Math.random()>0.3;if(s.status=a?"success":"failed",s.completedAt=new Date,!a)s.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),s}async batchReprocess(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let i=Array.from(this.messages.values()).filter((s)=>s.functionName===n.functionName).slice(0,e.maxMessages||10).map((s)=>this.reprocessMessage(s.id));return Promise.all(i)}getDLQStats(e){let n=this.dlqConfigs.get(e);if(!n)throw Error(`DLQ config not found: ${e}`);let r=Array.from(this.messages.values()).filter((c)=>c.functionName===n.functionName),i={},s=0;for(let c of r)i[c.errorType]=(i[c.errorType]||0)+1,s+=c.attemptCount;let a=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:a.length>0?new Date(Math.min(...a.map((c)=>c.getTime()))):void 0,newestMessage:a.length>0?new Date(Math.max(...a.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?s/r.length:0,errorTypes:i}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let n=this.dlqConfigs.get(e);if(!n)return[];return Array.from(this.messages.values()).filter((r)=>r.functionName===n.functionName)}generateDLQCF(e){return{DeadLetterConfig:{TargetArn:e.targetArn}}}generateSQSDLQCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${e.functionName}-dlq`,MessageRetentionPeriod:e.retentionPeriod||1209600,...e.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:e.targetArn,maxReceiveCount:e.maxReceiveCount}}}}}generateDLQAlarmCF(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${n.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.targetArn.split(":").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.notificationTopicArn]}}}}clear(){this.dlqConfigs.clear(),this.messages.clear(),this.alarms.clear(),this.reprocessing.clear(),this.configCounter=0,this.messageCounter=0,this.alarmCounter=0,this.reprocessCounter=0}}var eh=new Xl;class Ja{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"weighted",...e};return this.policies.set(n,r),r}createLatencyPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"latency",...e};return this.policies.set(n,r),r}createFailoverPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"failover",...e};return this.policies.set(n,r),r}createGeolocationPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geolocation",...e};return this.policies.set(n,r),r}createGeoproximityPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geoproximity",...e};return this.policies.set(n,r),r}createHTTPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:e.port===443?"https":"http",requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",port:e.port||(e.port===443?443:80),...e};return this.healthChecks.set(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),r}createTCPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),r}createCalculatedHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{let s=e.childHealthChecks.filter((a)=>this.healthChecks.get(a)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=s>=e.healthThreshold?"Healthy":"Unhealthy"},150),r}createTrafficPolicy(e){let n=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,r={id:n,version:1,...e};return this.trafficPolicies.set(n,r),r}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let n={},r=[];return e.locations.forEach((i,s)=>{let a=`endpoint${s}`;n[a]={type:"value",value:i.endpoint},r.push({endpointReference:a,region:i.region,latitude:i.latitude,longitude:i.longitude,bias:i.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:n,rules:{geoproximity:{ruleType:"geoproximity",locations:r}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let n={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let r=e;n.Properties.HealthCheckConfig.ChildHealthChecks=r.childHealthChecks,n.Properties.HealthCheckConfig.HealthThreshold=r.healthThreshold}else{if(e.ipAddress)n.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)n.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)n.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)n.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)n.Properties.HealthCheckConfig.EnableSNI=!0}return n}generateWeightedRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Weight:e.weight,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}generateFailoverRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Failover:e.failover,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var bp=new Ja;class Ql{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let n=`dnssec-${Date.now()}-${this.configCounter++}`,r={id:n,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(n,r),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{r.status="SIGNED",r.signingStatus="DNSSEC signing complete"},100),r}disableDNSSEC(e){let n=this.configs.get(e);if(!n)throw Error(`DNSSEC config not found: ${e}`);return n.status="DELETING",n.signingStatus="Removing DNSSEC signing",setTimeout(()=>{n.status="NOT_SIGNING",n.signingStatus="DNSSEC signing removed"},100),n}createKSK(e){let n=`ksk-${Date.now()}-${this.kskCounter++}`,r={id:n,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};r.dnskeyRecord=`${r.flag} 3 8 ${r.publicKey}`;let i=this.generateDigest(r.dnskeyRecord);return r.digestValue=i,r.dsRecord=`${r.keyTag} 8 ${r.digestAlgorithm} ${i}`,this.ksks.set(n,r),r}deactivateKSK(e){let n=this.ksks.get(e);if(!n)throw Error(`KSK not found: ${e}`);return n.status="INACTIVE",n}validateDNSSEC(e){let n=`validation-${Date.now()}-${this.validationCounter++}`,r=e.checkDNSKEY!==!1?Math.random()>0.1:!1,i=e.checkRRSIG!==!1?Math.random()>0.1:!1,s=r&&i,a=[];if(!r)a.push("DNSKEY record not found");if(!i)a.push("RRSIG record not found");let c;if(!r&&!i)c="INSECURE";else if(r&&i&&s)c="VALID";else if(r||i)c="BOGUS",a.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:n,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:i,validSignature:s,errors:a};return this.validations.set(n,u),u}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let n=Array.from(this.ksks.values());return e?n.filter((r)=>r.hostedZoneId===e):n}getDSRecord(e){let n=this.ksks.get(e);if(!n||!n.dsRecord)throw Error("DS record not available");return n.dsRecord}generatePublicKey(){let n="";for(let r=0;r<256;r++)n+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return n}generateDigest(e){let r="";for(let i=0;i<64;i++)r+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return r}generateDNSSECCF(e){return{Type:"AWS::Route53::DNSSEC",Properties:{HostedZoneId:e.hostedZoneId}}}generateKSKCF(e){return{Type:"AWS::Route53::KeySigningKey",Properties:{Name:e.name,HostedZoneId:e.hostedZoneId,KeyManagementServiceArn:e.keyManagementServiceArn,Status:e.status}}}clear(){this.configs.clear(),this.ksks.clear(),this.validations.clear(),this.configCounter=0,this.kskCounter=0,this.validationCounter=0}}var th=new Ql;class Yl{endpoints=new Map;rules=new Map;firewalls=new Map;ruleGroups=new Map;domainLists=new Map;endpointCounter=0;ruleCounter=0;firewallCounter=0;ruleGroupCounter=0;domainListCounter=0;createResolverEndpoint(e){let n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,status:"CREATING",...e};return this.endpoints.set(n,r),setTimeout(()=>{r.status="OPERATIONAL",r.ipAddresses.forEach((i)=>{if(!i.ip)i.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),r}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let n=`rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,status:"CREATING",...e};return this.rules.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let n=`domain-list-${Date.now()}-${this.domainListCounter++}`,r={id:n,status:"CREATING",...e};return this.domainLists.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createFirewallRuleGroup(e){let n=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,r={id:n,name:e.name,rules:e.rules.map((i,s)=>({id:`rule-${n}-${s}`,...i})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(n,r),r}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let n=`firewall-${Date.now()}-${this.firewallCounter++}`,r={id:n,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((i,s)=>({id:`assoc-${n}-${s}`,vpcId:e.vpcId,firewallRuleGroupId:i.firewallRuleGroupId,priority:i.priority,mutationProtection:i.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(n,r),r}createMalwareProtectionFirewall(e){let n=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),r=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:n.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:r.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.direction===e):n}getRule(e){return this.rules.get(e)}listRules(){return Array.from(this.rules.values())}getFirewall(e){return this.firewalls.get(e)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(e){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:e.name,Direction:e.direction,IpAddresses:e.ipAddresses.map((n)=>({SubnetId:n.subnetId,...n.ip&&{Ip:n.ip}})),SecurityGroupIds:e.securityGroupIds}}}generateResolverRuleCF(e){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:e.name,RuleType:e.ruleType,DomainName:e.domainName,...e.targetIps&&{TargetIps:e.targetIps.map((n)=>({Ip:n.ip,Port:n.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((n)=>({Name:n.name,Priority:n.priority,Action:n.action,FirewallDomainListId:n.firewallDomainListId,...n.blockResponse&&{BlockResponse:n.blockResponse},...n.blockOverrideDomain&&{BlockOverrideDomain:n.blockOverrideDomain},...n.blockOverrideTTL&&{BlockOverrideTtl:n.blockOverrideTTL}}))}}}clear(){this.endpoints.clear(),this.rules.clear(),this.firewalls.clear(),this.ruleGroups.clear(),this.domainLists.clear(),this.endpointCounter=0,this.ruleCounter=0,this.firewallCounter=0,this.ruleGroupCounter=0,this.domainListCounter=0}}var rh=new Yl;class Zl{bounces=new Map;complaints=new Map;handlers=new Map;suppressionList=new Map;metrics=new Map;bounceCounter=0;complaintCounter=0;handlerCounter=0;suppressionCounter=0;metricsCounter=0;recordBounce(e){let n=`bounce-${Date.now()}-${this.bounceCounter++}`,r={id:n,...e};if(this.bounces.set(n,r),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return r}recordComplaint(e){let n=`complaint-${Date.now()}-${this.complaintCounter++}`,r={id:n,...e};this.complaints.set(n,r);for(let i of e.recipients)this.addToSuppressionList({emailAddress:i,reason:"COMPLAINT"});return r}createBounceHandler(e){let n=`handler-${Date.now()}-${this.handlerCounter++}`,r={id:n,...e};return this.handlers.set(n,r),r}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let n=`suppression-${Date.now()}-${this.suppressionCounter++}`,r=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,i={id:n,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:r,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,i),i}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let n=this.suppressionList.get(e);if(!n)return!1;if(n.expiresAt&&n.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,n){let r=Array.from(this.bounces.values()).filter((p)=>p.timestamp>=e&&p.timestamp<=n),i=r.length,s=r.filter((p)=>p.bounceType==="Permanent").length,a=r.filter((p)=>p.bounceType==="Transient").length,c=i*10,u=i/c*100,d=new Map;for(let p of r)d.set(p.recipient,(d.get(p.recipient)||0)+1);let m=Array.from(d.entries()).map(([p,g])=>({email:p,count:g})).sort((p,g)=>g.count-p.count).slice(0,10);return{totalBounces:i,permanentBounces:s,transientBounces:a,bounceRate:u,topRecipients:m}}getComplaintStatistics(e,n){let r=Array.from(this.complaints.values()).filter((d)=>d.timestamp>=e&&d.timestamp<=n),i=r.length,s=new Set;for(let d of r)for(let m of d.recipients)s.add(m);let a=s.size,c=i*1000,u=i/c*100;return{totalComplaints:i,uniqueComplainters:a,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,n=new Date,r=new Date(n.getTime()-86400000),i=this.getBounceStatistics(r,n),s=this.getComplaintStatistics(r,n),a;if(i.bounceRate>10||s.complaintRate>0.5)a="Shutdown";else if(i.bounceRate>5||s.complaintRate>0.1)a="Probation";else if(i.bounceRate>2||s.complaintRate>0.05)a="Warning";else a="Good";let c={id:e,timestamp:n,bounceRate:i.bounceRate,complaintRate:s.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:i.totalBounces*10,reputationStatus:a};return this.metrics.set(e,c),c}getBounces(e){let n=Array.from(this.bounces.values());return e?n.filter((r)=>r.messageId===e):n}getComplaints(e){let n=Array.from(this.complaints.values());return e?n.filter((r)=>r.messageId===e):n}listSuppressionList(e){let n=Array.from(this.suppressionList.values());return e?n.filter((r)=>r.reason===e):n}generateSNSSubscriptionCF(e){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:e.topicArn,Endpoint:e.endpoint,Protocol:e.protocol}}}generateEventDestinationCF(e){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:e.configurationSetName,EventDestination:{Name:e.eventDestinationName,Enabled:!0,MatchingEventTypes:e.eventTypes,...e.snsTopicArn&&{SnsDestination:{TopicARN:e.snsTopicArn}},...e.cloudWatchDestination&&{CloudWatchDestination:e.cloudWatchDestination}}}}}clear(){this.bounces.clear(),this.complaints.clear(),this.handlers.clear(),this.suppressionList.clear(),this.metrics.clear(),this.bounceCounter=0,this.complaintCounter=0,this.handlerCounter=0,this.suppressionCounter=0,this.metricsCounter=0}}var nh=new Zl;class ed{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let n=`event-${Date.now()}-${this.eventCounter++}`,r={id:n,...e};if(this.events.set(n,r),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return r}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let n=`campaign-${Date.now()}-${this.campaignCounter++}`,r={id:n,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(n,r),r}updateCampaignStats(e,n){let r=this.campaigns.get(e);if(!r)return;switch(n){case"send":r.sentCount++;break;case"delivery":r.deliveredCount++;break;case"open":r.openCount++;break;case"click":r.clickCount++;break;case"bounce":r.bounceCount++;break;case"complaint":r.complaintCount++;break}}generateReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r=Array.from(this.events.values()).filter((v)=>{let I=v.timestamp>=e.startDate&&v.timestamp<=e.endDate,D=!e.campaignId||v.tags?.campaignId===e.campaignId;return I&&D}),i=r.filter((v)=>v.eventType==="send").length,s=r.filter((v)=>v.eventType==="delivery").length,a=r.filter((v)=>v.eventType==="open").length,c=r.filter((v)=>v.eventType==="click").length,u=r.filter((v)=>v.eventType==="bounce").length,d=r.filter((v)=>v.eventType==="complaint").length,m=i>0?s/i*100:0,p=s>0?a/s*100:0,g=s>0?c/s*100:0,y=a>0?c/a*100:0,f=i>0?u/i*100:0,h=s>0?d/s*100:0,S=new Map;for(let v of r)if(v.eventType==="click"){let I=v;S.set(I.link,(S.get(I.link)||0)+1)}let C=Array.from(S.entries()).map(([v,I])=>({link:v,clicks:I})).sort((v,I)=>I.clicks-v.clicks).slice(0,10),E={desktop:0,mobile:0,tablet:0,unknown:0};for(let v of r)if(v.eventType==="open"||v.eventType==="click"){let I=v.userAgent.toLowerCase();if(I.includes("mobile"))E.mobile++;else if(I.includes("tablet"))E.tablet++;else if(I.includes("mozilla"))E.desktop++;else E.unknown++}let w={id:n,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:i,totalDelivered:s,totalOpened:a,totalClicked:c,totalBounced:u,totalComplaints:d,deliveryRate:m,openRate:p,clickRate:g,clickToOpenRate:y,bounceRate:f,complaintRate:h,topLinks:C,deviceBreakdown:E,locationBreakdown:{}};return this.reports.set(n,w),w}createABTest(e){let n=`abtest-${Date.now()}-${this.abTestCounter++}`,r={id:n,name:e.name,variants:e.variants.map((i,s)=>({id:`variant-${n}-${s}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...i})),status:"draft"};return this.abTests.set(n,r),r}startABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);return n.status="running",n.startedAt=new Date,n}completeABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);let r=n.variants[0],i=0;for(let s of n.variants){let a=s.sentCount>0?s.openCount/s.sentCount:0;if(a>i)i=a,r=s}return n.status="completed",n.completedAt=new Date,n.winner=r.id,n}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let n=Array.from(this.events.values());if(e?.messageId)n=n.filter((r)=>r.messageId===e.messageId);if(e?.eventType)n=n.filter((r)=>r.eventType===e.eventType);if(e?.startDate)n=n.filter((r)=>r.timestamp>=e.startDate);if(e?.endDate)n=n.filter((r)=>r.timestamp<=e.endDate);return n}generateTrackingConfigurationCF(e){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:e.configurationSetName,...e.openTracking&&{TrackingOptions:{CustomRedirectDomain:"tracking.example.com"}}}}}clear(){this.events.clear(),this.campaigns.clear(),this.reports.clear(),this.abTests.clear(),this.eventCounter=0,this.campaignCounter=0,this.reportCounter=0,this.abTestCounter=0}}var ih=new ed;class td{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,n=Math.random()*5,r=Math.random()*0.5,i=Math.floor(Math.random()*10),s=Math.max(0,100-n*10-r*100-i*2),a=[];if(n>2)a.push("Reduce bounce rate by cleaning email list");if(r>0.1)a.push("Review email content and unsubscribe process");if(i>5)a.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:s,bounceRate:n,complaintRate:r,spamReports:i,blacklistStatus:this.checkBlacklists(),dkimStatus:"VERIFIED",spfStatus:"PASS",dmarcStatus:"PASS",sendingLimits:{maxSendRate:14,max24HourSend:50000,sentLast24Hours:12000,remainingQuota:38000,quotaResetTime:new Date(Date.now()+86400000)},recommendations:a};return this.dashboards.set(e,c),c}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((n)=>({listName:n,listed:Math.random()>0.95,delistUrl:`https://www.${n.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let n=`warmup-${Date.now()}-${this.warmupCounter++}`,r=[],i=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let a=0;a<e.durationDays;a++)r.push(Math.floor(e.initialDailyLimit+i*a));let s={id:n,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:r,currentLimit:r[0],status:"active"};return this.warmupPlans.set(n,s),s}createAggressiveWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(e){let n=this.warmupPlans.get(e);if(!n)throw Error(`Warmup plan not found: ${e}`);if(n.currentDay<n.totalDays)n.currentDay++,n.currentLimit=n.dailyLimits[n.currentDay-1];if(n.currentDay>=n.totalDays)n.status="completed";return n}trackDomainReputation(e){let n=`domain-${Date.now()}-${this.domainCounter++}`,r=e.delivered/e.totalSent*100,i=e.delivered>0?e.opened/e.delivered*100:0,s=e.delivered>0?e.clicked/e.delivered*100:0,a=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=i*0.4+s*0.6,d=Math.max(0,100-a*10-c*100+u*0.2),m={id:n,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:i,clickRate:s,bounceRate:a,complaintRate:c,engagementScore:u};return this.domainReputations.set(e.domain,m),m}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var oh=new td;class rd{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let n=`template-${Date.now()}-${this.templateCounter++}`,r=this.extractVariables(e.subject+e.htmlPart+e.textPart),i={id:n,variables:r,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(n,i),this.addVersion({templateId:n,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),i}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
|
|
3751
|
+
COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let u={sizeBefore:n.totalSize,sizeAfter:n.totalSize*0.6,timeBefore:300,timeAfter:120},d={id:r,name:`Optimization for ${n.imageId}`,recommendations:i,estimatedSavings:u};return this.optimizations.set(r,d),d}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var Kf=new Hl;class Wa{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let n=`registry-${Date.now()}-${this.registryCounter++}`,r={id:n,...e};return this.registries.set(n,r),r}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let n=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return n.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},n}enableReplication(e,n){let r=this.registries.get(e);if(!r)throw Error(`Registry not found: ${e}`);return r.replication={enabled:!0,destinations:n},r}createCredentials(e){let n=`creds-${Date.now()}-${this.credentialsCounter++}`,r={id:n,...e};return this.credentials.set(n,r),r}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((n)=>({Destinations:[{Region:n.region,...n.registryId&&{RegistryId:n.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var hp=new Wa;class Ka{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let n=`mesh-${Date.now()}-${this.meshCounter++}`,r={id:n,...e};return this.meshes.set(n,r),r}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let n=`vnode-${Date.now()}-${this.nodeCounter++}`,r={id:n,...e};return this.virtualNodes.set(n,r),r}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let n=`vrouter-${Date.now()}-${this.routerCounter++}`,r={id:n,...e};return this.virtualRouters.set(n,r),r}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let n=`vgateway-${Date.now()}-${this.gatewayCounter++}`,r={id:n,...e};return this.virtualGateways.set(n,r),r}createIngressGateway(e){let n={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)n.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[n],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(e){return this.meshes.get(e)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(e){return this.virtualNodes.get(e)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(e){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:e.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(e,n){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:n,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol},...r.healthCheck&&{HealthCheck:{Protocol:r.healthCheck.protocol,...r.healthCheck.path&&{Path:r.healthCheck.path},IntervalMillis:r.healthCheck.interval*1000,TimeoutMillis:r.healthCheck.timeout*1000,HealthyThreshold:r.healthCheck.healthyThreshold,UnhealthyThreshold:r.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,n){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:n,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol}}))}}}}clear(){this.meshes.clear(),this.virtualNodes.clear(),this.virtualRouters.clear(),this.virtualGateways.clear(),this.meshCounter=0,this.nodeCounter=0,this.routerCounter=0,this.gatewayCounter=0}}var yp=new Ka;class Gl{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let n=`layer-${Date.now()}-${this.layerCounter++}`,r=1,i={id:n,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(n,i),i}createNodeDependenciesLayer(e){return this.createLayer({layerName:e.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${e.nodeVersion}`],content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:5242880})}createUtilitiesLayer(e){return this.createLayer({layerName:e.layerName,description:"Shared utilities and helpers",compatibleRuntimes:e.runtimes,content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:1048576})}publishVersion(e){let n=this.layers.get(e);if(!n)throw Error(`Layer not found: ${e}`);let r=`version-${Date.now()}-${this.versionCounter++}`,i=n.version+1,s={id:r,layerName:n.layerName,version:i,createdAt:new Date,compatibleRuntimes:n.compatibleRuntimes,size:n.size,codeHash:this.generateHash()};return this.versions.set(r,s),n.version=i,n.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${i}`,s}addPermission(e){let n=`permission-${Date.now()}-${this.permissionCounter++}`,r={id:n,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(n,r),r}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((n)=>n.layerName===e)}generateLayerCF(e){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:e.layerName,Description:e.description,Content:e.content.type==="s3"?{S3Bucket:e.content.s3Bucket,S3Key:e.content.s3Key,...e.content.s3ObjectVersion&&{S3ObjectVersion:e.content.s3ObjectVersion}}:{ZipFile:e.content.zipFile},CompatibleRuntimes:e.compatibleRuntimes,...e.licenseInfo&&{LicenseInfo:e.licenseInfo}}}}generateLayerPermissionCF(e){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:${e.version}`,Action:e.action,Principal:e.principal,...e.organizationId&&{OrganizationId:e.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var Jf=new Gl;class ql{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let n=`version-${Date.now()}-${this.versionCounter++}`,r=this.getNextVersionNumber(e.functionName),i={id:n,functionName:e.functionName,version:r.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${r}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(n,i),i}getNextVersionNumber(e){let n=Array.from(this.versions.values()).filter((r)=>r.functionName===e).map((r)=>parseInt(r.version));return n.length>0?Math.max(...n)+1:1}createAlias(e){let n=`alias-${Date.now()}-${this.aliasCounter++}`,r={id:n,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(n,r),r}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.functionVersion=n,r.revisionId=this.generateHash(),r}configureWeightedRouting(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.routingConfig={additionalVersionWeights:n},r}createCanaryDeployment(e){let n=`deployment-${Date.now()}-${this.deploymentCounter++}`,r=Array.from(this.aliases.values()).find((s)=>s.functionName===e.functionName&&s.aliasName===e.aliasName);if(!r)r=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(r.id,{[e.toVersion]:e.canaryWeight});let i={id:n,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(n,i),i}completeDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.toVersion,r.routingConfig=void 0;return n.status="completed",n.completedAt=new Date,n}rollbackDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.fromVersion,r.routingConfig=void 0;return n.status="failed",n.completedAt=new Date,n}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let n=Array.from(this.versions.values());return e?n.filter((r)=>r.functionName===e):n}getAlias(e){return this.aliases.get(e)}listAliases(e){let n=Array.from(this.aliases.values());return e?n.filter((r)=>r.functionName===e):n}generateVersionCF(e){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:e.functionName,Description:e.description}}}generateAliasCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.aliasName,FunctionVersion:e.functionVersion,Description:e.description,...e.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(e.routingConfig.additionalVersionWeights||{}).map(([n,r])=>({FunctionVersion:n,FunctionWeight:r}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Xf=new ql;class Wl{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let n=`concurrency-${Date.now()}-${this.configCounter++}`,r={id:n,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(n,r),r}setProvisionedConcurrency(e){let n=`provisioned-${Date.now()}-${this.provisionedCounter++}`,r={id:n,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(n,r),setTimeout(()=>{r.status="ready",r.allocatedConcurrency=e.provisionedConcurrentExecutions,r.availableConcurrency=e.provisionedConcurrentExecutions},100),r}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let n=`schedule-${Date.now()}-${this.scheduleCounter++}`,r={id:n,...e};return this.schedules.set(n,r),r}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let n=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,r={id:n,...e};return this.autoScalingConfigs.set(n,r),r}configurePredictiveScaling(e){return this.configureAutoScaling({functionName:e.functionName,qualifier:e.qualifier,minCapacity:e.baselineCapacity,maxCapacity:e.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(e){return this.provisionedConfigs.get(e)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,ReservedConcurrentExecutions:e.reservedConcurrency}}}generateProvisionedConcurrencyCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:e.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${e.functionName}:${e.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:e.minCapacity,MaxCapacity:e.maxCapacity}}}generateAutoScalingPolicyCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${e.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:e.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:e.scaleInCooldown||300,ScaleOutCooldown:e.scaleOutCooldown||60}}}}clear(){this.configs.clear(),this.provisionedConfigs.clear(),this.schedules.clear(),this.autoScalingConfigs.clear(),this.configCounter=0,this.provisionedCounter=0,this.scheduleCounter=0,this.autoScalingCounter=0}}var Qf=new Wl;class Kl{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let n=`destination-${Date.now()}-${this.destinationCounter++}`,r={id:n,...e};return this.destinations.set(n,r),r}configureSQSDestination(e){let n={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let n={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let n={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let n={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(e){return this.configureDestinations({functionName:e.functionName,failureDestination:{type:"sqs",arn:e.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(e){let n=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,r={id:n,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(n,r),r}sendToDestination(e){let n=Array.from(this.destinations.values()).find((a)=>a.functionName===e.functionName);if(!n)return null;let r=e.status==="success"?n.successDestination:n.failureDestination;if(!r)return null;let i=`record-${Date.now()}-${this.recordCounter++}`,s={id:i,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:r.type,destinationArn:r.arn,payload:e.payload,error:e.error};return this.records.set(i,s),s}getDestination(e){return this.destinations.get(e)}listDestinations(e){let n=Array.from(this.destinations.values());return e?n.filter((r)=>r.functionName===e):n}getDestinationRecords(e){let n=Array.from(this.records.values());return e?n.filter((r)=>r.functionName===e):n}generateEventInvokeConfigCF(e){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:e.functionName,Qualifier:e.qualifier||"$LATEST",MaximumEventAgeInSeconds:e.maxEventAge||21600,MaximumRetryAttempts:e.maxRetries??2,...e.successDestination&&{DestinationConfig:{OnSuccess:{Destination:e.successDestination.arn}}},...e.failureDestination&&{DestinationConfig:{OnFailure:{Destination:e.failureDestination.arn}}}}}}generateEventBridgeRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{EventBusName:e.eventBusArn.split("/").pop(),EventPattern:{source:[e.source],"detail-type":[e.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}`,Id:e.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var Yf=new Kl;class Jl{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let n=`vpc-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};this.vpcConfigs.set(n,r);for(let i of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:i});return r}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,...e};return this.endpoints.set(n,r),r}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let n=`eni-${Date.now()}-${this.eniCounter++}`,r={id:n,functionName:e.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:e.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(n,r),setTimeout(()=>{r.status="available"},100),r}analyzeConnectivity(e){let n=`connectivity-${Date.now()}-${this.connectivityCounter++}`,r=Array.from(this.vpcConfigs.values()).find((d)=>d.functionName===e.functionName),i=Array.from(this.endpoints.values()).filter((d)=>d.vpcId===r?.vpcId).map((d)=>d.serviceName),s=[],a=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!a&&!c)s.push("Add NAT Gateway for internet access");if(!i.includes("com.amazonaws.us-east-1.s3"))s.push("Add S3 VPC endpoint to reduce NAT costs");if(!i.includes("com.amazonaws.us-east-1.dynamodb"))s.push("Add DynamoDB VPC endpoint for private access");let u={id:n,functionName:e.functionName,hasInternetAccess:a||c,hasNATGateway:a,hasVPCEndpoints:i.length>0,endpoints:i,recommendations:s};return this.connectivity.set(n,u),u}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let n=Array.from(this.vpcConfigs.values());return e?n.filter((r)=>r.functionName===e):n}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((n)=>n.functionName===e)}listVPCEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.vpcId===e):n}generateVPCConfigCF(e){return{VpcConfig:{SubnetIds:e.subnetIds,SecurityGroupIds:e.securityGroupIds,...e.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(e){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:e.vpcId,ServiceName:e.serviceName,VpcEndpointType:e.endpointType,...e.subnetIds&&{SubnetIds:e.subnetIds},...e.securityGroupIds&&{SecurityGroupIds:e.securityGroupIds},...e.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:e.privateDnsEnabled}}}}generateSecurityGroupCF(e){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:e.groupName,GroupDescription:`Security group for Lambda ${e.groupName}`,VpcId:e.vpcId,...e.ingressRules&&{SecurityGroupIngress:e.ingressRules.map((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,...n.cidrIp&&{CidrIp:n.cidrIp},...n.sourceSecurityGroupId&&{SourceSecurityGroupId:n.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,CidrIp:n.cidrIp||"0.0.0.0/0"}))}}}}clear(){this.vpcConfigs.clear(),this.endpoints.clear(),this.networkInterfaces.clear(),this.connectivity.clear(),this.configCounter=0,this.endpointCounter=0,this.eniCounter=0,this.connectivityCounter=0}}var Zf=new Jl;class Xl{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let n=`dlq-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.dlqConfigs.set(n,r),r}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let n=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:n.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),n}sendToDLQ(e){let n=`message-${Date.now()}-${this.messageCounter++}`,r={id:n,timestamp:new Date,...e};return this.messages.set(n,r),r}createDLQAlarm(e){let n=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:n,...e};return this.alarms.set(n,r),r}createAgeAlarm(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${n.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let n=this.messages.get(e);if(!n)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((a)=>a.functionName===n.functionName);if(!r)throw Error(`DLQ config not found for function: ${n.functionName}`);let i=`reprocess-${Date.now()}-${this.reprocessCounter++}`,s={id:i,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(i,s),setTimeout(()=>{s.status="processing",setTimeout(()=>{let a=Math.random()>0.3;if(s.status=a?"success":"failed",s.completedAt=new Date,!a)s.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),s}async batchReprocess(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let i=Array.from(this.messages.values()).filter((s)=>s.functionName===n.functionName).slice(0,e.maxMessages||10).map((s)=>this.reprocessMessage(s.id));return Promise.all(i)}getDLQStats(e){let n=this.dlqConfigs.get(e);if(!n)throw Error(`DLQ config not found: ${e}`);let r=Array.from(this.messages.values()).filter((c)=>c.functionName===n.functionName),i={},s=0;for(let c of r)i[c.errorType]=(i[c.errorType]||0)+1,s+=c.attemptCount;let a=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:a.length>0?new Date(Math.min(...a.map((c)=>c.getTime()))):void 0,newestMessage:a.length>0?new Date(Math.max(...a.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?s/r.length:0,errorTypes:i}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let n=this.dlqConfigs.get(e);if(!n)return[];return Array.from(this.messages.values()).filter((r)=>r.functionName===n.functionName)}generateDLQCF(e){return{DeadLetterConfig:{TargetArn:e.targetArn}}}generateSQSDLQCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${e.functionName}-dlq`,MessageRetentionPeriod:e.retentionPeriod||1209600,...e.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:e.targetArn,maxReceiveCount:e.maxReceiveCount}}}}}generateDLQAlarmCF(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${n.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.targetArn.split(":").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.notificationTopicArn]}}}}clear(){this.dlqConfigs.clear(),this.messages.clear(),this.alarms.clear(),this.reprocessing.clear(),this.configCounter=0,this.messageCounter=0,this.alarmCounter=0,this.reprocessCounter=0}}var eh=new Xl;class Ja{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"weighted",...e};return this.policies.set(n,r),r}createLatencyPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"latency",...e};return this.policies.set(n,r),r}createFailoverPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"failover",...e};return this.policies.set(n,r),r}createGeolocationPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geolocation",...e};return this.policies.set(n,r),r}createGeoproximityPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geoproximity",...e};return this.policies.set(n,r),r}createHTTPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:e.port===443?"https":"http",requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",port:e.port||(e.port===443?443:80),...e};return this.healthChecks.set(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),r}createTCPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),r}createCalculatedHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{let s=e.childHealthChecks.filter((a)=>this.healthChecks.get(a)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=s>=e.healthThreshold?"Healthy":"Unhealthy"},150),r}createTrafficPolicy(e){let n=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,r={id:n,version:1,...e};return this.trafficPolicies.set(n,r),r}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let n={},r=[];return e.locations.forEach((i,s)=>{let a=`endpoint${s}`;n[a]={type:"value",value:i.endpoint},r.push({endpointReference:a,region:i.region,latitude:i.latitude,longitude:i.longitude,bias:i.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:n,rules:{geoproximity:{ruleType:"geoproximity",locations:r}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let n={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let r=e;n.Properties.HealthCheckConfig.ChildHealthChecks=r.childHealthChecks,n.Properties.HealthCheckConfig.HealthThreshold=r.healthThreshold}else{if(e.ipAddress)n.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)n.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)n.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)n.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)n.Properties.HealthCheckConfig.EnableSNI=!0}return n}generateWeightedRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Weight:e.weight,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}generateFailoverRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Failover:e.failover,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var bp=new Ja;class Ql{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let n=`dnssec-${Date.now()}-${this.configCounter++}`,r={id:n,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(n,r),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{r.status="SIGNED",r.signingStatus="DNSSEC signing complete"},100),r}disableDNSSEC(e){let n=this.configs.get(e);if(!n)throw Error(`DNSSEC config not found: ${e}`);return n.status="DELETING",n.signingStatus="Removing DNSSEC signing",setTimeout(()=>{n.status="NOT_SIGNING",n.signingStatus="DNSSEC signing removed"},100),n}createKSK(e){let n=`ksk-${Date.now()}-${this.kskCounter++}`,r={id:n,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};r.dnskeyRecord=`${r.flag} 3 8 ${r.publicKey}`;let i=this.generateDigest(r.dnskeyRecord);return r.digestValue=i,r.dsRecord=`${r.keyTag} 8 ${r.digestAlgorithm} ${i}`,this.ksks.set(n,r),r}deactivateKSK(e){let n=this.ksks.get(e);if(!n)throw Error(`KSK not found: ${e}`);return n.status="INACTIVE",n}validateDNSSEC(e){let n=`validation-${Date.now()}-${this.validationCounter++}`,r=e.checkDNSKEY!==!1?Math.random()>0.1:!1,i=e.checkRRSIG!==!1?Math.random()>0.1:!1,s=r&&i,a=[];if(!r)a.push("DNSKEY record not found");if(!i)a.push("RRSIG record not found");let c;if(!r&&!i)c="INSECURE";else if(r&&i&&s)c="VALID";else if(r||i)c="BOGUS",a.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:n,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:i,validSignature:s,errors:a};return this.validations.set(n,u),u}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let n=Array.from(this.ksks.values());return e?n.filter((r)=>r.hostedZoneId===e):n}getDSRecord(e){let n=this.ksks.get(e);if(!n||!n.dsRecord)throw Error("DS record not available");return n.dsRecord}generatePublicKey(){let n="";for(let r=0;r<256;r++)n+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return n}generateDigest(e){let r="";for(let i=0;i<64;i++)r+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return r}generateDNSSECCF(e){return{Type:"AWS::Route53::DNSSEC",Properties:{HostedZoneId:e.hostedZoneId}}}generateKSKCF(e){return{Type:"AWS::Route53::KeySigningKey",Properties:{Name:e.name,HostedZoneId:e.hostedZoneId,KeyManagementServiceArn:e.keyManagementServiceArn,Status:e.status}}}clear(){this.configs.clear(),this.ksks.clear(),this.validations.clear(),this.configCounter=0,this.kskCounter=0,this.validationCounter=0}}var th=new Ql;class Yl{endpoints=new Map;rules=new Map;firewalls=new Map;ruleGroups=new Map;domainLists=new Map;endpointCounter=0;ruleCounter=0;firewallCounter=0;ruleGroupCounter=0;domainListCounter=0;createResolverEndpoint(e){let n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,status:"CREATING",...e};return this.endpoints.set(n,r),setTimeout(()=>{r.status="OPERATIONAL",r.ipAddresses.forEach((i)=>{if(!i.ip)i.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),r}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let n=`rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,status:"CREATING",...e};return this.rules.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let n=`domain-list-${Date.now()}-${this.domainListCounter++}`,r={id:n,status:"CREATING",...e};return this.domainLists.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createFirewallRuleGroup(e){let n=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,r={id:n,name:e.name,rules:e.rules.map((i,s)=>({id:`rule-${n}-${s}`,...i})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(n,r),r}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let n=`firewall-${Date.now()}-${this.firewallCounter++}`,r={id:n,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((i,s)=>({id:`assoc-${n}-${s}`,vpcId:e.vpcId,firewallRuleGroupId:i.firewallRuleGroupId,priority:i.priority,mutationProtection:i.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(n,r),r}createMalwareProtectionFirewall(e){let n=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),r=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:n.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:r.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.direction===e):n}getRule(e){return this.rules.get(e)}listRules(){return Array.from(this.rules.values())}getFirewall(e){return this.firewalls.get(e)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(e){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:e.name,Direction:e.direction,IpAddresses:e.ipAddresses.map((n)=>({SubnetId:n.subnetId,...n.ip&&{Ip:n.ip}})),SecurityGroupIds:e.securityGroupIds}}}generateResolverRuleCF(e){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:e.name,RuleType:e.ruleType,DomainName:e.domainName,...e.targetIps&&{TargetIps:e.targetIps.map((n)=>({Ip:n.ip,Port:n.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((n)=>({Name:n.name,Priority:n.priority,Action:n.action,FirewallDomainListId:n.firewallDomainListId,...n.blockResponse&&{BlockResponse:n.blockResponse},...n.blockOverrideDomain&&{BlockOverrideDomain:n.blockOverrideDomain},...n.blockOverrideTTL&&{BlockOverrideTtl:n.blockOverrideTTL}}))}}}clear(){this.endpoints.clear(),this.rules.clear(),this.firewalls.clear(),this.ruleGroups.clear(),this.domainLists.clear(),this.endpointCounter=0,this.ruleCounter=0,this.firewallCounter=0,this.ruleGroupCounter=0,this.domainListCounter=0}}var rh=new Yl;class Zl{bounces=new Map;complaints=new Map;handlers=new Map;suppressionList=new Map;metrics=new Map;bounceCounter=0;complaintCounter=0;handlerCounter=0;suppressionCounter=0;metricsCounter=0;recordBounce(e){let n=`bounce-${Date.now()}-${this.bounceCounter++}`,r={id:n,...e};if(this.bounces.set(n,r),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return r}recordComplaint(e){let n=`complaint-${Date.now()}-${this.complaintCounter++}`,r={id:n,...e};this.complaints.set(n,r);for(let i of e.recipients)this.addToSuppressionList({emailAddress:i,reason:"COMPLAINT"});return r}createBounceHandler(e){let n=`handler-${Date.now()}-${this.handlerCounter++}`,r={id:n,...e};return this.handlers.set(n,r),r}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let n=`suppression-${Date.now()}-${this.suppressionCounter++}`,r=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,i={id:n,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:r,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,i),i}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let n=this.suppressionList.get(e);if(!n)return!1;if(n.expiresAt&&n.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,n){let r=Array.from(this.bounces.values()).filter((p)=>p.timestamp>=e&&p.timestamp<=n),i=r.length,s=r.filter((p)=>p.bounceType==="Permanent").length,a=r.filter((p)=>p.bounceType==="Transient").length,c=i*10,u=i/c*100,d=new Map;for(let p of r)d.set(p.recipient,(d.get(p.recipient)||0)+1);let m=Array.from(d.entries()).map(([p,g])=>({email:p,count:g})).sort((p,g)=>g.count-p.count).slice(0,10);return{totalBounces:i,permanentBounces:s,transientBounces:a,bounceRate:u,topRecipients:m}}getComplaintStatistics(e,n){let r=Array.from(this.complaints.values()).filter((d)=>d.timestamp>=e&&d.timestamp<=n),i=r.length,s=new Set;for(let d of r)for(let m of d.recipients)s.add(m);let a=s.size,c=i*1000,u=i/c*100;return{totalComplaints:i,uniqueComplainters:a,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,n=new Date,r=new Date(n.getTime()-86400000),i=this.getBounceStatistics(r,n),s=this.getComplaintStatistics(r,n),a;if(i.bounceRate>10||s.complaintRate>0.5)a="Shutdown";else if(i.bounceRate>5||s.complaintRate>0.1)a="Probation";else if(i.bounceRate>2||s.complaintRate>0.05)a="Warning";else a="Good";let c={id:e,timestamp:n,bounceRate:i.bounceRate,complaintRate:s.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:i.totalBounces*10,reputationStatus:a};return this.metrics.set(e,c),c}getBounces(e){let n=Array.from(this.bounces.values());return e?n.filter((r)=>r.messageId===e):n}getComplaints(e){let n=Array.from(this.complaints.values());return e?n.filter((r)=>r.messageId===e):n}listSuppressionList(e){let n=Array.from(this.suppressionList.values());return e?n.filter((r)=>r.reason===e):n}generateSNSSubscriptionCF(e){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:e.topicArn,Endpoint:e.endpoint,Protocol:e.protocol}}}generateEventDestinationCF(e){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:e.configurationSetName,EventDestination:{Name:e.eventDestinationName,Enabled:!0,MatchingEventTypes:e.eventTypes,...e.snsTopicArn&&{SnsDestination:{TopicARN:e.snsTopicArn}},...e.cloudWatchDestination&&{CloudWatchDestination:e.cloudWatchDestination}}}}}clear(){this.bounces.clear(),this.complaints.clear(),this.handlers.clear(),this.suppressionList.clear(),this.metrics.clear(),this.bounceCounter=0,this.complaintCounter=0,this.handlerCounter=0,this.suppressionCounter=0,this.metricsCounter=0}}var nh=new Zl;class ed{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let n=`event-${Date.now()}-${this.eventCounter++}`,r={id:n,...e};if(this.events.set(n,r),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return r}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let n=`campaign-${Date.now()}-${this.campaignCounter++}`,r={id:n,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(n,r),r}updateCampaignStats(e,n){let r=this.campaigns.get(e);if(!r)return;switch(n){case"send":r.sentCount++;break;case"delivery":r.deliveredCount++;break;case"open":r.openCount++;break;case"click":r.clickCount++;break;case"bounce":r.bounceCount++;break;case"complaint":r.complaintCount++;break}}generateReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r=Array.from(this.events.values()).filter((v)=>{let w=v.timestamp>=e.startDate&&v.timestamp<=e.endDate,D=!e.campaignId||v.tags?.campaignId===e.campaignId;return w&&D}),i=r.filter((v)=>v.eventType==="send").length,s=r.filter((v)=>v.eventType==="delivery").length,a=r.filter((v)=>v.eventType==="open").length,c=r.filter((v)=>v.eventType==="click").length,u=r.filter((v)=>v.eventType==="bounce").length,d=r.filter((v)=>v.eventType==="complaint").length,m=i>0?s/i*100:0,p=s>0?a/s*100:0,g=s>0?c/s*100:0,y=a>0?c/a*100:0,f=i>0?u/i*100:0,h=s>0?d/s*100:0,S=new Map;for(let v of r)if(v.eventType==="click"){let w=v;S.set(w.link,(S.get(w.link)||0)+1)}let C=Array.from(S.entries()).map(([v,w])=>({link:v,clicks:w})).sort((v,w)=>w.clicks-v.clicks).slice(0,10),P={desktop:0,mobile:0,tablet:0,unknown:0};for(let v of r)if(v.eventType==="open"||v.eventType==="click"){let w=v.userAgent.toLowerCase();if(w.includes("mobile"))P.mobile++;else if(w.includes("tablet"))P.tablet++;else if(w.includes("mozilla"))P.desktop++;else P.unknown++}let E={id:n,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:i,totalDelivered:s,totalOpened:a,totalClicked:c,totalBounced:u,totalComplaints:d,deliveryRate:m,openRate:p,clickRate:g,clickToOpenRate:y,bounceRate:f,complaintRate:h,topLinks:C,deviceBreakdown:P,locationBreakdown:{}};return this.reports.set(n,E),E}createABTest(e){let n=`abtest-${Date.now()}-${this.abTestCounter++}`,r={id:n,name:e.name,variants:e.variants.map((i,s)=>({id:`variant-${n}-${s}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...i})),status:"draft"};return this.abTests.set(n,r),r}startABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);return n.status="running",n.startedAt=new Date,n}completeABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);let r=n.variants[0],i=0;for(let s of n.variants){let a=s.sentCount>0?s.openCount/s.sentCount:0;if(a>i)i=a,r=s}return n.status="completed",n.completedAt=new Date,n.winner=r.id,n}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let n=Array.from(this.events.values());if(e?.messageId)n=n.filter((r)=>r.messageId===e.messageId);if(e?.eventType)n=n.filter((r)=>r.eventType===e.eventType);if(e?.startDate)n=n.filter((r)=>r.timestamp>=e.startDate);if(e?.endDate)n=n.filter((r)=>r.timestamp<=e.endDate);return n}generateTrackingConfigurationCF(e){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:e.configurationSetName,...e.openTracking&&{TrackingOptions:{CustomRedirectDomain:"tracking.example.com"}}}}}clear(){this.events.clear(),this.campaigns.clear(),this.reports.clear(),this.abTests.clear(),this.eventCounter=0,this.campaignCounter=0,this.reportCounter=0,this.abTestCounter=0}}var ih=new ed;class td{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,n=Math.random()*5,r=Math.random()*0.5,i=Math.floor(Math.random()*10),s=Math.max(0,100-n*10-r*100-i*2),a=[];if(n>2)a.push("Reduce bounce rate by cleaning email list");if(r>0.1)a.push("Review email content and unsubscribe process");if(i>5)a.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:s,bounceRate:n,complaintRate:r,spamReports:i,blacklistStatus:this.checkBlacklists(),dkimStatus:"VERIFIED",spfStatus:"PASS",dmarcStatus:"PASS",sendingLimits:{maxSendRate:14,max24HourSend:50000,sentLast24Hours:12000,remainingQuota:38000,quotaResetTime:new Date(Date.now()+86400000)},recommendations:a};return this.dashboards.set(e,c),c}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((n)=>({listName:n,listed:Math.random()>0.95,delistUrl:`https://www.${n.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let n=`warmup-${Date.now()}-${this.warmupCounter++}`,r=[],i=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let a=0;a<e.durationDays;a++)r.push(Math.floor(e.initialDailyLimit+i*a));let s={id:n,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:r,currentLimit:r[0],status:"active"};return this.warmupPlans.set(n,s),s}createAggressiveWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(e){let n=this.warmupPlans.get(e);if(!n)throw Error(`Warmup plan not found: ${e}`);if(n.currentDay<n.totalDays)n.currentDay++,n.currentLimit=n.dailyLimits[n.currentDay-1];if(n.currentDay>=n.totalDays)n.status="completed";return n}trackDomainReputation(e){let n=`domain-${Date.now()}-${this.domainCounter++}`,r=e.delivered/e.totalSent*100,i=e.delivered>0?e.opened/e.delivered*100:0,s=e.delivered>0?e.clicked/e.delivered*100:0,a=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=i*0.4+s*0.6,d=Math.max(0,100-a*10-c*100+u*0.2),m={id:n,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:i,clickRate:s,bounceRate:a,complaintRate:c,engagementScore:u};return this.domainReputations.set(e.domain,m),m}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var oh=new td;class rd{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let n=`template-${Date.now()}-${this.templateCounter++}`,r=this.extractVariables(e.subject+e.htmlPart+e.textPart),i={id:n,variables:r,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(n,i),this.addVersion({templateId:n,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),i}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
|
|
3752
3752
|
<html>
|
|
3753
3753
|
<body>
|
|
3754
3754
|
<h1>Welcome, {{userName}}!</h1>
|
|
@@ -7248,7 +7248,7 @@ export const queue = __handlers.queue
|
|
|
7248
7248
|
export const cli = __handlers.cli
|
|
7249
7249
|
`}import{execSync as bs}from"node:child_process";import{createHash as Ss}from"node:crypto";import{cpSync as As,mkdtempSync as Cs,rmSync as vs,writeFileSync as Ts}from"node:fs";import{tmpdir as Rs}from"node:os";import{dirname as Ps,isAbsolute as Es,join as xe,resolve as ws}from"node:path";import{fileURLToPath as Is}from"node:url";var Ds=["adapter.ts","recursion.ts","auto-recursion.ts"];function Ns(){return xe(Ps(Is(import.meta.url)),"runtime")}function Sp(e,n,r){for(let i of e??[])r?.(`build: ${i}`),bs(i,{stdio:"inherit",cwd:n})}function is(e){return Ss("sha256").update(e).digest("hex")}function Xa(e,n,r){return`deployments/${e}/${n}/${r}.zip`}async function Dn(e){let n=ws(e.projectRoot??process.cwd()),{app:r}=e;if(!e.skipBuild)Sp(r.build,n,e.onStep);let i=r.entry;if(!i)throw Error("serverless app: `entry` is required to package a Node/Bun application");let s=Es(i)?i:xe(n,i),a=Cs(xe(Rs(),"tscloud-pkg-"));try{for(let y of Ds)As(xe(Ns(),y),xe(a,y));let c=xe(a,"bootstrap.ts");Ts(c,ud({entryImport:s,adapterImport:"./adapter"})),e.onStep?.("bundling application");let u=await Bun.build({entrypoints:[c],target:r.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!u.success){let y=u.logs.map((f)=>String(f)).join(`
|
|
7250
7250
|
`);throw Error(`serverless app bundle failed:
|
|
7251
|
-
${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=xt([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:is(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{vs(a,{recursive:!0,force:!0})}}var vp=["18","20","22"];function xs(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function Ki(e){let n=e.kind??"node";if(n==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(n==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=xs(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&vp.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function tr(e,n,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${n}-${r}-default`}];return e.queues.map((i)=>{if(typeof i==="string")return{name:`${n}-${r}-${i}`};let[s,a]=Object.entries(i)[0];return{name:`${n}-${r}-${s}`,concurrency:a}})}function Qa(e,n,r){return tr(e,n,r).map((i)=>i.name)}function Ya(e){let{app:n,environment:r,handlers:i}=e,s=e.config.project.slug,a=Ki(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${s}-${r}-http`,queue:`${s}-${r}-queue`,cli:`${s}-${r}-cli`};if(n.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let m=tr(n,s,r),p=m.map((k)=>k.name),g=p.length>0,y=n.logRetention??14,f=n.packaging==="image";if(f&&n.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let h=(n.scheduler??"on")!=="off",S=(n.cache?.driver??"dynamodb")==="dynamodb",C=Boolean(n.assets),E=Bi(s,r),w=n.tmpStorage??512,v={},I={},D=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:t.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${s}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${s}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${s}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${E}`),t.sub(`arn:aws:s3:::${E}/*`),...n.storage?.bucket?[t.sub(`arn:aws:s3:::${n.storage.bucket}`),t.sub(`arn:aws:s3:::${n.storage.bucket}/*`)]:[]]}]}}];if(g)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${s}-${r}-*`)});if(S)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${s}-${r}-cache*`)});let x=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)x.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)x.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");v.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${s}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:x,Policies:D}};let L=(k)=>({TSCLOUD_LAMBDA_MODE:k,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${s}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),B=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},F=O.mountPath??"/mnt/local",V=B&&!O.accessPointArn,ce=O.accessPointArn??(V?t.getAtt("EfsAccessPoint","Arn"):void 0),q=n.vpc?.subnets??[],J=q.length>0,K=n.cache?.driver==="elasticache"||n.database?.connection==="aurora-serverless"||Boolean(n.rdsProxy)||B;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Q=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ge=V?q.map((k,G)=>`EfsMountTarget${G}`):[],Te=B?{FileSystemConfigs:[{Arn:ce,LocalMountPath:F}]}:{};if(B)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function te(k,G,W,_,ee,mt,Be,he=w){v[`${k}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${G}`,RetentionInDays:y}};let Fe=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],en=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[W]}}}:{Runtime:a,Handler:W,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Fe.length?{Layers:[...new Set(Fe)]}:{}};v[k]={Type:"AWS::Lambda::Function",DependsOn:[`${k}LogGroup`,...ge],Properties:{FunctionName:G,Architectures:[c],MemorySize:ee,Timeout:mt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:L(_)},EphemeralStorage:{Size:he},...en,...Be!==void 0?{ReservedConcurrentExecutions:Be}:{},...Q,...Te}}}if(te("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,w),te("CliFunction",d.cli,i.cli,"cli",n.cliMemory??1024,n.cliTimeout??900,void 0,n.cliTmpStorage??w),g)te("QueueFunction",d.queue,i.queue,"queue",n.queueMemory??1024,n.queueTimeout??120,void 0,n.queueTmpStorage??w);let Z=(n.provisionedConcurrency??0)>0?n.provisionedConcurrency:0,re=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(Z)for(let k of re)v[`${k}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(k)}},v[`${k}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(k),Name:"live",FunctionVersion:t.getAtt(`${k}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Z}}};let fe=(k)=>Z?t.ref(`${k}Alias`):t.getAtt(k,"Arn"),se=(k)=>Z?t.ref(`${k}Alias`):t.ref(k);v.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${s}-${r}`,ProtocolType:"HTTP"}},v.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},v.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},v.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},v.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:se("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},I.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},I.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ue=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(ue.length){if(!n.certificateArn&&!n.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let k=n.certificateArn;if(!k)v.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ue[0],...ue.length>1?{SubjectAlternativeNames:ue.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ue.map((G)=>({DomainName:G,HostedZoneId:n.hostedZoneId}))}},k=t.ref("HttpCertificate");ue.forEach((G,W)=>{let _=`HttpDomain${W}`;if(v[_]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:G,DomainNameConfigurations:[{CertificateArn:k,EndpointType:"REGIONAL"}]}},v[`HttpApiMapping${W}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(_),Stage:"$default"}},n.hostedZoneId)v[`HttpDomainRecord${W}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:G,Type:"A",AliasTarget:{DNSName:t.getAtt(_,"RegionalDomainName"),HostedZoneId:t.getAtt(_,"RegionalHostedZoneId")}}};I[`CustomDomain${W}`]={Description:`Custom domain ${G}`,Value:G},I[`CustomDomainTarget${W}`]={Description:`Point ${G} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(_,"RegionalDomainName")}})}if(g)v.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${s}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((k,G)=>{let W=`AppQueue${G}`,_=n.queueTimeout??120;v[W]={Type:"AWS::SQS::Queue",Properties:{QueueName:k.name,VisibilityTimeout:Math.min(43200,_*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let ee=k.concurrency??n.queueConcurrency;v[`${W}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(W,"Arn"),FunctionName:se("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ee?{ScalingConfig:{MaximumConcurrency:Math.max(2,ee)}}:{}}},I[`QueueUrl${G}`]={Description:`Queue URL: ${k.name}`,Value:t.ref(W)}});if(h)v.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},v.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:se("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(n.warm&&n.warm>0){let G={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},W=(n.warmFunctions??["http"]).filter((_)=>_!=="queue"||g);for(let _ of W){let ee=_.charAt(0).toUpperCase()+_.slice(1),mt=Math.ceil(n.warm/5),Be=0;for(let he=0;he<mt;he++){let Fe=Math.min(5,n.warm-Be);v[`Warmer${ee}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-warmer-${_}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Fe},(en,lr)=>({Id:`warm-${_}-${he}-${lr}`,Arn:t.getAtt(G[_],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Be+=Fe}v[`Warmer${ee}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(G[_]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${s}-${r}-warmer-${_}-*`)}}}}if(S)v.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},I.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(C){if(v.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:E,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},v.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${s}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},v.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...n.assetDomain?{Aliases:[n.assetDomain],ViewerCertificate:{AcmCertificateArn:n.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},n.assetDomain){if(!n.assetCertificateArn){if(!n.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(u!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);v.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)v.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};I.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}v.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${E}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},I.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},I.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(n.firewall?.enabled){let k=[],G=0;if(n.firewall.rateLimit)k.push({Name:"rate-limit",Priority:G++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-rate`}});let W={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let _ of n.firewall.rules??[]){let ee=W[_];if(!ee)continue;k.push({Name:`managed-${_}`,Priority:G++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ee}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-${_}`}})}v.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${s}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:k,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-waf`}}},I.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:t.getAtt("WebAcl","Arn")}}if(J&&K){if(!n.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");v.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${s}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(V)v.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${s}-${r}-efs`}]}},q.forEach((k,G)=>{v[`EfsMountTarget${G}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:k,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),v.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},I.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")v.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${s}-${r} cache subnets`,SubnetIds:q}},v.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${s}-${r}-cache`,ReplicationGroupDescription:`${s}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},I.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")v.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${s}-${r} db subnets`,SubnetIds:q}},v.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${s}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},v.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${s}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:n.database?.minCapacity??0.5,MaxCapacity:n.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},v.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},I.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")v.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},v.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${s}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},v.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},I.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(I.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},I.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)I.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${s}-${r})`,Parameters:f?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:v,Outputs:I},Oe={};for(let k of Object.values(v))Oe[k.Type]=(Oe[k.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Oe}}var Cp=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Tp(e){let n=`php${e.replace(".","")}`;return Cp.map((r)=>`${n}-php-${r}`)}function Za(e,n){let r=`php${e.replace(".","")}`,i=Tp(e).join(" \\\n "),s=`/opt/remi/${r}/root`,a=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
|
|
7251
|
+
${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=xt([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:is(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{vs(a,{recursive:!0,force:!0})}}var vp=["18","20","22"];function xs(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function Ki(e){let n=e.kind??"node";if(n==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(n==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=xs(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&vp.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function tr(e,n,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${n}-${r}-default`}];return e.queues.map((i)=>{if(typeof i==="string")return{name:`${n}-${r}-${i}`};let[s,a]=Object.entries(i)[0];return{name:`${n}-${r}-${s}`,concurrency:a}})}function Qa(e,n,r){return tr(e,n,r).map((i)=>i.name)}function Ya(e){let{app:n,environment:r,handlers:i}=e,s=e.config.project.slug,a=Ki(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${s}-${r}-http`,queue:`${s}-${r}-queue`,cli:`${s}-${r}-cli`};if(n.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let m=tr(n,s,r),p=m.map((k)=>k.name),g=p.length>0,y=n.logRetention??14,f=n.packaging==="image";if(f&&n.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let h=(n.scheduler??"on")!=="off",S=(n.cache?.driver??"dynamodb")==="dynamodb",C=Boolean(n.assets),P=Bi(s,r),E=n.tmpStorage??512,v={},w={},D=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:t.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${s}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${s}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${s}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${P}`),t.sub(`arn:aws:s3:::${P}/*`),...n.storage?.bucket?[t.sub(`arn:aws:s3:::${n.storage.bucket}`),t.sub(`arn:aws:s3:::${n.storage.bucket}/*`)]:[]]}]}}];if(g)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${s}-${r}-*`)});if(S)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${s}-${r}-cache*`)});let x=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)x.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)x.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");v.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${s}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:x,Policies:D}};let L=(k)=>({TSCLOUD_LAMBDA_MODE:k,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${s}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),B=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},F=O.mountPath??"/mnt/local",V=B&&!O.accessPointArn,ce=O.accessPointArn??(V?t.getAtt("EfsAccessPoint","Arn"):void 0),q=n.vpc?.subnets??[],J=q.length>0,K=n.cache?.driver==="elasticache"||n.database?.connection==="aurora-serverless"||Boolean(n.rdsProxy)||B;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Q=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ge=V?q.map((k,G)=>`EfsMountTarget${G}`):[],Te=B?{FileSystemConfigs:[{Arn:ce,LocalMountPath:F}]}:{};if(B)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function te(k,G,W,_,ee,mt,Be,he=E){v[`${k}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${G}`,RetentionInDays:y}};let Fe=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],en=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[W]}}}:{Runtime:a,Handler:W,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Fe.length?{Layers:[...new Set(Fe)]}:{}};v[k]={Type:"AWS::Lambda::Function",DependsOn:[`${k}LogGroup`,...ge],Properties:{FunctionName:G,Architectures:[c],MemorySize:ee,Timeout:mt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:L(_)},EphemeralStorage:{Size:he},...en,...Be!==void 0?{ReservedConcurrentExecutions:Be}:{},...Q,...Te}}}if(te("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,E),te("CliFunction",d.cli,i.cli,"cli",n.cliMemory??1024,n.cliTimeout??900,void 0,n.cliTmpStorage??E),g)te("QueueFunction",d.queue,i.queue,"queue",n.queueMemory??1024,n.queueTimeout??120,void 0,n.queueTmpStorage??E);let Z=(n.provisionedConcurrency??0)>0?n.provisionedConcurrency:0,re=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(Z)for(let k of re)v[`${k}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(k)}},v[`${k}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(k),Name:"live",FunctionVersion:t.getAtt(`${k}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Z}}};let fe=(k)=>Z?t.ref(`${k}Alias`):t.getAtt(k,"Arn"),se=(k)=>Z?t.ref(`${k}Alias`):t.ref(k);v.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${s}-${r}`,ProtocolType:"HTTP"}},v.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},v.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},v.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},v.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:se("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},w.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},w.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ue=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(ue.length){if(!n.certificateArn&&!n.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let k=n.certificateArn;if(!k)v.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ue[0],...ue.length>1?{SubjectAlternativeNames:ue.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ue.map((G)=>({DomainName:G,HostedZoneId:n.hostedZoneId}))}},k=t.ref("HttpCertificate");ue.forEach((G,W)=>{let _=`HttpDomain${W}`;if(v[_]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:G,DomainNameConfigurations:[{CertificateArn:k,EndpointType:"REGIONAL"}]}},v[`HttpApiMapping${W}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(_),Stage:"$default"}},n.hostedZoneId)v[`HttpDomainRecord${W}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:G,Type:"A",AliasTarget:{DNSName:t.getAtt(_,"RegionalDomainName"),HostedZoneId:t.getAtt(_,"RegionalHostedZoneId")}}};w[`CustomDomain${W}`]={Description:`Custom domain ${G}`,Value:G},w[`CustomDomainTarget${W}`]={Description:`Point ${G} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(_,"RegionalDomainName")}})}if(g)v.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${s}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((k,G)=>{let W=`AppQueue${G}`,_=n.queueTimeout??120;v[W]={Type:"AWS::SQS::Queue",Properties:{QueueName:k.name,VisibilityTimeout:Math.min(43200,_*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let ee=k.concurrency??n.queueConcurrency;v[`${W}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(W,"Arn"),FunctionName:se("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ee?{ScalingConfig:{MaximumConcurrency:Math.max(2,ee)}}:{}}},w[`QueueUrl${G}`]={Description:`Queue URL: ${k.name}`,Value:t.ref(W)}});if(h)v.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},v.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:se("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(n.warm&&n.warm>0){let G={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},W=(n.warmFunctions??["http"]).filter((_)=>_!=="queue"||g);for(let _ of W){let ee=_.charAt(0).toUpperCase()+_.slice(1),mt=Math.ceil(n.warm/5),Be=0;for(let he=0;he<mt;he++){let Fe=Math.min(5,n.warm-Be);v[`Warmer${ee}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-warmer-${_}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Fe},(en,lr)=>({Id:`warm-${_}-${he}-${lr}`,Arn:t.getAtt(G[_],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Be+=Fe}v[`Warmer${ee}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(G[_]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${s}-${r}-warmer-${_}-*`)}}}}if(S)v.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},w.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(C){if(v.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:P,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},v.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${s}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},v.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...n.assetDomain?{Aliases:[n.assetDomain],ViewerCertificate:{AcmCertificateArn:n.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},n.assetDomain){if(!n.assetCertificateArn){if(!n.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(u!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);v.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)v.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};w.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}v.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${P}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},w.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},w.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(n.firewall?.enabled){let k=[],G=0;if(n.firewall.rateLimit)k.push({Name:"rate-limit",Priority:G++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-rate`}});let W={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let _ of n.firewall.rules??[]){let ee=W[_];if(!ee)continue;k.push({Name:`managed-${_}`,Priority:G++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ee}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-${_}`}})}v.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${s}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:k,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-waf`}}},w.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:t.getAtt("WebAcl","Arn")}}if(J&&K){if(!n.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");v.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${s}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(V)v.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${s}-${r}-efs`}]}},q.forEach((k,G)=>{v[`EfsMountTarget${G}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:k,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),v.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},w.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")v.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${s}-${r} cache subnets`,SubnetIds:q}},v.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${s}-${r}-cache`,ReplicationGroupDescription:`${s}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},w.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")v.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${s}-${r} db subnets`,SubnetIds:q}},v.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${s}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},v.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${s}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:n.database?.minCapacity??0.5,MaxCapacity:n.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},v.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},w.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")v.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},v.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${s}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},v.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},w.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(w.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},w.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)w.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${s}-${r})`,Parameters:f?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:v,Outputs:w},Oe={};for(let k of Object.values(v))Oe[k.Type]=(Oe[k.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Oe}}var Cp=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Tp(e){let n=`php${e.replace(".","")}`;return Cp.map((r)=>`${n}-php-${r}`)}function Za(e,n){let r=`php${e.replace(".","")}`,i=Tp(e).join(" \\\n "),s=`/opt/remi/${r}/root`,a=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
|
|
7252
7252
|
|
|
7253
7253
|
# Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
|
|
7254
7254
|
# cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
|
|
@@ -7309,7 +7309,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
7309
7309
|
|
|
7310
7310
|
# Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
|
|
7311
7311
|
CMD [ "index.http" ]
|
|
7312
|
-
`}import{execFileSync as ct}from"node:child_process";import{mkdtempSync as Kn,readFileSync as lt,rmSync as qn}from"node:fs";import{tmpdir as zn}from"node:os";import{dirname as ks,join as pe}from"node:path";import{fileURLToPath as Ms}from"node:url";function Qn(){return ks(Ms(import.meta.url))}function md(){return lt(pe(Qn(),"runtime.mjs"),"utf-8")}function Jn(e){return lt(pe(Qn(),`${e}-bootstrap`),"utf-8")}function uh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"arm64":"x64",i=e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=Kn(pe(zn(),"tscloud-node-layer-"));try{let c=i.includes(".")?i:Ls(i),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;s(`downloading Node ${c} (${n})`);let m=pe(a,"node.tar.xz");Yn(d,m),s("extracting node binary"),ct("tar",["-xf",m,"-C",a,`${u}/bin/node`],{stdio:"inherit"});let p=lt(pe(a,u,"bin","node"));s("packaging layer");let g=[{name:"bootstrap",data:Jn("node"),mode:493},{name:"runtime.mjs",data:md(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:xt(g),architecture:n,version:c,fileCount:g.length}}finally{qn(a,{recursive:!0,force:!0})}}function ph(e){let n=e.architecture??"x86_64",r=n==="arm64"?"bun-linux-aarch64":"bun-linux-x64",i=e.version==="latest"?"":e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=Kn(pe(zn(),"tscloud-bun-layer-"));try{let c=i?`https://github.com/oven-sh/bun/releases/download/bun-v${i}/${r}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${r}.zip`;s(`downloading Bun ${i||"latest"} (${n})`);let u=pe(a,"bun.zip");Yn(c,u),s("extracting bun binary"),ct("unzip",["-o","-q",u,"-d",a],{stdio:"inherit"});let d=lt(pe(a,r,"bun"));s("packaging layer");let m=[{name:"bootstrap",data:Jn("bun"),mode:493},{name:"runtime.mjs",data:md(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:xt(m),architecture:n,version:i||"latest",fileCount:m.length}}finally{qn(a,{recursive:!0,force:!0})}}function Yn(e,n){ct("curl",["-fsSL","-o",n,e],{stdio:["ignore","ignore","inherit"]})}function Ls(e){let n=ct("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),i=JSON.parse(n).find((s)=>s.version.startsWith(`v${e}.`));if(!i)throw Error(`No Node release found for major version ${e}`);return i.version.replace(/^v/,"")}import{AsyncLocalStorage as $s}from"node:async_hooks";import{createHash as Os}from"node:crypto";var tc="x-ts-cloud-invoke-depth",rc="x-ts-cloud-invoke-chain",nc="x-ts-cloud-trace-id";function gd(e){return Os("sha256").update(e).digest("hex").slice(0,8)}var Ji={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function qt(e,n){if(typeof e.get==="function")return e.get(n)??void 0;let r=e;return r[n]??r[n.toLowerCase()]??r[n.toUpperCase()]}function fd(e,n=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-n)}function hd(e,n=Ji){let r=gd(e.functionId),i=fd(qt(e.headers,rc)),s=e.traceId??qt(e.headers,nc)??crypto.randomUUID(),a=[...i,r],c=i.filter((g)=>g===r).length,u=i[i.length-1]===r,d=Number.parseInt(qt(e.headers,tc)??"",10),m=Math.max(a.length,Number.isFinite(d)?d+1:0),p="ok";if(m>n.maxDepth)p="depth_exceeded";else if(c>=n.maxRepeats)p="cycle_detected";else if(u&&n.maxRepeats<=1)p="self_invocation";return{reason:p,depth:m,chain:a,traceId:s,selfInvocation:u,repeats:c,propagate:{[tc]:String(m),[rc]:a.join("."),[nc]:s}}}var Zn={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 os{limits;clock;traces=new Map;breakers=new Map;constructor(e=Ji,n=()=>Date.now()){this.limits=e;this.clock=n}check(e){let n=this.clock();this.expireTraces(n);let r=hd(e,this.limits),i=this.breakers.get(e.functionId);if(i?.openUntil!=null&&i.openUntil>n)return this.deny(e.functionId,r,"breaker_open",n,!1);if(r.reason!=="ok")return this.deny(e.functionId,r,r.reason,n,!0);let s=this.traces.get(r.traceId)??{count:0,firstAt:n};if(s.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,s),this.deny(e.functionId,r,"trace_budget_exceeded",n,!0);if(this.traces.set(r.traceId,{count:s.count+1,firstAt:s.firstAt}),i)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,n,r,i,s){if(s){let a=this.breakers.get(e)??{consecutiveBlocks:0},c=a.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?i+this.limits.breakerCooldownMs:a.openUntil})}return{...n,allowed:!1,reason:r,message:Zn[r]}}breakerOpen(e){let n=this.breakers.get(e);return n?.openUntil!=null&&n.openUntil>this.clock()}reset(e){if(e){this.breakers.delete(e);return}this.breakers.clear(),this.traces.clear()}expireTraces(e){if(this.traces.size===0)return;for(let[n,r]of this.traces)if(e-r.firstAt>this.limits.traceWindowMs)this.traces.delete(n)}get trackedTraces(){return this.traces.size}}function ic(e){return{...e.propagate}}function oc(e){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":e.reason},body:{error:"recursion_blocked",reason:e.reason,message:e.message??Zn[e.reason],depth:e.depth,traceId:e.traceId}}}var yd=new $s;function Xn(e){let n=globalThis.process?.env?.[e];if(n==null||n==="")return;return n!=="0"&&n.toLowerCase()!=="false"}function Bs(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Ep(e){let n=e===!1?{enabled:!1}:e??{},r=Xn("TS_CLOUD_RECURSION_PROTECTION"),i=Xn("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??n.enabled??!0,detectionOnly:i??n.detectionOnly??!1,limits:{...Ji,...n.limits},functionId:n.functionId??Bs()}}var ve,oe;function wp(){let e=globalThis.fetch;if(!e||ve===e)return()=>{};oe=e;let n=async(r,i)=>{let s=yd.getStore();if(!s)return oe(r,i);let a=new Headers(i?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(ic(s)))a.set(c,u);if(r instanceof Request)return oe(new Request(r,{headers:a}),i);return oe(r,{...i,headers:a})};return Object.assign(n,e),globalThis.fetch=n,ve=n,()=>{if(globalThis.fetch===ve&&oe)globalThis.fetch=oe;ve=void 0}}var ut,zt;function Ap(e){if(!ut||JSON.stringify(zt)!==JSON.stringify(e))ut=new os(e),zt=e;return ut}function mh(){if(ut=void 0,zt=void 0,ve&&oe&&globalThis.fetch===ve)globalThis.fetch=oe;ve=void 0,oe=void 0}function bd(e,n){let r=Ep(n);if(!r.enabled)return;let i=Ap(r.limits),s={functionId:r.functionId,headers:e},a=i.check(s);return{verdict:a,blocked:!a.allowed&&!r.detectionOnly,observed:!a.allowed&&r.detectionOnly}}function Sd(e,n){return wp(),yd.run(e,n)}function gh(e){let n=e,r=n?.default??n;if(typeof r==="function")return{fetch:r};return{fetch:r?.fetch??n?.fetch,queue:r?.queue??n?.queue,cli:r?.cli??n?.cli}}var Fs=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Gs(e){if(!e)return!0;return Fs.test(e)}function _s(e){if(e?.maintenance)return e.maintenance;let n=globalThis.process?.env??{};return{enabled:n.MAINTENANCE_MODE==="1"||n.MAINTENANCE_MODE==="true",bypassSecret:n.MAINTENANCE_BYPASS_SECRET}}function Rp(e){let n=e.requestContext?.domainName??"localhost",r=e.rawQueryString?`?${e.rawQueryString}`:"",i=`https://${n}${e.rawPath||"/"}${r}`,s=new Headers;for(let[u,d]of Object.entries(e.headers??{}))if(d!==void 0)s.set(u,d);if(e.cookies?.length)s.set("cookie",e.cookies.join("; "));let a=e.requestContext.http.method,c;if(e.body!==void 0&&a!=="GET"&&a!=="HEAD")c=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(i,{method:a,headers:s,body:c})}async function vd(e){let n={},r=[],i=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let c of i)r.push(c);e.headers.forEach((c,u)=>{if(u.toLowerCase()==="set-cookie")return;n[u]=c});let s=Buffer.from(await e.arrayBuffer()),a=Gs(e.headers.get("content-type"));return{statusCode:e.status,headers:n,...r.length?{cookies:r}:{},body:a?s.toString("utf-8"):s.toString("base64"),isBase64Encoded:!a}}function Ip(e,n){return async(r)=>{if(r.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!e)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let i=_s(n);if(i.enabled){let c=r.headers?.["x-maintenance-bypass"]??r.cookies?.find((u)=>u.startsWith("tscloud_bypass="))?.split("=")[1];if(!i.bypassSecret||c!==i.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let s=bd(r.headers??{},n?.recursionProtection);if(s?.blocked){let c=oc(s.verdict);return{statusCode:c.status,headers:{...c.headers,"retry-after":"60"},body:JSON.stringify(c.body),isBase64Encoded:!1}}let a=Rp(r);if(!s){let c=await e(a);return vd(c)}if(s.observed)console.warn(`[ts-cloud] recursion detected (${s.verdict.reason}) at depth ${s.verdict.depth}; detection-only mode let it run`);return Sd(s.verdict,async()=>vd(await e(a)))}}function Ws(e){try{return JSON.parse(e)}catch{return e}}function Pp(e){return async(n)=>{let r=[];if(n.warmer)return{batchItemFailures:r};if(!e)return{batchItemFailures:r};for(let i of n.Records??[])try{await e(Ws(i.body),i)}catch{r.push({itemIdentifier:i.messageId})}return{batchItemFailures:r}}}function Dp(e){return async(n)=>{if(n.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(n)}}function fh(e,n){return{http:Ip(e.fetch,n),queue:Pp(e.queue),cli:Dp(e.cli)}}function Cd(e={}){let n=e.socketPath??"/tmp/.tscloud-fpm.sock",r=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7312
|
+
`}import{execFileSync as ot}from"node:child_process";import{mkdtempSync as Kn,readFileSync as lt,rmSync as qn}from"node:fs";import{tmpdir as zn}from"node:os";import{dirname as ks,join as pe}from"node:path";import{fileURLToPath as Ms}from"node:url";function Qn(){return ks(Ms(import.meta.url))}function md(){return lt(pe(Qn(),"runtime.mjs"),"utf-8")}function Jn(e){return lt(pe(Qn(),`${e}-bootstrap`),"utf-8")}function uh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"arm64":"x64",i=e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=Kn(pe(zn(),"tscloud-node-layer-"));try{let c=i.includes(".")?i:Ls(i),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;s(`downloading Node ${c} (${n})`);let m=pe(a,"node.tar.xz");Yn(d,m),s("extracting node binary"),ot("tar",["-xf",m,"-C",a,`${u}/bin/node`],{stdio:"inherit"});let p=lt(pe(a,u,"bin","node"));s("packaging layer");let g=[{name:"bootstrap",data:Jn("node"),mode:493},{name:"runtime.mjs",data:md(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:xt(g),architecture:n,version:c,fileCount:g.length}}finally{qn(a,{recursive:!0,force:!0})}}function ph(e){let n=e.architecture??"x86_64",r=n==="arm64"?"bun-linux-aarch64":"bun-linux-x64",i=e.version==="latest"?"":e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=Kn(pe(zn(),"tscloud-bun-layer-"));try{let c=i?`https://github.com/oven-sh/bun/releases/download/bun-v${i}/${r}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${r}.zip`;s(`downloading Bun ${i||"latest"} (${n})`);let u=pe(a,"bun.zip");Yn(c,u),s("extracting bun binary"),ot("unzip",["-o","-q",u,"-d",a],{stdio:"inherit"});let d=lt(pe(a,r,"bun"));s("packaging layer");let m=[{name:"bootstrap",data:Jn("bun"),mode:493},{name:"runtime.mjs",data:md(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:xt(m),architecture:n,version:i||"latest",fileCount:m.length}}finally{qn(a,{recursive:!0,force:!0})}}function Yn(e,n){ot("curl",["-fsSL","-o",n,e],{stdio:["ignore","ignore","inherit"]})}function Ls(e){let n=ot("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),i=JSON.parse(n).find((s)=>s.version.startsWith(`v${e}.`));if(!i)throw Error(`No Node release found for major version ${e}`);return i.version.replace(/^v/,"")}import{AsyncLocalStorage as $s}from"node:async_hooks";import{createHash as Os}from"node:crypto";var tc="x-ts-cloud-invoke-depth",rc="x-ts-cloud-invoke-chain",nc="x-ts-cloud-trace-id";function gd(e){return Os("sha256").update(e).digest("hex").slice(0,8)}var Ji={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function qt(e,n){if(typeof e.get==="function")return e.get(n)??void 0;let r=e;return r[n]??r[n.toLowerCase()]??r[n.toUpperCase()]}function fd(e,n=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-n)}function hd(e,n=Ji){let r=gd(e.functionId),i=fd(qt(e.headers,rc)),s=e.traceId??qt(e.headers,nc)??crypto.randomUUID(),a=[...i,r],c=i.filter((g)=>g===r).length,u=i[i.length-1]===r,d=Number.parseInt(qt(e.headers,tc)??"",10),m=Math.max(a.length,Number.isFinite(d)?d+1:0),p="ok";if(m>n.maxDepth)p="depth_exceeded";else if(c>=n.maxRepeats)p="cycle_detected";else if(u&&n.maxRepeats<=1)p="self_invocation";return{reason:p,depth:m,chain:a,traceId:s,selfInvocation:u,repeats:c,propagate:{[tc]:String(m),[rc]:a.join("."),[nc]:s}}}var Zn={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 os{limits;clock;traces=new Map;breakers=new Map;constructor(e=Ji,n=()=>Date.now()){this.limits=e;this.clock=n}check(e){let n=this.clock();this.expireTraces(n);let r=hd(e,this.limits),i=this.breakers.get(e.functionId);if(i?.openUntil!=null&&i.openUntil>n)return this.deny(e.functionId,r,"breaker_open",n,!1);if(r.reason!=="ok")return this.deny(e.functionId,r,r.reason,n,!0);let s=this.traces.get(r.traceId)??{count:0,firstAt:n};if(s.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,s),this.deny(e.functionId,r,"trace_budget_exceeded",n,!0);if(this.traces.set(r.traceId,{count:s.count+1,firstAt:s.firstAt}),i)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,n,r,i,s){if(s){let a=this.breakers.get(e)??{consecutiveBlocks:0},c=a.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?i+this.limits.breakerCooldownMs:a.openUntil})}return{...n,allowed:!1,reason:r,message:Zn[r]}}breakerOpen(e){let n=this.breakers.get(e);return n?.openUntil!=null&&n.openUntil>this.clock()}reset(e){if(e){this.breakers.delete(e);return}this.breakers.clear(),this.traces.clear()}expireTraces(e){if(this.traces.size===0)return;for(let[n,r]of this.traces)if(e-r.firstAt>this.limits.traceWindowMs)this.traces.delete(n)}get trackedTraces(){return this.traces.size}}function ic(e){return{...e.propagate}}function oc(e){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":e.reason},body:{error:"recursion_blocked",reason:e.reason,message:e.message??Zn[e.reason],depth:e.depth,traceId:e.traceId}}}var yd=new $s;function Xn(e){let n=globalThis.process?.env?.[e];if(n==null||n==="")return;return n!=="0"&&n.toLowerCase()!=="false"}function Bs(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Ep(e){let n=e===!1?{enabled:!1}:e??{},r=Xn("TS_CLOUD_RECURSION_PROTECTION"),i=Xn("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??n.enabled??!0,detectionOnly:i??n.detectionOnly??!1,limits:{...Ji,...n.limits},functionId:n.functionId??Bs()}}var ve,oe;function wp(){let e=globalThis.fetch;if(!e||ve===e)return()=>{};oe=e;let n=async(r,i)=>{let s=yd.getStore();if(!s)return oe(r,i);let a=new Headers(i?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(ic(s)))a.set(c,u);if(r instanceof Request)return oe(new Request(r,{headers:a}),i);return oe(r,{...i,headers:a})};return Object.assign(n,e),globalThis.fetch=n,ve=n,()=>{if(globalThis.fetch===ve&&oe)globalThis.fetch=oe;ve=void 0}}var ut,zt;function Ap(e){if(!ut||JSON.stringify(zt)!==JSON.stringify(e))ut=new os(e),zt=e;return ut}function mh(){if(ut=void 0,zt=void 0,ve&&oe&&globalThis.fetch===ve)globalThis.fetch=oe;ve=void 0,oe=void 0}function bd(e,n){let r=Ep(n);if(!r.enabled)return;let i=Ap(r.limits),s={functionId:r.functionId,headers:e},a=i.check(s);return{verdict:a,blocked:!a.allowed&&!r.detectionOnly,observed:!a.allowed&&r.detectionOnly}}function Sd(e,n){return wp(),yd.run(e,n)}function gh(e){let n=e,r=n?.default??n;if(typeof r==="function")return{fetch:r};return{fetch:r?.fetch??n?.fetch,queue:r?.queue??n?.queue,cli:r?.cli??n?.cli}}var Fs=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Gs(e){if(!e)return!0;return Fs.test(e)}function _s(e){if(e?.maintenance)return e.maintenance;let n=globalThis.process?.env??{};return{enabled:n.MAINTENANCE_MODE==="1"||n.MAINTENANCE_MODE==="true",bypassSecret:n.MAINTENANCE_BYPASS_SECRET}}function Rp(e){let n=e.requestContext?.domainName??"localhost",r=e.rawQueryString?`?${e.rawQueryString}`:"",i=`https://${n}${e.rawPath||"/"}${r}`,s=new Headers;for(let[u,d]of Object.entries(e.headers??{}))if(d!==void 0)s.set(u,d);if(e.cookies?.length)s.set("cookie",e.cookies.join("; "));let a=e.requestContext.http.method,c;if(e.body!==void 0&&a!=="GET"&&a!=="HEAD")c=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(i,{method:a,headers:s,body:c})}async function vd(e){let n={},r=[],i=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let c of i)r.push(c);e.headers.forEach((c,u)=>{if(u.toLowerCase()==="set-cookie")return;n[u]=c});let s=Buffer.from(await e.arrayBuffer()),a=Gs(e.headers.get("content-type"));return{statusCode:e.status,headers:n,...r.length?{cookies:r}:{},body:a?s.toString("utf-8"):s.toString("base64"),isBase64Encoded:!a}}function Ip(e,n){return async(r)=>{if(r.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!e)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let i=_s(n);if(i.enabled){let c=r.headers?.["x-maintenance-bypass"]??r.cookies?.find((u)=>u.startsWith("tscloud_bypass="))?.split("=")[1];if(!i.bypassSecret||c!==i.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let s=bd(r.headers??{},n?.recursionProtection);if(s?.blocked){let c=oc(s.verdict);return{statusCode:c.status,headers:{...c.headers,"retry-after":"60"},body:JSON.stringify(c.body),isBase64Encoded:!1}}let a=Rp(r);if(!s){let c=await e(a);return vd(c)}if(s.observed)console.warn(`[ts-cloud] recursion detected (${s.verdict.reason}) at depth ${s.verdict.depth}; detection-only mode let it run`);return Sd(s.verdict,async()=>vd(await e(a)))}}function Ws(e){try{return JSON.parse(e)}catch{return e}}function Pp(e){return async(n)=>{let r=[];if(n.warmer)return{batchItemFailures:r};if(!e)return{batchItemFailures:r};for(let i of n.Records??[])try{await e(Ws(i.body),i)}catch{r.push({itemIdentifier:i.messageId})}return{batchItemFailures:r}}}function Dp(e){return async(n)=>{if(n.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(n)}}function fh(e,n){return{http:Ip(e.fetch,n),queue:Pp(e.queue),cli:Dp(e.cli)}}function Cd(e={}){let n=e.socketPath??"/tmp/.tscloud-fpm.sock",r=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7313
7313
|
[global]
|
|
7314
7314
|
daemonize = no
|
|
7315
7315
|
error_log = ${e.errorLog??"/tmp/storage/logs/php-fpm.log"}
|
|
@@ -7326,4 +7326,4 @@ decorate_workers_output = no
|
|
|
7326
7326
|
php_admin_value[error_log] = /dev/stderr
|
|
7327
7327
|
php_admin_flag[log_errors] = on
|
|
7328
7328
|
clear_env = no
|
|
7329
|
-
`}import{readFileSync as Vs}from"node:fs";import{dirname as Us,join as nr}from"node:path";import{fileURLToPath as Hs}from"node:url";function js(){return nr(Us(Hs(import.meta.url)),"runtime-assets")}function kn(){let e=js(),n=(r)=>Vs(nr(e,r),"utf-8");return[{path:"bootstrap",contents:n("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:n("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:n("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:n("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:n("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:Cd(),mode:420}]}function sc(e={}){let n=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:n,CACHE_DRIVER:n,SESSION_DRIVER:n,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var Td=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as dt}from"node:child_process";import{existsSync as Ks,mkdirSync as qs,mkdtempSync as zs,readdirSync as Qs,readFileSync as Js,rmSync as Ys,statSync as ir,writeFileSync as Zs}from"node:fs";import{tmpdir as Xs}from"node:os";import{join as Me,relative as ea}from"node:path";function*sr(e){for(let n of Qs(e)){let r=Me(e,n);if(ir(r).isDirectory())yield*sr(r);else yield r}}function hh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),s=zs(Me(Xs(),"tscloud-php-layer-")),a="tscloud-php-layer:build";try{Zs(Me(s,"Dockerfile"),pd(e)),i("Building PHP runtime image (docker)"),dt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",s],{stdio:"inherit"}),i("Extracting /opt/php from image");let c=dt("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Me(s,"opt");qs(u,{recursive:!0});try{dt("docker",["cp",`${c}:/opt/php`,Me(u,"php")],{stdio:"inherit"})}finally{dt("docker",["rm",c],{stdio:"ignore"})}if(!Ks(Me(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of sr(u)){let f=ea(u,y).replace(/\\/g,"/"),h=ir(y).mode&73?493:420;d.push({name:f,data:Js(y),mode:h})}i("Injecting runtime assets");let m=new Set(kn().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of kn())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:xt(p),architecture:n,fileCount:p.length}}finally{Ys(s,{recursive:!0,force:!0})}}import{execSync as ta}from"node:child_process";import{createHash as na}from"node:crypto";import{readdirSync as ra,readFileSync as ia,statSync as ar}from"node:fs";import{join as sa,relative as or,resolve as Jt}from"node:path";var kp=[".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 aa(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*cr(e,n,r){for(let i of ra(e)){let s=sa(e,i),a=or(n,s).replace(/\\/g,"/");if(aa(a,r))continue;if(ar(s).isDirectory())yield*cr(s,n,r);else yield s}}function ss(e){if(e.skipBuild)return;let n=Jt(e.projectRoot??process.cwd()),r=e.app.build??Td;for(let i of r)e.onStep?.(`build: ${i}`),ta(i,{stdio:"inherit",cwd:n})}function as(e,n=[]){let r=Jt(e),i=[...kp,En(),...n],s=[];for(let a of cr(r,r,i)){let c=or(r,a).replace(/\\/g,"/"),u=(ar(a).mode&73)!==0;s.push({name:c,data:ia(a),mode:u?493:420})}return s}function ac(e){let n=Jt(e.projectRoot??process.cwd());ss(e),e.onStep?.("packaging application tree");let r=as(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=xt(r),s=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:na("sha256").update(i).digest("hex"),handlers:{http:s,queue:e.app.handlers?.queue??s,cli:e.app.handlers?.cli??s},fileCount:r.length}}class Ed{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let n=`asset-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.optimizations.set(n,r),r}createImageOptimization(e){let n=`image-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.imageConfigs.set(n,r),r}createSSGConfig(e){let n=`ssg-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.ssgConfigs.set(n,r),r}createPrerenderConfig(e){let n=`prerender-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.prerenderConfigs.set(n,r),r}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var yh=new Ed;class cc{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(e,n){let r=`lifecycle-${Date.now()}-${this.counter++}`,i={id:r,transitions:e,expiration:n};return this.policies.set(r,i),i}enableVersioning(e=!1){let n=`versioning-${Date.now()}-${this.counter++}`,r={id:n,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(n,r),r}createReplicationRule(e,n,r){let i=`replication-${Date.now()}-${this.counter++}`,s={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,s),s}createIntelligentTiering(e,n){let r=`tiering-${Date.now()}-${this.counter++}`,i={id:r,archiveDays:e,deepArchiveDays:n};return this.tieringConfigs.set(r,i),i}enableObjectLock(e){let n=`object-lock-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(n,r),r}enableTransferAcceleration(e){let n=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(n,r),r}createAccessPoint(e){let n=`access-point-${Date.now()}-${this.counter++}`,r={id:n,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(n,r),r}createGlacierArchive(e){let n=`glacier-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(n,r),r}createInventory(e){let n=`inventory-${Date.now()}-${this.counter++}`,r={id:n,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(n,r),r}createBatchOperation(e){let n=`batch-op-${Date.now()}-${this.counter++}`,r={id:n,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(n,r),r}executeBatchOperation(e){let n=this.batchOps.get(e);if(!n)throw Error(`Batch operation not found: ${e}`);return n.status="in_progress",n.totalObjects=1000,n.processedObjects=0,n}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSQSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSNSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}generateObjectLockCF(e){let n={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)n.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)n.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return n}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let n=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",i={Event:e.events[0],[r]:e.destination.arn};if(e.filter)i.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[n]:[i]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var Np=new cc;class wd{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,s={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,s),s}createSyntheticMonitor(e,n,r,i){let s=`synthetic-${Date.now()}-${this.counter++}`,a={id:s,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(s,a),a}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,s=n/(n+r)*100,a={id:i,resource:e,uptime:n,downtime:r,availability:s};return this.uptimeTrackers.set(i,a),a}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var bh=new wd;class Ad{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let s=`waf-${Date.now()}-${this.counter++}`,a={id:s,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(s,a),a}enableShield(e,n="standard"){let r=`shield-${Date.now()}-${this.counter++}`,i={id:r,resourceArn:e,protectionType:n};return this.shieldProtections.set(r,i),i}createSecurityGroup(e,n,r){let i=`sg-${Date.now()}-${this.counter++}`,s={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,s),s}createNACL(e,n){let r=`nacl-${Date.now()}-${this.counter++}`,i={id:r,vpcId:e,rules:n};return this.nacls.set(r,i),i}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var Sh=new Ad;class Rd{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,n){let r=`tagging-${Date.now()}-${this.counter++}`,i={id:r,tags:e,resources:n};return this.strategies.set(r,i),i}createCostAllocation(e,n){let r=`cost-${Date.now()}-${this.counter++}`,i={id:r,tagKey:e,allocations:n};return this.allocations.set(r,i),i}createResourceGroup(e,n,r){let i=`group-${Date.now()}-${this.counter++}`,s={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,s),s}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var vh=new Rd;export{Tm,Em,da,il,ua,pa,En,Ve,R,ma,ol,H,Fr,A,ou,ne,jr,ga,Jo,le,U,Xo,su,au,cu,lu,l,o,wm,Am,T,fa,ha,ya,Rm,Im,$e,ba,Bi,du,Pm,Dm,ze,Pt,Sa,sl,al,km,cl,ll,dl,Qo,va,ot,Yo,wn,Fi,An,He,uu,Zo,es,Ca,Ta,Ea,wa,Aa,Ra,Ae,j,pu,mu,ul,b,M,st,N,pl,Dt,ye,Xt,Nm,ml,Re,ts,Ge,Qt,ji,Ie,rs,Le,gu,Vi,Pe,De,ie,zi,X,Yt,kt,ke,t,Rn,xm,gl,Ia,_m,Om,$m,Lm,Pa,Mm,Um,Bm,Fm,jm,Vm,zm,Hm,Gm,qm,Wm,Km,fu,hu,yu,bu,Su,vu,Cu,Zt,fl,hl,Vr,Hi,Jm,yl,Xm,Qm,In,Ym,Zm,eg,tg,rg,ng,Tu,Eu,wu,Au,Ru,Gi,ig,Pn,Iu,bl,Pu,Da,be,Du,ku,Nt,ns,er,Nu,Sl,xu,_u,Ou,vl,Se,og,sg,ag,cg,$u,lg,Ne,dg,ug,pg,ka,Na,Lu,Cl,Tl,mg,gg,fg,hg,yg,Mu,xa,bg,Sg,vg,Cg,Tg,Uu,Bu,Eg,wg,Ag,Rg,Ig,Pg,Dg,Fu,kg,El,_a,Ng,xg,_g,Og,wl,Al,Rl,$g,Oa,ju,Vu,zu,Hu,$a,Gu,Lg,Mg,Ug,Bg,Fg,jg,Vg,qu,Wu,Ku,Ju,Il,zg,Hg,Gg,qg,Wg,Kg,Jg,Xg,Qg,Xu,Qu,Yu,Zu,Yg,Zg,Pl,ef,Dl,kl,Nl,xl,tf,rf,nf,of,at,qi,sf,af,cf,lf,df,uf,pf,mf,ep,gf,ff,_l,Ol,hf,yf,tp,bf,Sf,vf,Cf,Tf,Ef,wf,Af,Rf,If,Pf,Df,kf,Nf,xf,_f,Of,$f,Lf,Mf,Uf,La,rp,Ma,np,Ua,ip,Ba,op,Fa,sp,zr,ap,ja,cp,Wi,lp,Va,dp,za,up,$l,Bf,Ll,Ff,Ha,pp,Hr,mp,Ml,jf,Ga,gp,Ul,Vf,Bl,zf,Fl,Hf,qa,fp,jl,Gf,Vl,qf,zl,Wf,Hl,Kf,Wa,hp,Ka,yp,Gl,Jf,ql,Xf,Wl,Qf,Kl,Yf,Jl,Zf,Xl,eh,Ja,bp,Ql,th,Yl,rh,Zl,nh,ed,ih,td,oh,rd,sh,nd,id,od,sd,ad,ah,cd,ch,ld,lh,dd,dh,xt,ud,Sp,is,Xa,Dn,vp,Ki,tr,Qa,Ya,Cp,Tp,Za,pd,ec,md,uh,ph,tc,rc,nc,gd,Ji,fd,hd,os,ic,oc,yd,Ep,wp,Ap,mh,bd,Sd,gh,Rp,vd,Ip,Pp,Dp,fh,Cd,kn,sc,Td,hh,kp,ss,as,ac,Ed,yh,cc,Np,wd,bh,Ad,Sh,Rd,vh};
|
|
7329
|
+
`}import{readFileSync as Vs}from"node:fs";import{dirname as Us,join as nr}from"node:path";import{fileURLToPath as Hs}from"node:url";function js(){return nr(Us(Hs(import.meta.url)),"runtime-assets")}function kn(){let e=js(),n=(r)=>Vs(nr(e,r),"utf-8");return[{path:"bootstrap",contents:n("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:n("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:n("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:n("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:n("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:Cd(),mode:420}]}function sc(e={}){let n=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:n,CACHE_DRIVER:n,SESSION_DRIVER:n,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var Td=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as dt}from"node:child_process";import{existsSync as Ks,mkdirSync as qs,mkdtempSync as zs,readdirSync as Qs,readFileSync as Js,rmSync as Ys,statSync as ir,writeFileSync as Zs}from"node:fs";import{tmpdir as Xs}from"node:os";import{join as Me,relative as ea}from"node:path";function*sr(e){for(let n of Qs(e)){let r=Me(e,n);if(ir(r).isDirectory())yield*sr(r);else yield r}}function hh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),s=zs(Me(Xs(),"tscloud-php-layer-")),a="tscloud-php-layer:build";try{Zs(Me(s,"Dockerfile"),pd(e)),i("Building PHP runtime image (docker)"),dt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",s],{stdio:"inherit"}),i("Extracting /opt/php from image");let c=dt("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Me(s,"opt");qs(u,{recursive:!0});try{dt("docker",["cp",`${c}:/opt/php`,Me(u,"php")],{stdio:"inherit"})}finally{dt("docker",["rm",c],{stdio:"ignore"})}if(!Ks(Me(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of sr(u)){let f=ea(u,y).replace(/\\/g,"/"),h=ir(y).mode&73?493:420;d.push({name:f,data:Js(y),mode:h})}i("Injecting runtime assets");let m=new Set(kn().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of kn())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:xt(p),architecture:n,fileCount:p.length}}finally{Ys(s,{recursive:!0,force:!0})}}import{execSync as ta}from"node:child_process";import{createHash as na}from"node:crypto";import{readdirSync as ra,readFileSync as ia,statSync as ar}from"node:fs";import{join as sa,relative as or,resolve as Jt}from"node:path";var kp=[".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 aa(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*cr(e,n,r){for(let i of ra(e)){let s=sa(e,i),a=or(n,s).replace(/\\/g,"/");if(aa(a,r))continue;if(ar(s).isDirectory())yield*cr(s,n,r);else yield s}}function ss(e){if(e.skipBuild)return;let n=Jt(e.projectRoot??process.cwd()),r=e.app.build??Td;for(let i of r)e.onStep?.(`build: ${i}`),ta(i,{stdio:"inherit",cwd:n})}function as(e,n=[]){let r=Jt(e),i=[...kp,En(),...n],s=[];for(let a of cr(r,r,i)){let c=or(r,a).replace(/\\/g,"/"),u=(ar(a).mode&73)!==0;s.push({name:c,data:ia(a),mode:u?493:420})}return s}function ac(e){let n=Jt(e.projectRoot??process.cwd());ss(e),e.onStep?.("packaging application tree");let r=as(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=xt(r),s=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:na("sha256").update(i).digest("hex"),handlers:{http:s,queue:e.app.handlers?.queue??s,cli:e.app.handlers?.cli??s},fileCount:r.length}}class Ed{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let n=`asset-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.optimizations.set(n,r),r}createImageOptimization(e){let n=`image-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.imageConfigs.set(n,r),r}createSSGConfig(e){let n=`ssg-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.ssgConfigs.set(n,r),r}createPrerenderConfig(e){let n=`prerender-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.prerenderConfigs.set(n,r),r}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var yh=new Ed;class cc{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(e,n){let r=`lifecycle-${Date.now()}-${this.counter++}`,i={id:r,transitions:e,expiration:n};return this.policies.set(r,i),i}enableVersioning(e=!1){let n=`versioning-${Date.now()}-${this.counter++}`,r={id:n,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(n,r),r}createReplicationRule(e,n,r){let i=`replication-${Date.now()}-${this.counter++}`,s={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,s),s}createIntelligentTiering(e,n){let r=`tiering-${Date.now()}-${this.counter++}`,i={id:r,archiveDays:e,deepArchiveDays:n};return this.tieringConfigs.set(r,i),i}enableObjectLock(e){let n=`object-lock-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(n,r),r}enableTransferAcceleration(e){let n=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(n,r),r}createAccessPoint(e){let n=`access-point-${Date.now()}-${this.counter++}`,r={id:n,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(n,r),r}createGlacierArchive(e){let n=`glacier-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(n,r),r}createInventory(e){let n=`inventory-${Date.now()}-${this.counter++}`,r={id:n,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(n,r),r}createBatchOperation(e){let n=`batch-op-${Date.now()}-${this.counter++}`,r={id:n,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(n,r),r}executeBatchOperation(e){let n=this.batchOps.get(e);if(!n)throw Error(`Batch operation not found: ${e}`);return n.status="in_progress",n.totalObjects=1000,n.processedObjects=0,n}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSQSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSNSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}generateObjectLockCF(e){let n={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)n.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)n.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return n}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let n=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",i={Event:e.events[0],[r]:e.destination.arn};if(e.filter)i.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[n]:[i]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var Np=new cc;class wd{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,s={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,s),s}createSyntheticMonitor(e,n,r,i){let s=`synthetic-${Date.now()}-${this.counter++}`,a={id:s,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(s,a),a}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,s=n/(n+r)*100,a={id:i,resource:e,uptime:n,downtime:r,availability:s};return this.uptimeTrackers.set(i,a),a}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var bh=new wd;class Ad{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let s=`waf-${Date.now()}-${this.counter++}`,a={id:s,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(s,a),a}enableShield(e,n="standard"){let r=`shield-${Date.now()}-${this.counter++}`,i={id:r,resourceArn:e,protectionType:n};return this.shieldProtections.set(r,i),i}createSecurityGroup(e,n,r){let i=`sg-${Date.now()}-${this.counter++}`,s={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,s),s}createNACL(e,n){let r=`nacl-${Date.now()}-${this.counter++}`,i={id:r,vpcId:e,rules:n};return this.nacls.set(r,i),i}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var Sh=new Ad;class Rd{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,n){let r=`tagging-${Date.now()}-${this.counter++}`,i={id:r,tags:e,resources:n};return this.strategies.set(r,i),i}createCostAllocation(e,n){let r=`cost-${Date.now()}-${this.counter++}`,i={id:r,tagKey:e,allocations:n};return this.allocations.set(r,i),i}createResourceGroup(e,n,r){let i=`group-${Date.now()}-${this.counter++}`,s={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,s),s}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var vh=new Rd;export{Tm,Em,da,il,ua,pa,En,ze,I,ma,ol,H,Fr,A,ou,ne,jr,ga,Jo,le,U,Xo,su,au,cu,lu,l,o,wm,Am,T,fa,ha,ya,Rm,Im,$e,ba,Bi,du,Pm,Dm,He,Pt,Sa,sl,al,km,cl,ll,dl,Qo,va,st,Yo,wn,Fi,An,Ge,uu,Zo,es,Ca,Ta,Ea,wa,Aa,Ra,Ae,j,pu,mu,ul,b,M,at,N,pl,Dt,ye,Xt,Nm,ml,Re,ts,qe,Qt,ji,Ie,rs,Le,gu,Vi,Pe,De,ie,zi,X,Yt,kt,ke,t,Rn,xm,gl,Ia,_m,Om,$m,Lm,Pa,Mm,Um,Bm,Fm,jm,Vm,zm,Hm,Gm,qm,Wm,Km,fu,hu,yu,bu,Su,vu,Cu,Zt,fl,hl,Vr,Hi,Jm,yl,Xm,Qm,In,Ym,Zm,eg,tg,rg,ng,Tu,Eu,wu,Au,Ru,Gi,ig,Pn,Iu,bl,Pu,Da,be,Du,ku,Nt,ns,er,Nu,Sl,xu,_u,Ou,vl,Se,og,sg,ag,cg,$u,lg,Ne,dg,ug,pg,ka,Na,Lu,Cl,Tl,mg,gg,fg,hg,yg,Mu,xa,bg,Sg,vg,Cg,Tg,Uu,Bu,Eg,wg,Ag,Rg,Ig,Pg,Dg,Fu,kg,El,_a,Ng,xg,_g,Og,wl,Al,Rl,$g,Oa,ju,Vu,zu,Hu,$a,Gu,Lg,Mg,Ug,Bg,Fg,jg,Vg,qu,Wu,Ku,Ju,Il,zg,Hg,Gg,qg,Wg,Kg,Jg,Xg,Qg,Xu,Qu,Yu,Zu,Yg,Zg,Pl,ef,Dl,kl,Nl,xl,tf,rf,nf,of,ct,qi,sf,af,cf,lf,df,uf,pf,mf,ep,gf,ff,_l,Ol,hf,yf,tp,bf,Sf,vf,Cf,Tf,Ef,wf,Af,Rf,If,Pf,Df,kf,Nf,xf,_f,Of,$f,Lf,Mf,Uf,La,rp,Ma,np,Ua,ip,Ba,op,Fa,sp,zr,ap,ja,cp,Wi,lp,Va,dp,za,up,$l,Bf,Ll,Ff,Ha,pp,Hr,mp,Ml,jf,Ga,gp,Ul,Vf,Bl,zf,Fl,Hf,qa,fp,jl,Gf,Vl,qf,zl,Wf,Hl,Kf,Wa,hp,Ka,yp,Gl,Jf,ql,Xf,Wl,Qf,Kl,Yf,Jl,Zf,Xl,eh,Ja,bp,Ql,th,Yl,rh,Zl,nh,ed,ih,td,oh,rd,sh,nd,id,od,sd,ad,ah,cd,ch,ld,lh,dd,dh,xt,ud,Sp,is,Xa,Dn,vp,Ki,tr,Qa,Ya,Cp,Tp,Za,pd,ec,md,uh,ph,tc,rc,nc,gd,Ji,fd,hd,os,ic,oc,yd,Ep,wp,Ap,mh,bd,Sd,gh,Rp,vd,Ip,Pp,Dp,fh,Cd,kn,sc,Td,hh,kp,ss,as,ac,Ed,yh,cc,Np,wd,bh,Ad,Sh,Rd,vh};
|