@stacksjs/ts-cloud 0.16.57 → 0.16.58

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.
Files changed (93) hide show
  1. package/dist/bin/{chunk-8nfrknq3.js → chunk-0vfw6xy0.js} +1 -1
  2. package/dist/bin/{chunk-1q6wqzh1.js → chunk-1gznb7bh.js} +3 -3
  3. package/dist/bin/chunk-32nkkq9k.js +1 -0
  4. package/dist/bin/chunk-37aphhk9.js +3 -0
  5. package/dist/bin/{chunk-6sfn8fjv.js → chunk-4fkmd2ce.js} +1 -1
  6. package/dist/bin/{chunk-tbp1gf1p.js → chunk-5mnfp9ae.js} +1 -1
  7. package/dist/bin/chunk-5wz1e4ne.js +1 -0
  8. package/dist/bin/chunk-71vhvzhv.js +1 -0
  9. package/dist/bin/{chunk-jxm62h8r.js → chunk-8t01yv89.js} +1 -1
  10. package/dist/bin/{chunk-s59x3psv.js → chunk-9292d4yb.js} +34 -34
  11. package/dist/bin/{chunk-sbate1ky.js → chunk-agakphd1.js} +1 -1
  12. package/dist/bin/{chunk-k1kk78qg.js → chunk-ebhfg18g.js} +4 -4
  13. package/dist/bin/{chunk-1cccv502.js → chunk-enmw6v4x.js} +1 -1
  14. package/dist/bin/{chunk-8fh0gv4q.js → chunk-gvv4hn0h.js} +1 -1
  15. package/dist/bin/{chunk-s98wngxx.js → chunk-nnrta1g9.js} +1 -1
  16. package/dist/bin/{chunk-mn3x457v.js → chunk-p1eqv66t.js} +73 -73
  17. package/dist/bin/{chunk-dg8ceycc.js → chunk-qvrfaeqq.js} +7 -7
  18. package/dist/bin/chunk-sgkyg842.js +1 -0
  19. package/dist/bin/{chunk-rqvrjp8g.js → chunk-t8qzx4ka.js} +21 -21
  20. package/dist/bin/{chunk-v9js2b1d.js → chunk-tdftrmyx.js} +1 -1
  21. package/dist/bin/{chunk-hkx5j0bn.js → chunk-vmrkqtch.js} +1 -1
  22. package/dist/bin/{chunk-bn2sn094.js → chunk-wg9zm31f.js} +1 -1
  23. package/dist/bin/{chunk-jyvr7eh5.js → chunk-wzpsq446.js} +1 -1
  24. package/dist/bin/{chunk-e3zsrpbj.js → chunk-yn3499yh.js} +1 -1
  25. package/dist/bin/{chunk-28124w0n.js → chunk-zp1cxtbh.js} +1 -1
  26. package/dist/bin/{chunk-ek27709c.js → chunk-zpjy26jk.js} +3 -3
  27. package/dist/bin/cli.js +211 -211
  28. package/dist/bin/dashboard-server.js +1 -1
  29. package/dist/{chunk-r3qpx6xp.js → chunk-4f0b21fp.js} +2 -2
  30. package/dist/deploy/index.js +1 -1
  31. package/dist/drivers/shared/compute-ops.d.ts +6 -3
  32. package/dist/index.js +1 -1
  33. package/dist/mail/index.js +2 -2
  34. package/dist/ui/404.html +1 -1
  35. package/dist/ui/accept-invitation.html +1 -1
  36. package/dist/ui/access-denied.html +1 -1
  37. package/dist/ui/account/automation.html +6 -6
  38. package/dist/ui/account/security.html +2 -2
  39. package/dist/ui/applications/compose.html +6 -6
  40. package/dist/ui/applications/new.html +2 -2
  41. package/dist/ui/data/backups.html +6 -6
  42. package/dist/ui/data/services.html +6 -6
  43. package/dist/ui/data/volumes.html +6 -6
  44. package/dist/ui/index.html +6 -6
  45. package/dist/ui/infrastructure/topology.html +6 -6
  46. package/dist/ui/integrations.html +2 -2
  47. package/dist/ui/operations/alerts.html +6 -6
  48. package/dist/ui/operations/configuration.html +6 -6
  49. package/dist/ui/operations/jobs.html +5 -5
  50. package/dist/ui/operations/maintenance.html +5 -5
  51. package/dist/ui/operations/observability.html +6 -6
  52. package/dist/ui/operations/previews.html +6 -6
  53. package/dist/ui/operations/queue.html +5 -5
  54. package/dist/ui/operations/regions.html +5 -5
  55. package/dist/ui/operations/releases.html +6 -6
  56. package/dist/ui/operations/spend.html +6 -6
  57. package/dist/ui/operations/workloads.html +6 -6
  58. package/dist/ui/security.html +2 -2
  59. package/dist/ui/server/actions.html +6 -6
  60. package/dist/ui/server/activity.html +2 -2
  61. package/dist/ui/server/capacity.html +6 -6
  62. package/dist/ui/server/database.html +5 -5
  63. package/dist/ui/server/deployments.html +5 -5
  64. package/dist/ui/server/diagnostics.html +1 -1
  65. package/dist/ui/server/firewall.html +5 -5
  66. package/dist/ui/server/fleet.html +6 -6
  67. package/dist/ui/server/logs.html +5 -5
  68. package/dist/ui/server/metrics.html +5 -5
  69. package/dist/ui/server/security.html +2 -2
  70. package/dist/ui/server/services.html +2 -2
  71. package/dist/ui/server/sites.html +6 -6
  72. package/dist/ui/server/ssh-keys.html +6 -6
  73. package/dist/ui/server/team.html +6 -6
  74. package/dist/ui/server/terminal.html +2 -2
  75. package/dist/ui/serverless/alarms.html +6 -6
  76. package/dist/ui/serverless/assets.html +2 -2
  77. package/dist/ui/serverless/cost.html +2 -2
  78. package/dist/ui/serverless/data.html +6 -6
  79. package/dist/ui/serverless/deployments.html +2 -2
  80. package/dist/ui/serverless/firewall.html +1 -1
  81. package/dist/ui/serverless/functions.html +5 -5
  82. package/dist/ui/serverless/logs.html +6 -6
  83. package/dist/ui/serverless/metrics.html +2 -2
  84. package/dist/ui/serverless/queues.html +5 -5
  85. package/dist/ui/serverless/secrets.html +6 -6
  86. package/dist/ui/serverless/traces.html +6 -6
  87. package/dist/ui/serverless.html +6 -6
  88. package/package.json +3 -3
  89. package/dist/bin/chunk-6tdt3ea9.js +0 -1
  90. package/dist/bin/chunk-cdseg15k.js +0 -3
  91. package/dist/bin/chunk-et6hzqpx.js +0 -1
  92. package/dist/bin/chunk-gx5wqrgh.js +0 -1
  93. package/dist/bin/chunk-pexjxc5g.js +0 -1
@@ -1,14 +1,14 @@
1
- import{Y,is,kt,Dn}from"./chunk-z6xnegpe.js";import{Yt,zr}from"./chunk-7p70c4br.js";var al={};Yt(al,{default:()=>Dr,handler:()=>yt});var cl={};Yt(cl,{default:()=>Nr,handler:()=>ft});var Yl={};Yt(Yl,{EmailAnalyticsModule:()=>Je,EmailRules:()=>_t,EmailScheduling:()=>Bt,EmailSearch:()=>Ot,EmailTemplates:()=>Ce,EmailThreading:()=>$t,SharedMailboxes:()=>Ft});var Zl={};Yt(Zl,{default:()=>ra,handler:()=>na});var ed={};Yt(ed,{CallAnalytics:()=>Ut,CallRecording:()=>Vt,Callbacks:()=>at,IVRBuilder:()=>we});var td={};Yt(td,{AbTesting:()=>me,LinkTracking:()=>Zt,MmsSupport:()=>qt,SmsAnalytics:()=>jt,SmsCampaigns:()=>Ht,SmsChatbot:()=>zt});var hm={backgroundJobs:{visibilityTimeout:120,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fifo:{fifo:!0,contentBasedDeduplication:!0,visibilityTimeout:30,encrypted:!0},highThroughput:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0},delayed:{delaySeconds:60,visibilityTimeout:60,encrypted:!0},longRunning:{visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:2,encrypted:!0},monitored:{visibilityTimeout:60,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0,alarms:{enabled:!0,queueDepthThreshold:1000,messageAgeThreshold:3600,dlqAlarm:!0}},lambdaOptimized:{visibilityTimeout:360,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fanOut:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0}},ym={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}};import{isAbsolute as pt,join as Ye,relative as ur}from"node:path";var sa=".ts-cloud",Zc="TS_CLOUD_STATE_DIR",gt=null;function aa(e){gt=e?.trim()||null}function ca(){return Boolean(process.env[Zc]?.trim()||gt)}function Cn(){return process.env[Zc]?.trim()||gt||sa}function je(...e){return Ye(Cn(),...e)}function A(e,...n){let r=Cn();return pt(r)?Ye(r,...n):Ye(e,r,...n)}function la(e,n=process.cwd()){let r=(a,s)=>{let c=ur(a,s);return c===""||!c.startsWith("..")&&!pt(c)},i=pt(e)?e:Ye(n,e);return r(A(n),i)}function el(e){let n=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((i)=>i?.app!=null);return{server:n,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:n}=el(e);return n?"serverless":"server"}function Ur(e){let{server:n,serverless:r}=el(e);if(n&&r)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(e.mode==="server"&&r&&!n)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&n&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function w(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function dr(e){return typeof e==="object"&&e!==null?e:{}}function eu(e){return e===!0||typeof e==="object"&&e!==null}function mr(e,n){let r=n?e.environments?.[n]:void 0;if(r?.domain)return r.domain;let i=Object.values(e.sites??{}),a=e.sites?.main?.domain??i.find((s)=>s.domain)?.domain;if(a)return a;return`${e.project?.slug??"app"}.local`}function pr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function ne(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=dr(r),a=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),s=i.mode??(a==="production"?"server":"catcher"),c=s==="server",u=mr(e,n.environment),d=i.hostname??(c?`mail.${u}`:"localhost"),m=i.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=i.tls??{},y=g.enabled??c,f=!!(g.certPath&&g.keyPath),h=(i.accounts??[]).map((Q)=>({address:Q.address,password:Q.password,passwordPolicy:Q.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},C=i.dkim===!1?!1:i.dkim===!0||c,P=typeof i.webmail==="object"&&i.webmail!==null?i.webmail:{},E=i.webmail===!1?!1:P.enabled??!0,v=d.includes(".")&&!d.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(d),I=P.domain===!1?void 0:P.domain??(c&&v?d:void 0),D=P.tls??(I?!1:y),N=[...new Set(P.aliases??[])].filter((Q)=>Q!==I),M=i.spam??{},F=i.delivery??(c?"direct":"none"),O=i.expose??c,G=pr(d),U=[...new Set([d,...G?[G]:[],...i.domains??[]])],ce=P.attachments?.maxFileBytes??20971520,q=P.attachments?.maxTotalBytes??20971520,J=P.attachments?.maxCount??20,K=P.undoSendSeconds??10;for(let[Q,ge,Te]of[["maxFileBytes",ce,104857600],["maxTotalBytes",q,104857600],["maxCount",J,100],["undoSendSeconds",K,30]])if(!Number.isInteger(ge)||ge<0||ge>Te)throw Error(`Mail webmail ${Q} must be an integer from 0 to ${Te}`);return{enabled:eu(r),mode:s,version:i.version,hostname:d,domains:U,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:C,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:E,port:P.port??p.webmail,domain:I,aliases:N,tls:D,secureCookies:P.secureCookies??(!!I||D),attachmentMaxFileBytes:ce,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:F,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:M.enabled??c,enforce:M.enforce??!1,junkScore:M.junkScore??5,rejectScore:M.rejectScore??12,dnsbl:M.dnsbl??c,greylist:M.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function Fr(e){if(!e.enabled||!e.expose)return[];let n=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)n.push(e.webmail.port);return[...new Set(n)].sort((r,i)=>r-i)}function da(e){if(!e.enabled)return{};let n=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(n)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let i=e.accounts[0];if(i)r.MAIL_USERNAME=i.address,r.MAIL_PASSWORD=i.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function qo(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let n=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(n.map((r,i)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(r))throw Error(`Invalid mail webmail hostname: ${r}`);return[`__mail_webmail_${i}`,{domain:r,proxyTo:`localhost:${e.webmail.port}`}]}))}function le(e,n={}){let r=e.infrastructure?.compute?.proxy,i=ne(e,n);if(!i.enabled||!i.webmail.enabled||!i.webmail.domain)return r;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:i.tls.acmeEmail??`webmaster@${i.webmail.domain}`,...r}}function B(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class Go{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,n){return this.template.Resources[e]=n,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,n){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=n,this}addOutput(e,n){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=n,this}addMetadata(e,n){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=n,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,n=0){let r=" ".repeat(n),i="";for(let[a,s]of Object.entries(e)){if(s===null||s===void 0)continue;if(typeof s==="object"&&!Array.isArray(s))i+=`${r}${a}:
1
+ import{Y,is,kt,Dn}from"./chunk-z6xnegpe.js";import{Yt,zr}from"./chunk-7p70c4br.js";var al={};Yt(al,{default:()=>Dr,handler:()=>yt});var cl={};Yt(cl,{default:()=>Nr,handler:()=>ft});var Yl={};Yt(Yl,{EmailAnalyticsModule:()=>Je,EmailRules:()=>_t,EmailScheduling:()=>Bt,EmailSearch:()=>Ot,EmailTemplates:()=>Ce,EmailThreading:()=>$t,SharedMailboxes:()=>Ft});var Zl={};Yt(Zl,{default:()=>ra,handler:()=>na});var ed={};Yt(ed,{CallAnalytics:()=>Ut,CallRecording:()=>Vt,Callbacks:()=>at,IVRBuilder:()=>we});var td={};Yt(td,{AbTesting:()=>me,LinkTracking:()=>Zt,MmsSupport:()=>qt,SmsAnalytics:()=>jt,SmsCampaigns:()=>Ht,SmsChatbot:()=>zt});var hm={backgroundJobs:{visibilityTimeout:120,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fifo:{fifo:!0,contentBasedDeduplication:!0,visibilityTimeout:30,encrypted:!0},highThroughput:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0},delayed:{delaySeconds:60,visibilityTimeout:60,encrypted:!0},longRunning:{visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:2,encrypted:!0},monitored:{visibilityTimeout:60,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0,alarms:{enabled:!0,queueDepthThreshold:1000,messageAgeThreshold:3600,dlqAlarm:!0}},lambdaOptimized:{visibilityTimeout:360,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fanOut:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0}},ym={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}};import{isAbsolute as pt,join as Ye,relative as ur}from"node:path";var sa=".ts-cloud",Zc="TS_CLOUD_STATE_DIR",gt=null;function aa(e){gt=e?.trim()||null}function ca(){return Boolean(process.env[Zc]?.trim()||gt)}function Cn(){return process.env[Zc]?.trim()||gt||sa}function je(...e){return Ye(Cn(),...e)}function R(e,...n){let r=Cn();return pt(r)?Ye(r,...n):Ye(e,r,...n)}function la(e,n=process.cwd()){let r=(a,s)=>{let c=ur(a,s);return c===""||!c.startsWith("..")&&!pt(c)},i=pt(e)?e:Ye(n,e);return r(R(n),i)}function el(e){let n=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((i)=>i?.app!=null);return{server:n,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:n}=el(e);return n?"serverless":"server"}function Ur(e){let{server:n,serverless:r}=el(e);if(n&&r)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(e.mode==="server"&&r&&!n)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&n&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function A(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function dr(e){return typeof e==="object"&&e!==null?e:{}}function eu(e){return e===!0||typeof e==="object"&&e!==null}function mr(e,n){let r=n?e.environments?.[n]:void 0;if(r?.domain)return r.domain;let i=Object.values(e.sites??{}),a=e.sites?.main?.domain??i.find((s)=>s.domain)?.domain;if(a)return a;return`${e.project?.slug??"app"}.local`}function pr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function ne(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=dr(r),a=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),s=i.mode??(a==="production"?"server":"catcher"),c=s==="server",u=mr(e,n.environment),d=i.hostname??(c?`mail.${u}`:"localhost"),m=i.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=i.tls??{},y=g.enabled??c,f=!!(g.certPath&&g.keyPath),h=(i.accounts??[]).map((Q)=>({address:Q.address,password:Q.password,passwordPolicy:Q.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},C=i.dkim===!1?!1:i.dkim===!0||c,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),N=[...new Set(E.aliases??[])].filter((Q)=>Q!==I),M=i.spam??{},F=i.delivery??(c?"direct":"none"),O=i.expose??c,G=pr(d),U=[...new Set([d,...G?[G]:[],...i.domains??[]])],ce=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:eu(r),mode:s,version:i.version,hostname:d,domains:U,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:C,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:w,port:E.port??p.webmail,domain:I,aliases:N,tls:D,secureCookies:E.secureCookies??(!!I||D),attachmentMaxFileBytes:ce,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:F,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:M.enabled??c,enforce:M.enforce??!1,junkScore:M.junkScore??5,rejectScore:M.rejectScore??12,dnsbl:M.dnsbl??c,greylist:M.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function Fr(e){if(!e.enabled||!e.expose)return[];let n=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)n.push(e.webmail.port);return[...new Set(n)].sort((r,i)=>r-i)}function da(e){if(!e.enabled)return{};let n=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(n)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let i=e.accounts[0];if(i)r.MAIL_USERNAME=i.address,r.MAIL_PASSWORD=i.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function qo(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let n=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(n.map((r,i)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(r))throw Error(`Invalid mail webmail hostname: ${r}`);return[`__mail_webmail_${i}`,{domain:r,proxyTo:`localhost:${e.webmail.port}`}]}))}function le(e,n={}){let r=e.infrastructure?.compute?.proxy,i=ne(e,n);if(!i.enabled||!i.webmail.enabled||!i.webmail.domain)return r;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:i.tls.acmeEmail??`webmaster@${i.webmail.domain}`,...r}}function B(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class Go{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,n){return this.template.Resources[e]=n,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,n){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=n,this}addOutput(e,n){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=n,this}addMetadata(e,n){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=n,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,n=0){let r=" ".repeat(n),i="";for(let[a,s]of Object.entries(e)){if(s===null||s===void 0)continue;if(typeof s==="object"&&!Array.isArray(s))i+=`${r}${a}:
2
2
  ${this.convertToYAML(s,n+1)}`;else if(Array.isArray(s)){i+=`${r}${a}:
3
3
  `;for(let c of s)if(typeof c==="object")i+=`${r} -
4
4
  ${this.convertToYAML(c,n+2)}`;else i+=`${r} - ${c}
5
5
  `}else i+=`${r}${a}: ${s}
6
- `}return i}}function tu(e){let n=[],r=[],i=[];if(gr(e,n),e.Resources)yr(e.Resources,n,r);else n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)fr(e.Parameters,n,r);if(e.Outputs)hr(e.Outputs,n);br(e,n);let a=Sr(e);if(a.length>0)for(let s of a)n.push({path:"Resources",message:`Circular dependency detected: ${s.join(" → ")}`,severity:"error"});return Cr(e,r,i),{valid:n.length===0,errors:n,warnings:r,info:i}}function gr(e,n){if(!e.AWSTemplateFormatVersion)n.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")n.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function yr(e,n,r){let i=Object.keys(e);if(i.length===0){n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(i.length>500)r.push({path:"Resources",message:`Template contains ${i.length} resources (limit is 500)`,severity:"warning"});for(let a of i){let s=e[a];if(!/^[a-zA-Z0-9]+$/.test(a))n.push({path:`Resources.${a}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!s.Type)n.push({path:`Resources.${a}.Type`,message:"Resource Type is required",severity:"error"});else if(!s.Type.startsWith("AWS::")&&!s.Type.startsWith("Custom::"))n.push({path:`Resources.${a}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(s.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(s.DeletionPolicy))n.push({path:`Resources.${a}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!s.DeletionPolicy&&an(s.Type))r.push({path:`Resources.${a}.DeletionPolicy`,message:`${s.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function fr(e,n,r){let i=Object.keys(e);if(i.length>200)r.push({path:"Parameters",message:`Template contains ${i.length} parameters (limit is 200)`,severity:"warning"});for(let a of i){let s=e[a];if(!s.Type)n.push({path:`Parameters.${a}.Type`,message:"Parameter Type is required",severity:"error"});let c=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(s.Type&&!c.includes(s.Type))n.push({path:`Parameters.${a}.Type`,message:`Invalid parameter type: ${s.Type}`,severity:"error"})}}function hr(e,n){let r=Object.keys(e);for(let i of r)if(!e[i].Value)n.push({path:`Outputs.${i}.Value`,message:"Output Value is required",severity:"error"})}function br(e,n){let r=e.Resources||{},i=e.Parameters||{},a=new Set(Object.keys(r)),s=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!a.has(m)&&!s.has(m)&&m!=="AWS::Region"&&m!=="AWS::AccountId"&&m!=="AWS::StackName"&&m!=="AWS::StackId"&&m!=="AWS::URLSuffix"&&m!=="AWS::Partition"&&m!=="AWS::NoValue")n.push({path:d,message:`Reference to non-existent resource or parameter: ${m}`,severity:"error"})}if(u["Fn::GetAtt"]){let m=u["Fn::GetAtt"];if(Array.isArray(m)&&m.length>=1){let p=m[0];if(!a.has(p))n.push({path:d,message:`GetAtt references non-existent resource: ${p}`,severity:"error"})}}for(let m in u)c(u[m],`${d}.${m}`)}for(let u in r)c(r[u],`Resources.${u}`);if(e.Outputs)for(let u in e.Outputs)c(e.Outputs[u],`Outputs.${u}`)}function Sr(e){let n=e.Resources||{},r=new Map;for(let u in n){let d=new Set,m=n[u];if(m.DependsOn)if(Array.isArray(m.DependsOn))m.DependsOn.forEach((g)=>d.add(g));else d.add(m.DependsOn);Ar(m).forEach((g)=>d.add(g)),r.set(u,d)}let i=[],a=new Set,s=new Set;function c(u,d){a.add(u),s.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!a.has(p))c(p,[...d]);else if(s.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}s.delete(u)}for(let u of r.keys())if(!a.has(u))c(u,[]);return i}function Ar(e){let n=new Set;function r(i){if(typeof i!=="object"||i===null)return;if(i.Ref&&typeof i.Ref==="string"){if(!i.Ref.startsWith("AWS::"))n.add(i.Ref)}if(i["Fn::GetAtt"]&&Array.isArray(i["Fn::GetAtt"]))n.add(i["Fn::GetAtt"][0]);for(let a in i)r(i[a])}return r(e),n}function an(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function Cr(e,n,r){let i=e.Resources||{};if(!e.Description)r.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let a in i){let s=i[a],c=s.Properties;if(c&&!c.Tags&&vr(s.Type))r.push({path:`Resources.${a}`,message:`Consider adding Tags to ${s.Type}`,severity:"info"});if(an(s.Type)){if(s.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${a}`,message:"S3 bucket should enable encryption",severity:"warning"});if(s.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${a}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function vr(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function ru(e){let n=[],r=[],i=[],a=Buffer.byteLength(e,"utf8"),s=a/1024,c=51200,u=460800;if(a>460800)n.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(a>51200)r.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:n.length===0,errors:n,warnings:r,info:i}}function nu(e){let n=[],r=[],i=[],a=e.Resources||{},s=e.Parameters||{},c=e.Outputs||{};if(Object.keys(a).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(a).length} resources (limit is 500)`,severity:"error"});if(Object.keys(s).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(s).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(c).length>200)n.push({path:"Outputs",message:`Template has ${Object.keys(c).length} outputs (limit is 200)`,severity:"error"});return{valid:n.length===0,errors:n,warnings:r,info:i}}var R={Ref:(e)=>({Ref:e}),GetAtt:(e,n)=>({"Fn::GetAtt":[e,n]}),Sub:(e,n)=>{if(n)return{"Fn::Sub":[e,n]};return{"Fn::Sub":e}},Join:(e,n)=>({"Fn::Join":[e,n]}),Select:(e,n)=>({"Fn::Select":[e,n]}),Split:(e,n)=>({"Fn::Split":[e,n]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,n,r)=>({"Fn::If":[e,n,r]}),Equals:(e,n)=>({"Fn::Equals":[e,n]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},iu={AccountId:{Ref:"AWS::AccountId"},Region:{Ref:"AWS::Region"},StackId:{Ref:"AWS::StackId"},StackName:{Ref:"AWS::StackName"},NotificationARNs:{Ref:"AWS::NotificationARNs"},Partition:{Ref:"AWS::Partition"},URLSuffix:{Ref:"AWS::URLSuffix"},NoValue:{Ref:"AWS::NoValue"}};function l(e){let{slug:n,environment:r,resourceType:i,timestamp:a,suffix:s}=e,c=[n,r,i];if(a)c.push(a);if(s)c.push(s);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function bm(){return Date.now().toString()}function Sm(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function T(e,n){return e.project.stackName??`${e.project.slug}-${n}`}function ua(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function pa(e,n){return`${e.project.slug}-${n}`}function ma(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function vm(e,n,r,i){return i??`${e}-${n}-${r}`}function Cm(e,n){return`${e}-${n}-deploy`}function Oe(e,n){return`${e.project.slug}-${n}-app`}function ga(e,n){return`${e}-${n}-deployments`}function Li(e,n){return`${e}-${n}-assets`}class ou{nodes=new Map;addResource(e,n){let r=this.extractDependencies(n);this.nodes.set(e,{logicalId:e,resource:n,dependencies:r})}extractDependencies(e){let n=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((r)=>n.add(r));else n.add(e.DependsOn);return this.findReferences(e.Properties||{},n),n}findReferences(e,n){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))n.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))n.add(e["Fn::GetAtt"][0]);for(let r of Object.values(e))if(typeof r==="object")this.findReferences(r,n)}topologicalSort(){let e=[],n=new Set,r=new Set,i=(a)=>{if(n.has(a))return;if(r.has(a))throw Error(`Circular dependency detected: ${a}`);r.add(a);let s=this.nodes.get(a);if(s)for(let c of s.dependencies)i(c);r.delete(a),n.add(a),e.push(a)};for(let a of this.nodes.keys())i(a);return e}validate(){for(let[e,n]of this.nodes.entries())for(let r of n.dependencies)if(!this.nodes.has(r))throw Error(`Resource "${e}" depends on "${r}" which does not exist`)}getDependents(e){let n=[];for(let[r,i]of this.nodes.entries())if(i.dependencies.has(e))n.push(r);return n}}function Tm(e,n){let r=[],i=[],a=[],s=[],c=[],u=e.Resources||{},d=n.Resources||{},m=new Set([...Object.keys(u),...Object.keys(d)]);for(let g of m){let y=u[g],f=d[g];if(!y&&f)r.push({logicalId:g,action:"add",resourceType:f.Type});else if(y&&!f)i.push({logicalId:g,action:"remove",resourceType:y.Type});else if(y&&f)if(y.Type!==f.Type)s.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=sn(y.Properties||{},f.Properties||{});if(h.length>0)if(Tr(y.Type,h))s.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else a.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Rr([...i,...s,...a]);return{added:r,removed:i,updated:a,replaced:s,unchanged:c,summary:{totalChanges:r.length+i.length+a.length+s.length,requiresReplacement:s.length>0,dangerousChanges:p}}}function sn(e,n,r=""){let i=[],a=new Set([...Object.keys(e),...Object.keys(n)]);for(let s of a){let c=r?`${r}.${s}`:s,u=e[s],d=n[s];if(u===void 0&&d!==void 0)i.push({path:c,oldValue:void 0,newValue:d});else if(u!==void 0&&d===void 0)i.push({path:c,oldValue:u,newValue:void 0});else if(typeof u!==typeof d)i.push({path:c,oldValue:u,newValue:d});else if(typeof u==="object"&&u!==null)if(Array.isArray(u)&&Array.isArray(d)){if(JSON.stringify(u)!==JSON.stringify(d))i.push({path:c,oldValue:u,newValue:d})}else if(!Array.isArray(u)&&!Array.isArray(d)){let m=sn(u,d,c);i.push(...m)}else i.push({path:c,oldValue:u,newValue:d});else if(u!==d)i.push({path:c,oldValue:u,newValue:d})}return i}function Tr(e,n){let i={"AWS::S3::Bucket":new Set(["BucketName"]),"AWS::DynamoDB::Table":new Set(["TableName","KeySchema"]),"AWS::RDS::DBInstance":new Set(["DBInstanceIdentifier","DBName","Engine"]),"AWS::Lambda::Function":new Set(["FunctionName"]),"AWS::EC2::Instance":new Set(["ImageId","InstanceType","KeyName"]),"AWS::ECS::TaskDefinition":new Set(["Family","ContainerDefinitions"]),"AWS::ElastiCache::CacheCluster":new Set(["CacheNodeType","Engine"]),"AWS::CloudFront::Distribution":new Set([]),"AWS::Route53::HostedZone":new Set(["Name"]),"AWS::IAM::Role":new Set(["RoleName","Path"]),"AWS::KMS::Key":new Set(["KeyPolicy"]),"AWS::Cognito::UserPool":new Set(["UserPoolName"]),"AWS::OpenSearchService::Domain":new Set(["DomainName"])}[e];if(!i)return!1;for(let a of n){let s=a.path.split(".")[0];if(i.has(s))return!0}return!1}function Rr(e){let n=[];for(let r of e){if(r.action==="remove"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"||r.resourceType==="AWS::ElastiCache::CacheCluster"))n.push(`Removing ${r.resourceType} ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"))n.push(`Replacing ${r.resourceType} ${r.logicalId} - data loss risk!`);if((r.action==="remove"||r.action==="replace")&&r.resourceType==="AWS::S3::Bucket")n.push(`${r.action==="remove"?"Removing":"Replacing"} S3 bucket ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&r.resourceType==="AWS::EC2::Instance")n.push(`Replacing EC2 instance ${r.logicalId} - downtime expected`);if(r.action==="update"&&r.resourceType==="AWS::EC2::SecurityGroup")n.push(`Updating security group ${r.logicalId} - may affect connectivity`);if((r.action==="update"||r.action==="replace")&&(r.resourceType==="AWS::IAM::Role"||r.resourceType==="AWS::IAM::Policy"))n.push(`Modifying IAM ${r.resourceType.split("::")[2]} ${r.logicalId} - may affect permissions`)}return n}function Em(e){let n=[];if(n.push(`=== Stack Update Analysis ===
6
+ `}return i}}function tu(e){let n=[],r=[],i=[];if(gr(e,n),e.Resources)yr(e.Resources,n,r);else n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)fr(e.Parameters,n,r);if(e.Outputs)hr(e.Outputs,n);br(e,n);let a=Sr(e);if(a.length>0)for(let s of a)n.push({path:"Resources",message:`Circular dependency detected: ${s.join(" → ")}`,severity:"error"});return Cr(e,r,i),{valid:n.length===0,errors:n,warnings:r,info:i}}function gr(e,n){if(!e.AWSTemplateFormatVersion)n.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")n.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function yr(e,n,r){let i=Object.keys(e);if(i.length===0){n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(i.length>500)r.push({path:"Resources",message:`Template contains ${i.length} resources (limit is 500)`,severity:"warning"});for(let a of i){let s=e[a];if(!/^[a-zA-Z0-9]+$/.test(a))n.push({path:`Resources.${a}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!s.Type)n.push({path:`Resources.${a}.Type`,message:"Resource Type is required",severity:"error"});else if(!s.Type.startsWith("AWS::")&&!s.Type.startsWith("Custom::"))n.push({path:`Resources.${a}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(s.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(s.DeletionPolicy))n.push({path:`Resources.${a}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!s.DeletionPolicy&&an(s.Type))r.push({path:`Resources.${a}.DeletionPolicy`,message:`${s.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function fr(e,n,r){let i=Object.keys(e);if(i.length>200)r.push({path:"Parameters",message:`Template contains ${i.length} parameters (limit is 200)`,severity:"warning"});for(let a of i){let s=e[a];if(!s.Type)n.push({path:`Parameters.${a}.Type`,message:"Parameter Type is required",severity:"error"});let c=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(s.Type&&!c.includes(s.Type))n.push({path:`Parameters.${a}.Type`,message:`Invalid parameter type: ${s.Type}`,severity:"error"})}}function hr(e,n){let r=Object.keys(e);for(let i of r)if(!e[i].Value)n.push({path:`Outputs.${i}.Value`,message:"Output Value is required",severity:"error"})}function br(e,n){let r=e.Resources||{},i=e.Parameters||{},a=new Set(Object.keys(r)),s=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!a.has(m)&&!s.has(m)&&m!=="AWS::Region"&&m!=="AWS::AccountId"&&m!=="AWS::StackName"&&m!=="AWS::StackId"&&m!=="AWS::URLSuffix"&&m!=="AWS::Partition"&&m!=="AWS::NoValue")n.push({path:d,message:`Reference to non-existent resource or parameter: ${m}`,severity:"error"})}if(u["Fn::GetAtt"]){let m=u["Fn::GetAtt"];if(Array.isArray(m)&&m.length>=1){let p=m[0];if(!a.has(p))n.push({path:d,message:`GetAtt references non-existent resource: ${p}`,severity:"error"})}}for(let m in u)c(u[m],`${d}.${m}`)}for(let u in r)c(r[u],`Resources.${u}`);if(e.Outputs)for(let u in e.Outputs)c(e.Outputs[u],`Outputs.${u}`)}function Sr(e){let n=e.Resources||{},r=new Map;for(let u in n){let d=new Set,m=n[u];if(m.DependsOn)if(Array.isArray(m.DependsOn))m.DependsOn.forEach((g)=>d.add(g));else d.add(m.DependsOn);Ar(m).forEach((g)=>d.add(g)),r.set(u,d)}let i=[],a=new Set,s=new Set;function c(u,d){a.add(u),s.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!a.has(p))c(p,[...d]);else if(s.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}s.delete(u)}for(let u of r.keys())if(!a.has(u))c(u,[]);return i}function Ar(e){let n=new Set;function r(i){if(typeof i!=="object"||i===null)return;if(i.Ref&&typeof i.Ref==="string"){if(!i.Ref.startsWith("AWS::"))n.add(i.Ref)}if(i["Fn::GetAtt"]&&Array.isArray(i["Fn::GetAtt"]))n.add(i["Fn::GetAtt"][0]);for(let a in i)r(i[a])}return r(e),n}function an(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function Cr(e,n,r){let i=e.Resources||{};if(!e.Description)r.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let a in i){let s=i[a],c=s.Properties;if(c&&!c.Tags&&vr(s.Type))r.push({path:`Resources.${a}`,message:`Consider adding Tags to ${s.Type}`,severity:"info"});if(an(s.Type)){if(s.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${a}`,message:"S3 bucket should enable encryption",severity:"warning"});if(s.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${a}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function vr(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function ru(e){let n=[],r=[],i=[],a=Buffer.byteLength(e,"utf8"),s=a/1024,c=51200,u=460800;if(a>460800)n.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(a>51200)r.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:n.length===0,errors:n,warnings:r,info:i}}function nu(e){let n=[],r=[],i=[],a=e.Resources||{},s=e.Parameters||{},c=e.Outputs||{};if(Object.keys(a).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(a).length} resources (limit is 500)`,severity:"error"});if(Object.keys(s).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(s).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(c).length>200)n.push({path:"Outputs",message:`Template has ${Object.keys(c).length} outputs (limit is 200)`,severity:"error"});return{valid:n.length===0,errors:n,warnings:r,info:i}}var 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})},iu={AccountId:{Ref:"AWS::AccountId"},Region:{Ref:"AWS::Region"},StackId:{Ref:"AWS::StackId"},StackName:{Ref:"AWS::StackName"},NotificationARNs:{Ref:"AWS::NotificationARNs"},Partition:{Ref:"AWS::Partition"},URLSuffix:{Ref:"AWS::URLSuffix"},NoValue:{Ref:"AWS::NoValue"}};function l(e){let{slug:n,environment:r,resourceType:i,timestamp:a,suffix:s}=e,c=[n,r,i];if(a)c.push(a);if(s)c.push(s);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function bm(){return Date.now().toString()}function Sm(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function T(e,n){return e.project.stackName??`${e.project.slug}-${n}`}function ua(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function pa(e,n){return`${e.project.slug}-${n}`}function ma(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function vm(e,n,r,i){return i??`${e}-${n}-${r}`}function Cm(e,n){return`${e}-${n}-deploy`}function Oe(e,n){return`${e.project.slug}-${n}-app`}function ga(e,n){return`${e}-${n}-deployments`}function Li(e,n){return`${e}-${n}-assets`}class ou{nodes=new Map;addResource(e,n){let r=this.extractDependencies(n);this.nodes.set(e,{logicalId:e,resource:n,dependencies:r})}extractDependencies(e){let n=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((r)=>n.add(r));else n.add(e.DependsOn);return this.findReferences(e.Properties||{},n),n}findReferences(e,n){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))n.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))n.add(e["Fn::GetAtt"][0]);for(let r of Object.values(e))if(typeof r==="object")this.findReferences(r,n)}topologicalSort(){let e=[],n=new Set,r=new Set,i=(a)=>{if(n.has(a))return;if(r.has(a))throw Error(`Circular dependency detected: ${a}`);r.add(a);let s=this.nodes.get(a);if(s)for(let c of s.dependencies)i(c);r.delete(a),n.add(a),e.push(a)};for(let a of this.nodes.keys())i(a);return e}validate(){for(let[e,n]of this.nodes.entries())for(let r of n.dependencies)if(!this.nodes.has(r))throw Error(`Resource "${e}" depends on "${r}" which does not exist`)}getDependents(e){let n=[];for(let[r,i]of this.nodes.entries())if(i.dependencies.has(e))n.push(r);return n}}function Tm(e,n){let r=[],i=[],a=[],s=[],c=[],u=e.Resources||{},d=n.Resources||{},m=new Set([...Object.keys(u),...Object.keys(d)]);for(let g of m){let y=u[g],f=d[g];if(!y&&f)r.push({logicalId:g,action:"add",resourceType:f.Type});else if(y&&!f)i.push({logicalId:g,action:"remove",resourceType:y.Type});else if(y&&f)if(y.Type!==f.Type)s.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=sn(y.Properties||{},f.Properties||{});if(h.length>0)if(Tr(y.Type,h))s.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else a.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Rr([...i,...s,...a]);return{added:r,removed:i,updated:a,replaced:s,unchanged:c,summary:{totalChanges:r.length+i.length+a.length+s.length,requiresReplacement:s.length>0,dangerousChanges:p}}}function sn(e,n,r=""){let i=[],a=new Set([...Object.keys(e),...Object.keys(n)]);for(let s of a){let c=r?`${r}.${s}`:s,u=e[s],d=n[s];if(u===void 0&&d!==void 0)i.push({path:c,oldValue:void 0,newValue:d});else if(u!==void 0&&d===void 0)i.push({path:c,oldValue:u,newValue:void 0});else if(typeof u!==typeof d)i.push({path:c,oldValue:u,newValue:d});else if(typeof u==="object"&&u!==null)if(Array.isArray(u)&&Array.isArray(d)){if(JSON.stringify(u)!==JSON.stringify(d))i.push({path:c,oldValue:u,newValue:d})}else if(!Array.isArray(u)&&!Array.isArray(d)){let m=sn(u,d,c);i.push(...m)}else i.push({path:c,oldValue:u,newValue:d});else if(u!==d)i.push({path:c,oldValue:u,newValue:d})}return i}function Tr(e,n){let i={"AWS::S3::Bucket":new Set(["BucketName"]),"AWS::DynamoDB::Table":new Set(["TableName","KeySchema"]),"AWS::RDS::DBInstance":new Set(["DBInstanceIdentifier","DBName","Engine"]),"AWS::Lambda::Function":new Set(["FunctionName"]),"AWS::EC2::Instance":new Set(["ImageId","InstanceType","KeyName"]),"AWS::ECS::TaskDefinition":new Set(["Family","ContainerDefinitions"]),"AWS::ElastiCache::CacheCluster":new Set(["CacheNodeType","Engine"]),"AWS::CloudFront::Distribution":new Set([]),"AWS::Route53::HostedZone":new Set(["Name"]),"AWS::IAM::Role":new Set(["RoleName","Path"]),"AWS::KMS::Key":new Set(["KeyPolicy"]),"AWS::Cognito::UserPool":new Set(["UserPoolName"]),"AWS::OpenSearchService::Domain":new Set(["DomainName"])}[e];if(!i)return!1;for(let a of n){let s=a.path.split(".")[0];if(i.has(s))return!0}return!1}function Rr(e){let n=[];for(let r of e){if(r.action==="remove"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"||r.resourceType==="AWS::ElastiCache::CacheCluster"))n.push(`Removing ${r.resourceType} ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"))n.push(`Replacing ${r.resourceType} ${r.logicalId} - data loss risk!`);if((r.action==="remove"||r.action==="replace")&&r.resourceType==="AWS::S3::Bucket")n.push(`${r.action==="remove"?"Removing":"Replacing"} S3 bucket ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&r.resourceType==="AWS::EC2::Instance")n.push(`Replacing EC2 instance ${r.logicalId} - downtime expected`);if(r.action==="update"&&r.resourceType==="AWS::EC2::SecurityGroup")n.push(`Updating security group ${r.logicalId} - may affect connectivity`);if((r.action==="update"||r.action==="replace")&&(r.resourceType==="AWS::IAM::Role"||r.resourceType==="AWS::IAM::Policy"))n.push(`Modifying IAM ${r.resourceType.split("::")[2]} ${r.logicalId} - may affect permissions`)}return n}function Em(e){let n=[];if(n.push(`=== Stack Update Analysis ===
7
7
  `),e.summary.totalChanges===0)return n.push(`No changes detected.
8
8
  `),n.join(`
9
9
  `);if(n.push(`Total changes: ${e.summary.totalChanges}`),n.push(`Requires replacement: ${e.summary.requiresReplacement?"Yes":"No"}
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 Ge,readdirSync as Pr}from"node:fs";import{join as de}from"node:path";class Ve{static createBucket(e){let{name:n,bucketName:r,slug:i,environment:a,public:s=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,y=r??l({slug:i,environment:a,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(!s)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(s)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 a={...r,Event:i};e.Properties.NotificationConfiguration.LambdaConfigurations.push(a)}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:a,retentionDays:s,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:s};if(m&&m<s)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}]}}},I=l({slug:r,environment:i,resourceType:"backup-selection",suffix:n}),D=o(I),N=a.map((F)=>R.GetAtt(F,"Arn")),M={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:R.Ref(P),BackupSelection:{SelectionName:I,IamRoleArn:R.GetAtt(h,"Arn"),Resources:N}}};return{vault:y,plan:v,selection:M,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:a,protocol:s="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:a,Protocol:s}},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,a=i||l({slug:n,environment:r,resourceType:"s3",suffix:"docs"}),s=o(a);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:a,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:s}}static createEmailBucket(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"s3",suffix:"email"}),a=o(i),s={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(a),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:R.Join("",[R.GetAtt(a,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":R.Ref("AWS::AccountId")}}}]}}};return{bucket:s,bucketPolicy:c,logicalId:a}}static docsExist(e={}){let{projectRoot:n=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let i of r){let a=de(n,i);if(Ge(a)){let s=["dist","build",".bunpress/dist","_site","out","public"];for(let c of s){let u=de(a,c);if(Ge(u))try{if(Pr(u).length>0)return{exists:!0,path:a,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:a,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let n=Ve.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!n.exists)return{bucket:null,logicalId:null,docsInfo:n};let r=Ve.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:a,encryptionKeyArn:s}=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:s?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:s}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:i?{Status:"Enabled"}:void 0,LifecycleConfiguration:a?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:a}]}: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",a=r.docs||"docs/dist",s=r.private||"private";return{web:{exists:Ge(de(n,i)),path:de(n,i)},docs:{exists:Ge(de(n,a)),path:de(n,a)},private:{exists:Ge(de(n,s)),path:de(n,s)}}}static createDeploymentBuckets(e){let{slug:n,environment:r,domain:i,projectRoot:a,paths:s}=e,c=Ve.checkSourcePaths({projectRoot:a,paths:s}),u={},d={web:!1,docs:!1,private:!1},m=Ve.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=Ve.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=Ve.createPrivateBucket({slug:n,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class At{static createRepository(e){let{name:n,slug:r,environment:i,scanOnPush:a=!0,imageMutability:s="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:s,ImageScanningConfiguration:{ScanOnPush:a},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)y.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(At.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(At.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:a=[],healthCheckEndpoint:s="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...a],g=m||`bun run ${r}`,y=`# Multi-stage build for Bun application
11
+ `)}import{existsSync as Ge,readdirSync as Pr}from"node:fs";import{join as de}from"node:path";class Ve{static createBucket(e){let{name:n,bucketName:r,slug:i,environment:a,public:s=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,y=r??l({slug:i,environment:a,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(!s)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(s)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 a={...r,Event:i};e.Properties.NotificationConfiguration.LambdaConfigurations.push(a)}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:a,retentionDays:s,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:s};if(m&&m<s)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),N=a.map((F)=>P.GetAtt(F,"Arn")),M={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:P.Ref(E),BackupSelection:{SelectionName:I,IamRoleArn:P.GetAtt(h,"Arn"),Resources:N}}};return{vault:y,plan:v,selection:M,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:a,protocol:s="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:a,Protocol:s}},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,a=i||l({slug:n,environment:r,resourceType:"s3",suffix:"docs"}),s=o(a);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:a,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:s}}static createEmailBucket(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"s3",suffix:"email"}),a=o(i),s={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(a),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:P.Join("",[P.GetAtt(a,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":P.Ref("AWS::AccountId")}}}]}}};return{bucket:s,bucketPolicy:c,logicalId:a}}static docsExist(e={}){let{projectRoot:n=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let i of r){let a=de(n,i);if(Ge(a)){let s=["dist","build",".bunpress/dist","_site","out","public"];for(let c of s){let u=de(a,c);if(Ge(u))try{if(Pr(u).length>0)return{exists:!0,path:a,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:a,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let n=Ve.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!n.exists)return{bucket:null,logicalId:null,docsInfo:n};let r=Ve.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:a,encryptionKeyArn:s}=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:s?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:s}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:i?{Status:"Enabled"}:void 0,LifecycleConfiguration:a?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:a}]}: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",a=r.docs||"docs/dist",s=r.private||"private";return{web:{exists:Ge(de(n,i)),path:de(n,i)},docs:{exists:Ge(de(n,a)),path:de(n,a)},private:{exists:Ge(de(n,s)),path:de(n,s)}}}static createDeploymentBuckets(e){let{slug:n,environment:r,domain:i,projectRoot:a,paths:s}=e,c=Ve.checkSourcePaths({projectRoot:a,paths:s}),u={},d={web:!1,docs:!1,private:!1},m=Ve.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=Ve.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=Ve.createPrivateBucket({slug:n,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class At{static createRepository(e){let{name:n,slug:r,environment:i,scanOnPush:a=!0,imageMutability:s="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:s,ImageScanningConfiguration:{ScanOnPush:a},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)y.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(At.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(At.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:a=[],healthCheckEndpoint:s="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...a],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)=>At.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>At.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var fa=[400,403,404,416,429,500,502,503,504],tl=[500,502,503,504],rl=["GET","HEAD","OPTIONS"],wm="-failover-group",nl=["default","media-quality-based"],il={min:1,max:3},ol={min:1,max:10};function Wo(e){if(e===void 0)return[...tl];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${fa.join(", ")}). Omit it to use the default ${tl.join(", ")}.`);let n=e.filter((r)=>!fa.includes(r));if(n.length>0)throw Error(`CloudFront origin failover: ${n.join(", ")} ${n.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${fa.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function ha(e){let{primaryOriginId:n,secondaryOriginId:r}=e;if(!n||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(n===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${n}")`);let i=Wo(e.statusCodes);return on(e.selectionCriteria),{Id:e.groupId??`${n}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:i.length,Items:i}},Members:{Quantity:2,Items:[{OriginId:n},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function on(e,n="the origin group"){if(e===void 0)return;if(!nl.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${nl.join(", ")}.`)}function Ze(e,n,r){if(typeof e!=="number"||!Number.isInteger(e)||e<n.min||e>n.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${n.min} to ${n.max}, got ${JSON.stringify(e)}.`)}function it(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)Ze(e.connectionAttempts,il,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)Ze(e.connectionTimeout,ol,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Ko(e){return{Quantity:1,Items:[ha(e)]}}function Tn(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((a)=>!rl.includes(a.toUpperCase()));if(i.length>0)throw Error(`CloudFront origin failover: ${n} allows ${i.join(", ")}, but a cache behavior that targets an origin group may only allow ${rl.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Mi(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function _e(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function se(e){return typeof e==="string"?e:void 0}var Er=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function En(e,n="the distribution"){let r=_e(e.Origins),i=new Set(r.map((p)=>se(p.Id)).filter((p)=>!!p)),a=new Map(r.map((p)=>[se(p.Id)??"",p.DomainName])),s=r.some((p)=>se(p.Id)===void 0);for(let p of r){let g=se(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)Ze(p.ConnectionAttempts,il,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)Ze(p.ConnectionTimeout,ol,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=_e(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${n} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=se(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${n} has an origin group without an Id.`);let y=`${n} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${n} declares origin group "${g}" twice.`);if(i.has(g))throw Error(`CloudFront origin failover: ${y} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let f=p.Members,h=_e(f);if(h.length!==2||f?.Quantity!==void 0&&f.Quantity!==h.length)throw Error(`CloudFront origin failover: ${y} must have exactly 2 members (a primary and a secondary), it has ${h.length}${f?.Quantity!==void 0&&f.Quantity!==h.length?` with Quantity ${f.Quantity}`:""}.`);let S=h.map((E)=>se(E.OriginId));for(let E of S)if(E&&!i.has(E)&&!s)throw Error(`CloudFront origin failover: ${y} lists member "${E}", which is not an origin of this distribution. Origins: ${[...i].join(", ")||"(none)"}.`);if(S[0]&&S[0]===S[1])throw Error(`CloudFront origin failover: ${y} lists "${S[0]}" as both primary and secondary.`);let C=p.FailoverCriteria?.StatusCodes,P=_e(C);if(Wo(P),C?.Quantity!==void 0&&C.Quantity!==P.length)throw Error(`CloudFront origin failover: ${y} FailoverCriteria.StatusCodes.Quantity is ${C.Quantity} but it lists ${P.length} code(s).`);if(on(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let E of S){let v=E?se(a.get(E)):void 0;if(v&&!Er.test(v))throw Error(`CloudFront origin failover: ${y} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${E}" is ${v}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of _e(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let y=se(p.TargetOriginId);if(!y)continue;if(d.has(y))Tn(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!s&&u.every((f)=>se(f.Id)!==void 0))throw Error(`CloudFront: ${g} of ${n} targets "${y}", which is neither an origin nor an origin group of this distribution.`)}}class ze{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,y=l({slug:n,environment:r,resourceType:"cdn"}),f=o(y),h={Id:"DefaultOrigin",DomainName:i.domainName,OriginPath:i.originPath||"",...it(i,"the CDN origin")},S;if(i.type==="s3"){let P=`${f}OAC`;S={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${y}-oac`,Description:`Origin Access Control for ${y}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},h.OriginAccessControlId=R.Ref(P)}else if(i.type==="alb"||i.type==="custom")h.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let C={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${y}`,DefaultRootObject:"index.html",Origins:[h],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:m?"http2and3":"http2"}}};if(a&&s)C.Properties.DistributionConfig.Aliases=[a],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)C.Properties.DistributionConfig.CustomErrorResponses=c.map((P)=>({ErrorCode:P.errorCode,ResponseCode:P.responseCode,ResponsePagePath:P.responsePagePath}));if(d&&d.length>0)C.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((P)=>({EventType:P.event,LambdaFunctionARN:P.functionArn}));if(g)ze.addOriginFailover(C,g);return{distribution:C,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,a=i.TargetOriginId,s=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Tn(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===s))throw Error(`CloudFront origin failover: an origin with id "${s}" already exists`);let c=ha({primaryOriginId:a,secondaryOriginId:s,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(Mi(n.domainName)?"s3":"custom"),d={Id:s,DomainName:n.domainName,OriginPath:n.originPath||"",...it(n,"the failover origin")},m=it(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===a);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===a);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},i.TargetOriginId=c.Id,En(r),e}static setCustomDomain(e,n,r){return e.Properties.DistributionConfig.Aliases=[n],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,n){return e.Properties.DistributionConfig.CustomErrorResponses=n.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,n,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:n,LambdaFunctionARN:r}),e}static setCachePolicy(e,n){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${n.default||86400}s)`,e}static createSpaDistribution(e){return ze.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"edge-docs"}),a=o(i),s=o(`${i}-role`),c=o(`${i}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},d=`
94
+ `)}`}};static DockerfileTemplates={bunServer:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>At.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var fa=[400,403,404,416,429,500,502,503,504],tl=[500,502,503,504],rl=["GET","HEAD","OPTIONS"],wm="-failover-group",nl=["default","media-quality-based"],il={min:1,max:3},ol={min:1,max:10};function Wo(e){if(e===void 0)return[...tl];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${fa.join(", ")}). Omit it to use the default ${tl.join(", ")}.`);let n=e.filter((r)=>!fa.includes(r));if(n.length>0)throw Error(`CloudFront origin failover: ${n.join(", ")} ${n.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${fa.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function ha(e){let{primaryOriginId:n,secondaryOriginId:r}=e;if(!n||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(n===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${n}")`);let i=Wo(e.statusCodes);return on(e.selectionCriteria),{Id:e.groupId??`${n}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:i.length,Items:i}},Members:{Quantity:2,Items:[{OriginId:n},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function on(e,n="the origin group"){if(e===void 0)return;if(!nl.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${nl.join(", ")}.`)}function Ze(e,n,r){if(typeof e!=="number"||!Number.isInteger(e)||e<n.min||e>n.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${n.min} to ${n.max}, got ${JSON.stringify(e)}.`)}function it(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)Ze(e.connectionAttempts,il,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)Ze(e.connectionTimeout,ol,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Ko(e){return{Quantity:1,Items:[ha(e)]}}function Tn(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((a)=>!rl.includes(a.toUpperCase()));if(i.length>0)throw Error(`CloudFront origin failover: ${n} allows ${i.join(", ")}, but a cache behavior that targets an origin group may only allow ${rl.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Mi(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function _e(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function se(e){return typeof e==="string"?e:void 0}var Er=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function En(e,n="the distribution"){let r=_e(e.Origins),i=new Set(r.map((p)=>se(p.Id)).filter((p)=>!!p)),a=new Map(r.map((p)=>[se(p.Id)??"",p.DomainName])),s=r.some((p)=>se(p.Id)===void 0);for(let p of r){let g=se(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)Ze(p.ConnectionAttempts,il,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)Ze(p.ConnectionTimeout,ol,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=_e(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${n} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=se(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${n} has an origin group without an Id.`);let y=`${n} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${n} declares origin group "${g}" twice.`);if(i.has(g))throw Error(`CloudFront origin failover: ${y} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let f=p.Members,h=_e(f);if(h.length!==2||f?.Quantity!==void 0&&f.Quantity!==h.length)throw Error(`CloudFront origin failover: ${y} must have exactly 2 members (a primary and a secondary), it has ${h.length}${f?.Quantity!==void 0&&f.Quantity!==h.length?` with Quantity ${f.Quantity}`:""}.`);let S=h.map((w)=>se(w.OriginId));for(let w of S)if(w&&!i.has(w)&&!s)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=_e(C);if(Wo(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(on(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let w of S){let v=w?se(a.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 _e(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let y=se(p.TargetOriginId);if(!y)continue;if(d.has(y))Tn(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!s&&u.every((f)=>se(f.Id)!==void 0))throw Error(`CloudFront: ${g} of ${n} targets "${y}", which is neither an origin nor an origin group of this distribution.`)}}class ze{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,y=l({slug:n,environment:r,resourceType:"cdn"}),f=o(y),h={Id:"DefaultOrigin",DomainName:i.domainName,OriginPath:i.originPath||"",...it(i,"the CDN origin")},S;if(i.type==="s3"){let 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(a&&s)C.Properties.DistributionConfig.Aliases=[a],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)C.Properties.DistributionConfig.CustomErrorResponses=c.map((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)ze.addOriginFailover(C,g);return{distribution:C,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,a=i.TargetOriginId,s=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Tn(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===s))throw Error(`CloudFront origin failover: an origin with id "${s}" already exists`);let c=ha({primaryOriginId:a,secondaryOriginId:s,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(Mi(n.domainName)?"s3":"custom"),d={Id:s,DomainName:n.domainName,OriginPath:n.originPath||"",...it(n,"the failover origin")},m=it(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===a);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===a);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},i.TargetOriginId=c.Id,En(r),e}static setCustomDomain(e,n,r){return e.Properties.DistributionConfig.Aliases=[n],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,n){return e.Properties.DistributionConfig.CustomErrorResponses=n.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,n,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:n,LambdaFunctionARN:r}),e}static setCachePolicy(e,n){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${n.default||86400}s)`,e}static createSpaDistribution(e){return ze.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"edge-docs"}),a=o(i),s=o(`${i}-role`),c=o(`${i}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},d=`
95
95
  'use strict';
96
96
 
97
97
  exports.handler = async (event) => {
@@ -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:R.GetAtt(s,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:a,roleLogicalId:s,versionLogicalId:c}}static createDocsDistribution(e){let{slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,lambdaEdgeFunctionArn:c}=e,u=ze.createDistribution({slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,comment:`Docs CDN for ${n}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(c)ze.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:a,certificateArn:s,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(a&&s)C.Properties.DistributionConfig.Aliases=[a],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:C,logicalId:y}}static createMultiOriginDistribution(e){let{slug:n,environment:r,s3BucketDomainName:i,albDomainName:a,apiPathPattern:s="/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:a,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:s,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:a,customHeaders:s={},forwardHeaders:c=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:u={default:0,max:0,min:0}}=n,d=Object.entries(s).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:a,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 a=e.Properties.DistributionConfig.Origins?.find((s)=>s.Id===n);if(a){if(!a.OriginCustomHeaders)a.OriginCustomHeaders=[];a.OriginCustomHeaders.push({HeaderName:r,HeaderValue:i})}return e}static EdgeFunctionTemplates={docsOriginRequest:`
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:P.GetAtt(s,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:a,roleLogicalId:s,versionLogicalId:c}}static createDocsDistribution(e){let{slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,lambdaEdgeFunctionArn:c}=e,u=ze.createDistribution({slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,comment:`Docs CDN for ${n}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(c)ze.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:a,certificateArn:s,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(([E,w])=>({HeaderName:E,HeaderValue:w})),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(a&&s)C.Properties.DistributionConfig.Aliases=[a],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:C,logicalId:y}}static createMultiOriginDistribution(e){let{slug:n,environment:r,s3BucketDomainName:i,albDomainName:a,apiPathPattern:s="/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(([E,w])=>({HeaderName:E,HeaderValue:w})),h={Id:"S3Origin",DomainName:i,OriginAccessControlId:P.Ref(g)},S={Id:"ALBOrigin",DomainName:a,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:s,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:a,customHeaders:s={},forwardHeaders:c=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:u={default:0,max:0,min:0}}=n,d=Object.entries(s).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:a,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 a=e.Properties.DistributionConfig.Origins?.find((s)=>s.Id===n);if(a){if(!a.OriginCustomHeaders)a.OriginCustomHeaders=[];a.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:a="GET_HEAD",cachedMethods:s="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:ze.Config.allowedMethods(a),CachedMethods:ze.Config.cachedMethods(s),ForwardedValues:{QueryString:u,Headers:d,Cookies:ze.Config.cookies(r,i)}}}};static applyConfig(e,n){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(n.ttl)r.MinTTL=n.ttl.min,r.MaxTTL=n.ttl.max,r.DefaultTTL=n.ttl.default;if(n.compress!==void 0)r.Compress=n.compress;if(n.allowedMethods)r.AllowedMethods=ze.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=ze.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=ze.Config.cookies(n.cookies,n.allowedCookies)}return e}}var su=[403,404,500,502,503,504],Jo="TsCloud::StorageFailover",Xo="AllowCloudFrontFailoverRead",wr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Ir=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function ya(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,a=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${a}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!wr.test(n.region))throw Error(`${a}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${a}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let s=n.bucket??`${r}-${n.region}`;if(!Ir.test(s)||s.includes("..")){let c=n.bucket===void 0&&s.length>63?` The default name (<primary bucket>-<region>) is ${s.length} characters; S3 allows 63. Set ${a}.failover.bucket.`:"";throw Error(`${a}.failover: "${s}" is not a valid S3 bucket name.${c}`)}if(s===r)throw Error(`${a}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:s,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:Wo(n.statusCodes??su),primaryConnection:it(n,`${a}.failover`)}}function ba(e,n){return`${e}.s3.${n}.amazonaws.com`}function Sa(e){let n=`arn:aws:s3:::${e.primaryBucket}`,r=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:n},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${n}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function va(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Ca(e){return{Sid:Xo,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function Ta(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Jo];return Array.isArray(r)?r:[]}class Ae{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:a}=e,s=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${s}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:a||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:a,ttl:s,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${a}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:a}};if(n)m.Properties.HostedZoneId=n;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=s||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,n,r){return Ae.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:i,values:[n]})}static createWwwRedirect(e,n){return Ae.createRecord({hostedZoneId:n,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:i,values:n.map((a)=>`${a.priority} ${a.server}`)})}static createTxtRecord(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:i,values:[`"${n}"`]})}static createSpfRecord(e,n,r){return Ae.createTxtRecord(e,n,r)}static createDmarcRecord(e,n,r,i){let a=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Ae.createTxtRecord(`_dmarc.${e}`,a,i)}static createS3WebsiteAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,n){return`${e}.s3-website-${n}.amazonaws.com`}static createStoreRecord(e,n,r){return Ae.createCname(`store.${e}`,n,r)}static createApiRecord(e,n,r){return Ae.createCname(`api.${e}`,n,r)}static createDocsRecord(e,n,r){return Ae.createCname(`docs.${e}`,n,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:n,subdomains:r=[],slug:i,environment:a,validationMethod:s="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:a,resourceType:"acm"}),d=o(`${u}-${n.replace(/\./g,"")}`),m=[n];for(let g of r)if(g==="*")m.push(`*.${n}`);else m.push(`${g}.${n}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n,SubjectAlternativeNames:m,ValidationMethod:s}};if(s==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:n,slug:r,environment:i,enableRotation:a=!0,multiRegion:s=!1}=e,c=l({slug:r,environment:i,resourceType:"kms"}),u=o(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:R.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},m={Type:"AWS::KMS::Key",Properties:{Description:n,Enabled:!0,EnableKeyRotation:a,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:s}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:R.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:a="allow"}=e,s=l({slug:n,environment:r,resourceType:"waf"}),c=o(s);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:s,Scope:i,DefaultAction:a==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-metric`}}},logicalId:c}}static setRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockCountries(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{GeoMatchStatement:{CountryCodes:n.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockIpAddresses(e,n,r,i){let a=l({slug:r,environment:i,resourceType:"ipset"}),s=o(`${a}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${a}-${n.name}`,Scope:e.Properties.Scope,IPAddressVersion:n.ipVersion||"IPV4",Addresses:n.ipAddresses,Description:`Blocked IPs for ${n.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{IPSetReferenceStatement:{Arn:R.GetAtt(s,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:s}}static addManagedRules(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:n.vendorName,Name:n.ruleName}};if(n.excludedRules&&n.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=n.excludedRules.map((i)=>({Name:i}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r=n.paths.map((i)=>({SearchString:i,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((i)=>({ByteMatchStatement:i}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static setHeaderRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:n.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(n.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:n.headerValue,FieldToMatch:{SingleHeader:{Name:n.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static protectLoginEndpoint(e,n){let{loginPaths:r,priority:i,requestsPerMinute:a=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:a=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:a=!1,enableRateLimiting:s=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:n,environment:r,scope:i,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),a)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(s)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function au(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function cu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${au(e)?"arm64":"x86_64"}`}function sl(e="t3.micro"){return`{{resolve:ssm:${cu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:a=sl(i),keyName:s,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,y=l({slug:n,environment:r,resourceType:"ec2"}),f=o(y),h={Type:"AWS::EC2::Instance",Properties:{ImageId:a,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(s)h.Properties.KeyName=s;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=R.Base64(d);return h.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:h,logicalId:f}}static createSecurityGroup(e){let{slug:n,environment:r,vpcId:i,description:a,ingress:s=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:a||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(s.length>0)m.Properties.SecurityGroupIngress=s.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,n,r){return b.createSecurityGroup({slug:e,environment:n,vpcId:r,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:n,environment:r,scheme:i="internet-facing",subnets:a,securityGroups:s,type:c="application"}=e,u=l({slug:n,environment:r,resourceType:"alb"}),d=o(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:i,Type:c,Subnets:a,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s)m.Properties.SecurityGroups=s;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:a="HTTP",vpcId:s,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,y=l({slug:n,environment:r,resourceType:"tg"}),f=o(y);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:y,Port:i,Protocol:a,VpcId:s,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:a,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}},logicalId:f}}static createListener(e,n){let{port:r,protocol:i="HTTP",certificateArn:a,defaultTargetGroupArn:s}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:R.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}};if(i==="HTTPS"&&a)u.Properties.Certificates=[{CertificateArn:a}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,n){let r=l({slug:e,environment:n,resourceType:"ecs-cluster"}),i=o(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createFargateService(e){let{slug:n,environment:r,image:i,cpu:a="256",memory:s="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:y,securityGroups:f,targetGroupArn:h}=e,{cluster:S,logicalId:C}=b.createEcsCluster(n,r),P=l({slug:n,environment:r,resourceType:"fargate"}),E=o(`${P}-execution-role`),v={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}},I=o(`${P}-task-role`),D={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},N=o(`${P}-task`),M={Type:"AWS::ECS::TaskDefinition",Properties:{Family:P,TaskRoleArn:R.GetAtt(I,"Arn"),ExecutionRoleArn:R.GetAtt(E,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a,Memory:s,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([G,U])=>({Name:G,Value:U})),Secrets:m.map((G)=>({Name:G.name,ValueFrom:G.valueFrom}))}],Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(p)M.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)M.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":R.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let F=o(`${P}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:P,Cluster:R.Ref(C),TaskDefinition:R.Ref(N),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:y,SecurityGroups:f,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(h)O.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:n,ContainerPort:u}];return{cluster:S,taskDefinition:M,service:O,taskRole:D,executionRole:v,clusterLogicalId:C,taskDefinitionLogicalId:N,serviceLogicalId:F,taskRoleLogicalId:I,executionRoleLogicalId:E}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:a,code:s,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:n,environment:r,resourceType:"lambda"}),g=o(p),y=o(`${p}-role`),f={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(m)f.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:i,Role:R.GetAtt(y,"Arn"),Handler:a,Code:{...s.s3Bucket&&{S3Bucket:s.s3Bucket},...s.s3Key&&{S3Key:s.s3Key},...s.zipFile&&{ZipFile:s.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)h.Properties.Environment={Variables:d};if(m)h.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:h,role:f,logicalId:g,roleLogicalId:y}}static generateNodeServerUserData(e={}){let{nodeVersion:n="20",appRepo:r,environment:i={}}=e,a=Object.entries(i).map(([s,c])=>`echo "export ${s}='${c}'" >> /etc/environment`).join(`
200
+ `.trim()};static Config={ttl:(e)=>{let{min:n=0,max:r=86400,default:i=86400}=e;return{MinTTL:n,MaxTTL:r,DefaultTTL:i}},cookies:(e,n)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&n)r.WhitelistedNames=n;return r},allowedMethods:(e)=>{let n={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},cachedMethods:(e)=>{let n={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},ttlPresets:{static:{min:0,max:31536000,default:31536000},dynamic:{min:0,max:0,default:0},api:{min:0,max:3600,default:60},html:{min:0,max:86400,default:86400},images:{min:0,max:604800,default:604800}},cacheBehavior:(e)=>{let{ttl:n={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:i,allowedMethods:a="GET_HEAD",cachedMethods:s="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:ze.Config.allowedMethods(a),CachedMethods:ze.Config.cachedMethods(s),ForwardedValues:{QueryString:u,Headers:d,Cookies:ze.Config.cookies(r,i)}}}};static applyConfig(e,n){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(n.ttl)r.MinTTL=n.ttl.min,r.MaxTTL=n.ttl.max,r.DefaultTTL=n.ttl.default;if(n.compress!==void 0)r.Compress=n.compress;if(n.allowedMethods)r.AllowedMethods=ze.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=ze.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=ze.Config.cookies(n.cookies,n.allowedCookies)}return e}}var su=[403,404,500,502,503,504],Jo="TsCloud::StorageFailover",Xo="AllowCloudFrontFailoverRead",wr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Ir=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function ya(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,a=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${a}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!wr.test(n.region))throw Error(`${a}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${a}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let s=n.bucket??`${r}-${n.region}`;if(!Ir.test(s)||s.includes("..")){let c=n.bucket===void 0&&s.length>63?` The default name (<primary bucket>-<region>) is ${s.length} characters; S3 allows 63. Set ${a}.failover.bucket.`:"";throw Error(`${a}.failover: "${s}" is not a valid S3 bucket name.${c}`)}if(s===r)throw Error(`${a}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:s,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:Wo(n.statusCodes??su),primaryConnection:it(n,`${a}.failover`)}}function ba(e,n){return`${e}.s3.${n}.amazonaws.com`}function Sa(e){let n=`arn:aws:s3:::${e.primaryBucket}`,r=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:n},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${n}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function va(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Ca(e){return{Sid:Xo,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function Ta(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Jo];return Array.isArray(r)?r:[]}class Ae{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:a}=e,s=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${s}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:a||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:a,ttl:s,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${a}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:a}};if(n)m.Properties.HostedZoneId=n;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=s||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,n,r){return Ae.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:i,values:[n]})}static createWwwRedirect(e,n){return Ae.createRecord({hostedZoneId:n,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:i,values:n.map((a)=>`${a.priority} ${a.server}`)})}static createTxtRecord(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:i,values:[`"${n}"`]})}static createSpfRecord(e,n,r){return Ae.createTxtRecord(e,n,r)}static createDmarcRecord(e,n,r,i){let a=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Ae.createTxtRecord(`_dmarc.${e}`,a,i)}static createS3WebsiteAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,n){return`${e}.s3-website-${n}.amazonaws.com`}static createStoreRecord(e,n,r){return Ae.createCname(`store.${e}`,n,r)}static createApiRecord(e,n,r){return Ae.createCname(`api.${e}`,n,r)}static createDocsRecord(e,n,r){return Ae.createCname(`docs.${e}`,n,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:n,subdomains:r=[],slug:i,environment:a,validationMethod:s="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:a,resourceType:"acm"}),d=o(`${u}-${n.replace(/\./g,"")}`),m=[n];for(let g of r)if(g==="*")m.push(`*.${n}`);else m.push(`${g}.${n}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n,SubjectAlternativeNames:m,ValidationMethod:s}};if(s==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:n,slug:r,environment:i,enableRotation:a=!0,multiRegion:s=!1}=e,c=l({slug:r,environment:i,resourceType:"kms"}),u=o(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS: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:a,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:s}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:P.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:a="allow"}=e,s=l({slug:n,environment:r,resourceType:"waf"}),c=o(s);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:s,Scope:i,DefaultAction:a==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-metric`}}},logicalId:c}}static setRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockCountries(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{GeoMatchStatement:{CountryCodes:n.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockIpAddresses(e,n,r,i){let a=l({slug:r,environment:i,resourceType:"ipset"}),s=o(`${a}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${a}-${n.name}`,Scope:e.Properties.Scope,IPAddressVersion:n.ipVersion||"IPV4",Addresses:n.ipAddresses,Description:`Blocked IPs for ${n.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{IPSetReferenceStatement:{Arn:P.GetAtt(s,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:s}}static addManagedRules(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:n.vendorName,Name:n.ruleName}};if(n.excludedRules&&n.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=n.excludedRules.map((i)=>({Name:i}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r=n.paths.map((i)=>({SearchString:i,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((i)=>({ByteMatchStatement:i}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static setHeaderRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:n.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(n.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:n.headerValue,FieldToMatch:{SingleHeader:{Name:n.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static protectLoginEndpoint(e,n){let{loginPaths:r,priority:i,requestsPerMinute:a=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:a=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:a=!1,enableRateLimiting:s=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:n,environment:r,scope:i,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),a)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(s)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function au(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function cu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${au(e)?"arm64":"x86_64"}`}function sl(e="t3.micro"){return`{{resolve:ssm:${cu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:a=sl(i),keyName:s,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,y=l({slug:n,environment:r,resourceType:"ec2"}),f=o(y),h={Type:"AWS::EC2::Instance",Properties:{ImageId:a,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(s)h.Properties.KeyName=s;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=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:a,ingress:s=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:a||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(s.length>0)m.Properties.SecurityGroupIngress=s.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,n,r){return b.createSecurityGroup({slug:e,environment:n,vpcId:r,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:n,environment:r,scheme:i="internet-facing",subnets:a,securityGroups:s,type:c="application"}=e,u=l({slug:n,environment:r,resourceType:"alb"}),d=o(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:i,Type:c,Subnets:a,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s)m.Properties.SecurityGroups=s;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:a="HTTP",vpcId:s,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,y=l({slug:n,environment:r,resourceType:"tg"}),f=o(y);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:y,Port:i,Protocol:a,VpcId:s,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:a,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}},logicalId:f}}static createListener(e,n){let{port:r,protocol:i="HTTP",certificateArn:a,defaultTargetGroupArn:s}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:P.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}};if(i==="HTTPS"&&a)u.Properties.Certificates=[{CertificateArn:a}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,n){let r=l({slug:e,environment:n,resourceType:"ecs-cluster"}),i=o(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createFargateService(e){let{slug:n,environment:r,image:i,cpu:a="256",memory:s="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:y,securityGroups:f,targetGroupArn:h}=e,{cluster:S,logicalId:C}=b.createEcsCluster(n,r),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"}]}}},N=o(`${E}-task`),M={Type:"AWS::ECS::TaskDefinition",Properties:{Family:E,TaskRoleArn:P.GetAtt(I,"Arn"),ExecutionRoleArn:P.GetAtt(w,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a,Memory:s,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([G,U])=>({Name:G,Value:U})),Secrets:m.map((G)=>({Name:G.name,ValueFrom:G.valueFrom}))}],Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:r}]}};if(p)M.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)M.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":P.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let F=o(`${E}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:E,Cluster:P.Ref(C),TaskDefinition:P.Ref(N),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:M,service:O,taskRole:D,executionRole:v,clusterLogicalId:C,taskDefinitionLogicalId:N,serviceLogicalId:F,taskRoleLogicalId:I,executionRoleLogicalId:w}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:a,code:s,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:n,environment:r,resourceType:"lambda"}),g=o(p),y=o(`${p}-role`),f={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(m)f.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:i,Role:P.GetAtt(y,"Arn"),Handler:a,Code:{...s.s3Bucket&&{S3Bucket:s.s3Bucket},...s.s3Key&&{S3Key:s.s3Key},...s.zipFile&&{ZipFile:s.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)h.Properties.Environment={Variables:d};if(m)h.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:h,role:f,logicalId:g,roleLogicalId:y}}static generateNodeServerUserData(e={}){let{nodeVersion:n="20",appRepo:r,environment:i={}}=e,a=Object.entries(i).map(([s,c])=>`echo "export ${s}='${c}'" >> /etc/environment`).join(`
201
201
  `);return`#!/bin/bash
202
202
  # Update system
203
203
  yum update -y
@@ -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:a,keyName:s,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:a,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(s)h.Properties.KeyName=s;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:a,maxSize:s,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:a,MaxSize:s,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,a-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:S,logicalId:h}}static createScalingPolicy(e){let{slug:n,environment:r,autoScalingGroupName:i,policyType:a="TargetTrackingScaling",targetValue:s=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:a}};if(a==="TargetTrackingScaling")m.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:c},TargetValue:s};return{scalingPolicy:m,logicalId:d}}static AutoScaling={smallWebServer:(e,n,r,i,a)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:i,targetGroupArns:a,healthCheckType:a?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,n,r,i,a)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:i,targetGroupArns:a,healthCheckType:a?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,n,r,i,a)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:i,targetGroupArns:a,healthCheckType:a?"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,a=b.createFargateService(i);if(n.length>0){if(!a.executionRole.Properties.Policies)a.executionRole.Properties.Policies=[];if(a.executionRole.Properties.Policies.push(b.Secrets.createAccessPolicy(n)),r.length>0)a.executionRole.Properties.Policies.push(b.Secrets.createKmsPolicy(r))}return a}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:a,keyName:s,instanceType:c="t3.micro",imageId:u=sl(c),mountEfs:d,databaseTools:m=!1}=e,p=e.allowedCidrs??(s?["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((N)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:N,Description:`SSH access from ${N}`})),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
301
+ `}static createLaunchConfiguration(e){let{slug:n,environment:r,imageId:i,instanceType:a,keyName:s,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:a,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(s)h.Properties.KeyName=s;if(c)h.Properties.SecurityGroups=c;if(u)h.Properties.UserData=P.Base64(u);if(g)h.Properties.IamInstanceProfile=g;return{launchConfiguration:h,logicalId:f}}static createAutoScalingGroup(e){let{slug:n,environment:r,launchConfigurationName:i,minSize:a,maxSize:s,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:a,MaxSize:s,HealthCheckType:m,HealthCheckGracePeriod:p,Cooldown:g,Tags:[{Key:"Name",Value:f,PropagateAtLaunch:!0},{Key:"Environment",Value:r,PropagateAtLaunch:!0},...Object.entries(y).map(([C,E])=>({Key:C,Value:E,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,a-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:S,logicalId:h}}static createScalingPolicy(e){let{slug:n,environment:r,autoScalingGroupName:i,policyType:a="TargetTrackingScaling",targetValue:s=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:a}};if(a==="TargetTrackingScaling")m.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:c},TargetValue:s};return{scalingPolicy:m,logicalId:d}}static AutoScaling={smallWebServer:(e,n,r,i,a)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:i,targetGroupArns:a,healthCheckType:a?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,n,r,i,a)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:i,targetGroupArns:a,healthCheckType:a?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,n,r,i,a)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:i,targetGroupArns:a,healthCheckType:a?"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,a=b.createFargateService(i);if(n.length>0){if(!a.executionRole.Properties.Policies)a.executionRole.Properties.Policies=[];if(a.executionRole.Properties.Policies.push(b.Secrets.createAccessPolicy(n)),r.length>0)a.executionRole.Properties.Policies.push(b.Secrets.createKmsPolicy(r))}return a}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:a,keyName:s,instanceType:c="t3.micro",imageId:u=sl(c),mountEfs:d,databaseTools:m=!1}=e,p=e.allowedCidrs??(s?["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((N)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:N,Description:`SSH access from ${N}`})),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`),E={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${g}-profile`,Roles:[P.Ref(h)]}},w=`#!/bin/bash
302
302
  dnf install -y amazon-efs-utils nfs-utils jq wget htop
303
- `;if(m)E+=`
303
+ `;if(m)w+=`
304
304
  # Database clients: psql, mysql (MariaDB), redis-cli
305
305
  dnf install -y postgresql16 mariadb105 redis6
306
- `;if(d){let N=d.mountPath||"/mnt/efs";E+=`
306
+ `;if(d){let N=d.mountPath||"/mnt/efs";w+=`
307
307
  # Mount EFS
308
308
  mkdir -p ${N}
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}:/ ${N} efs _netdev,tls,nofail 0 0" >> /etc/fstab
314
- `}let v=o(g),I={Type:"AWS::EC2::Instance",DependsOn:[C],Properties:{ImageId:u,InstanceType:c,SubnetId:a,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(s)I.Properties.KeyName=s;let D={[y]:f,[h]:S,[C]:P,[v]:I};return{instance:I,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:a,throughput:s,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")&&a)m.Iops=a;if(d==="gp3"&&s)m.Throughput=s;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:a}=e,s={SpotInstanceType:r,InstanceInterruptionBehavior:i};if(n)s.MaxPrice=n;if(a)s.BlockDurationMinutes=a;return{SpotOptions:s}},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:a="capacity-optimized",spotMaxPrice:s}=e,c={OnDemandBaseCapacity:r,OnDemandPercentageAboveBaseCapacity:i,SpotAllocationStrategy:a};if(s)c.SpotMaxPrice=s;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:a=70,scaleDownThreshold:s=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:a,predefinedMetricType:d[u]||d.cpu,scaleInCooldown:c,scaleOutCooldown:c}]}},forEcs:(e)=>{let{min:n,max:r,cpuTarget:i=70,memoryTarget:a}=e,s=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:i}];if(a)s.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:a});return{minCapacity:n,maxCapacity:r,targetTrackingPolicies:s}},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:a=2,unhealthyThreshold:s=5,protocol:c="HTTP"}=e,u={HealthCheckIntervalSeconds:r,HealthCheckTimeoutSeconds:i,HealthyThresholdCount:a,UnhealthyThresholdCount:s};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:a="ELBSecurityPolicy-TLS13-1-2-2021-06"}=e;return{Port:i,Protocol:"HTTPS",Certificates:[{CertificateArn:n}],SslPolicy:a,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:a=256,environmentVariables:s,reservedConcurrency:c}=e,u={Handler:n,Runtime:r,Timeout:i,MemorySize:a};if(s)u.Environment={Variables:s};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:a="systemd",enableSsl:s=!0,sslEmail:c="admin@example.com",domain:u,appPort:d=3000,installDatabaseClients:m=!1,installRedis:p=!1,extraPackages:g=[]}=e,y=`#!/bin/bash
314
+ `}let v=o(g),I={Type:"AWS::EC2::Instance",DependsOn:[C],Properties:{ImageId:u,InstanceType:c,SubnetId:a,SecurityGroupIds:[P.Ref(y)],IamInstanceProfile:P.Ref(C),UserData:d?{"Fn::Base64":P.Sub(w,{FileSystemId:d.fileSystemId})}:P.Base64(w),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(s)I.Properties.KeyName=s;let D={[y]:f,[h]:S,[C]:E,[v]:I};return{instance:I,securityGroup:f,instanceProfile:E,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:a,throughput:s,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")&&a)m.Iops=a;if(d==="gp3"&&s)m.Throughput=s;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:a}=e,s={SpotInstanceType:r,InstanceInterruptionBehavior:i};if(n)s.MaxPrice=n;if(a)s.BlockDurationMinutes=a;return{SpotOptions:s}},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:a="capacity-optimized",spotMaxPrice:s}=e,c={OnDemandBaseCapacity:r,OnDemandPercentageAboveBaseCapacity:i,SpotAllocationStrategy:a};if(s)c.SpotMaxPrice=s;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:a=70,scaleDownThreshold:s=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:a,predefinedMetricType:d[u]||d.cpu,scaleInCooldown:c,scaleOutCooldown:c}]}},forEcs:(e)=>{let{min:n,max:r,cpuTarget:i=70,memoryTarget:a}=e,s=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:i}];if(a)s.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:a});return{minCapacity:n,maxCapacity:r,targetTrackingPolicies:s}},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:a=2,unhealthyThreshold:s=5,protocol:c="HTTP"}=e,u={HealthCheckIntervalSeconds:r,HealthCheckTimeoutSeconds:i,HealthyThresholdCount:a,UnhealthyThresholdCount:s};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:a="ELBSecurityPolicy-TLS13-1-2-2021-06"}=e;return{Port:i,Protocol:"HTTPS",Certificates:[{CertificateArn:n}],SslPolicy:a,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:a=256,environmentVariables:s,reservedConcurrency:c}=e,u={Handler:n,Runtime:r,Timeout:i,MemorySize:a};if(s)u.Environment={Variables:s};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:a="systemd",enableSsl:s=!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:a}=e,s=l({slug:n,environment:r,resourceType:"eip"}),c=o(s),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r},...i?[{Key:"Domain",Value:i}]:[]]}},d={[c]:u},m,p;if(a)p=o(`${s}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:R.GetAtt(c,"AllocationId"),InstanceId:R.Ref(a)}},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:a,instanceType:s="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 I=l({slug:n,environment:r,resourceType:"server-profile"}),D=o(I),N={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:I,Roles:[R.Ref(E)]}};f[D]=N;let M=l({slug:n,environment:r,resourceType:"server"}),F=o(M),O={Type:"AWS::EC2::Instance",DependsOn:[D],Properties:{ImageId:c,InstanceType:s,KeyName:u,SubnetId:a,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:M},{Key:"Environment",Value:r},...d?[{Key:"Domain",Value:d}]:[]]}};if(m)O.Properties.UserData=R.Base64(m);f[F]=O;let{eip:G,eipAssociation:U,eipLogicalId:ce,associationLogicalId:q,resources:J}=b.createElasticIp({slug:n,environment:r,domain:d,instanceLogicalId:F});return Object.assign(f,J),{instance:O,securityGroup:C,eip:G,eipAssociation:U,instanceRole:v,instanceProfile:N,resources:f,outputs:{instanceLogicalId:F,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
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:a}=e,s=l({slug:n,environment:r,resourceType:"eip"}),c=o(s),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r},...i?[{Key:"Domain",Value:i}]:[]]}},d={[c]:u},m,p;if(a)p=o(`${s}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:P.GetAtt(c,"AllocationId"),InstanceId:P.Ref(a)}},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:a,instanceType:s="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 E=l({slug:n,environment:r,resourceType:"server-role"}),w=o(E),v={Type:"AWS::IAM::Role",Properties:{RoleName:E,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[w]=v;let I=l({slug:n,environment:r,resourceType:"server-profile"}),D=o(I),N={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:I,Roles:[P.Ref(w)]}};f[D]=N;let M=l({slug:n,environment:r,resourceType:"server"}),F=o(M),O={Type:"AWS::EC2::Instance",DependsOn:[D],Properties:{ImageId:c,InstanceType:s,KeyName:u,SubnetId:a,SecurityGroupIds:[P.Ref(S)],IamInstanceProfile:P.Ref(D),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:g,VolumeType:y,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:r},...d?[{Key:"Domain",Value:d}]:[]]}};if(m)O.Properties.UserData=P.Base64(m);f[F]=O;let{eip:G,eipAssociation:U,eipLogicalId:ce,associationLogicalId:q,resources:J}=b.createElasticIp({slug:n,environment:r,domain:d,instanceLogicalId:F});return Object.assign(f,J),{instance:O,securityGroup:C,eip:G,eipAssociation:U,instanceRole:v,instanceProfile:N,resources:f,outputs:{instanceLogicalId:F,securityGroupLogicalId:S,eipLogicalId:ce,associationLogicalId:q,roleLogicalId:w,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 L{static createVpc(e){let{slug:n,environment:r,cidr:i="10.0.0.0/16",enableDnsHostnames:a=!0,enableDnsSupport:s=!0}=e,c=l({slug:n,environment:r,resourceType:"vpc"}),u=o(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:i,EnableDnsHostnames:a,EnableDnsSupport:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:n,environment:r,vpcId:i,type:a,cidr:s,availabilityZone:c,mapPublicIp:u=a==="public"}=e,d=l({slug:n,environment:r,resourceType:`subnet-${a}`}),m=o(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:i,CidrBlock:s,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:a}]}},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:a}=e,s=l({slug:r,environment:i,resourceType:"nat"}),c=o(s);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:R.GetAtt(n,"AllocationId"),SubnetId:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:c}}static createRouteTable(e,n,r,i){let a=l({slug:e,environment:n,resourceType:`rt-${i}`}),s=o(a);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:R.Ref(r),Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n},{Key:"Type",Value:i}]}},logicalId:s}}static createRoute(e,n,r){let i=o(`${e}-route-${r.type}`),a={Type:"AWS::EC2::Route",Properties:{RouteTableId:R.Ref(e),DestinationCidrBlock:n}};if(r.type==="igw")a.Properties.GatewayId=R.Ref(r.logicalId);else if(r.type==="nat")a.Properties.NatGatewayId=R.Ref(r.logicalId);else if(r.type==="instance")a.Properties.InstanceId=R.Ref(r.logicalId);return{route:a,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:a,trafficType:s="ALL",logGroupName:c}=e,u=l({slug:n,environment:r,resourceType:"flowlog"}),d=o(u);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:a,ResourceIds:[i],TrafficType:s,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,a]=e.split("/"),s=Number.parseInt(a,10),c=Math.ceil(Math.log2(n*r)),u=s+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:a="10.0.0.0/16",zones:s=3,enableNatGateway:c=!1,singleNatGateway:u=!1,enableFlowLogs:d=!1}=e,m={},p=[],g=[],y=[],{vpc:f,logicalId:h}=L.createVpc({slug:n,environment:r,cidr:a});m[h]=f;let{internetGateway:S,logicalId:C}=L.createInternetGateway(n,r);m[C]=S;let{attachment:P,logicalId:E}=L.attachInternetGateway(h,C);m[E]=P;let{routeTable:v,logicalId:I}=L.createRouteTable(n,r,h,"public");m[I]=v;let{route:D,logicalId:N}=L.createRoute(I,"0.0.0.0/0",{type:"igw",logicalId:C});D.DependsOn=E,m[N]=D;let M=L.calculateSubnetCidrs(a,s,2),F=L.getAvailabilityZones(i,s),O=[];for(let G=0;G<s;G++){let U=F[G],ce=M[G*2],q=M[G*2+1],{subnet:J,logicalId:K}=L.createSubnet({slug:n,environment:r,vpcId:R.Ref(h),type:"public",cidr:ce,availabilityZone:U});m[K]=J,p.push(K);let{association:Q,logicalId:ge}=L.associateSubnetWithRouteTable(K,I);m[ge]=Q;let{subnet:Te,logicalId:te}=L.createSubnet({slug:n,environment:r,vpcId:R.Ref(h),type:"private",cidr:q,availabilityZone:U});if(m[te]=Te,g.push(te),c&&(!u||G===0)){let{eip:Z,logicalId:re}=L.createEip(`${n}-${U}`,r);m[re]=Z;let{natGateway:fe,logicalId:ae}=L.createNatGateway({slug:`${n}-${U}`,environment:r,subnetId:R.Ref(K)},re);fe.DependsOn=E,m[ae]=fe,y.push(ae);let{routeTable:ue,logicalId:Ee}=L.createRouteTable(`${n}-${U}`,r,h,"private");m[Ee]=ue,O.push(Ee);let{route:Le,logicalId:x}=L.createRoute(Ee,"0.0.0.0/0",{type:"nat",logicalId:ae});m[x]=Le;let{association:_,logicalId:V}=L.associateSubnetWithRouteTable(te,Ee);m[V]=_}else if(c&&u&&G>0){let{association:Z,logicalId:re}=L.associateSubnetWithRouteTable(te,O[0]);m[re]=Z}else{let{routeTable:Z,logicalId:re}=L.createRouteTable(`${n}-${U}-isolated`,r,h,"private");m[re]=Z;let{association:fe,logicalId:ae}=L.associateSubnetWithRouteTable(te,re);m[ae]=fe}}if(d){let{flowLog:G,logicalId:U}=L.enableFlowLogs({slug:n,environment:r,resourceId:R.Ref(h),resourceType:"VPC"});m[U]=G}return{resources:m,outputs:{vpcId:h,publicSubnetIds:p,privateSubnetIds:g,natGatewayIds:y.length>0?y:void 0}}}static NatGatewayCostWarning=`
580
+ `,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class L{static createVpc(e){let{slug:n,environment:r,cidr:i="10.0.0.0/16",enableDnsHostnames:a=!0,enableDnsSupport:s=!0}=e,c=l({slug:n,environment:r,resourceType:"vpc"}),u=o(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:i,EnableDnsHostnames:a,EnableDnsSupport:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:n,environment:r,vpcId:i,type:a,cidr:s,availabilityZone:c,mapPublicIp:u=a==="public"}=e,d=l({slug:n,environment:r,resourceType:`subnet-${a}`}),m=o(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:i,CidrBlock:s,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:a}]}},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:P.Ref(e),InternetGatewayId:P.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:a}=e,s=l({slug:r,environment:i,resourceType:"nat"}),c=o(s);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:P.GetAtt(n,"AllocationId"),SubnetId:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:c}}static createRouteTable(e,n,r,i){let a=l({slug:e,environment:n,resourceType:`rt-${i}`}),s=o(a);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:P.Ref(r),Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n},{Key:"Type",Value:i}]}},logicalId:s}}static createRoute(e,n,r){let i=o(`${e}-route-${r.type}`),a={Type:"AWS::EC2::Route",Properties:{RouteTableId:P.Ref(e),DestinationCidrBlock:n}};if(r.type==="igw")a.Properties.GatewayId=P.Ref(r.logicalId);else if(r.type==="nat")a.Properties.NatGatewayId=P.Ref(r.logicalId);else if(r.type==="instance")a.Properties.InstanceId=P.Ref(r.logicalId);return{route:a,logicalId:i}}static associateSubnetWithRouteTable(e,n){let r=o(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:P.Ref(e),RouteTableId:P.Ref(n)}},logicalId:r}}static enableFlowLogs(e){let{slug:n,environment:r,resourceId:i,resourceType:a,trafficType:s="ALL",logGroupName:c}=e,u=l({slug:n,environment:r,resourceType:"flowlog"}),d=o(u);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:a,ResourceIds:[i],TrafficType:s,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,a]=e.split("/"),s=Number.parseInt(a,10),c=Math.ceil(Math.log2(n*r)),u=s+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,E=[C>>>24&255,C>>>16&255,C>>>8&255,C&255].join(".");h.push(`${E}/${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:a="10.0.0.0/16",zones:s=3,enableNatGateway:c=!1,singleNatGateway:u=!1,enableFlowLogs:d=!1}=e,m={},p=[],g=[],y=[],{vpc:f,logicalId:h}=L.createVpc({slug:n,environment:r,cidr:a});m[h]=f;let{internetGateway:S,logicalId:C}=L.createInternetGateway(n,r);m[C]=S;let{attachment:E,logicalId:w}=L.attachInternetGateway(h,C);m[w]=E;let{routeTable:v,logicalId:I}=L.createRouteTable(n,r,h,"public");m[I]=v;let{route:D,logicalId:N}=L.createRoute(I,"0.0.0.0/0",{type:"igw",logicalId:C});D.DependsOn=w,m[N]=D;let M=L.calculateSubnetCidrs(a,s,2),F=L.getAvailabilityZones(i,s),O=[];for(let G=0;G<s;G++){let U=F[G],ce=M[G*2],q=M[G*2+1],{subnet:J,logicalId:K}=L.createSubnet({slug:n,environment:r,vpcId:P.Ref(h),type:"public",cidr:ce,availabilityZone:U});m[K]=J,p.push(K);let{association:Q,logicalId:ge}=L.associateSubnetWithRouteTable(K,I);m[ge]=Q;let{subnet:Te,logicalId:te}=L.createSubnet({slug:n,environment:r,vpcId:P.Ref(h),type:"private",cidr:q,availabilityZone:U});if(m[te]=Te,g.push(te),c&&(!u||G===0)){let{eip:Z,logicalId:re}=L.createEip(`${n}-${U}`,r);m[re]=Z;let{natGateway:fe,logicalId:ae}=L.createNatGateway({slug:`${n}-${U}`,environment:r,subnetId:P.Ref(K)},re);fe.DependsOn=w,m[ae]=fe,y.push(ae);let{routeTable:ue,logicalId:Ee}=L.createRouteTable(`${n}-${U}`,r,h,"private");m[Ee]=ue,O.push(Ee);let{route:Le,logicalId:x}=L.createRoute(Ee,"0.0.0.0/0",{type:"nat",logicalId:ae});m[x]=Le;let{association:_,logicalId:V}=L.associateSubnetWithRouteTable(te,Ee);m[V]=_}else if(c&&u&&G>0){let{association:Z,logicalId:re}=L.associateSubnetWithRouteTable(te,O[0]);m[re]=Z}else{let{routeTable:Z,logicalId:re}=L.createRouteTable(`${n}-${U}-isolated`,r,h,"private");m[re]=Z;let{association:fe,logicalId:ae}=L.associateSubnetWithRouteTable(te,re);m[ae]=fe}}if(d){let{flowLog:G,logicalId:U}=L.enableFlowLogs({slug:n,environment:r,resourceId:P.Ref(h),resourceType:"VPC"});m[U]=G}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 ot{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:a,performanceMode:s="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:n,environment:r,resourceType:"efs"}),p=o(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:i,PerformanceMode:s,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(a)g.Properties.KmsKeyId=a;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,n){let{slug:r,environment:i,subnetId:a,securityGroups:s,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${a}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:a,SecurityGroups:s}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:a="/",uid:s="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${a.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:R.Ref(e),PosixUser:{Uid:s,Gid:c},RootDirectory:{Path:a,CreationInfo:{OwnerUid:s,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${a}`},{Key:"Environment",Value:i}]}},logicalId:m}}static setLifecyclePolicy(e,n){let{transitionToIA:r,transitionToPrimary:i=!1}=n;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let a=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:a})}if(i)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,n){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=n,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:a=[],sourceCidrBlocks:s=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of s)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:g,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${n} ${r}`,VpcId:i,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,n){let{slug:r,environment:i,subnetIds:a,securityGroupId:s}=n,c=[],u=[];for(let d=0;d<a.length;d++){let m=a[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:m,SecurityGroups:[s]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:a,sourceSecurityGroupIds:s=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=ot.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)ot.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=ot.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s});g[S]=h;let{mountTargets:C,logicalIds:P}=ot.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:a,securityGroupId:R.Ref(S)});for(let E=0;E<C.length;E++)g[P[E]]=C[E];return{resources:g,outputs:{fileSystemId:f,securityGroupId:S,mountTargetIds:P}}}}class k{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:a=!0,dkimKeyLength:s="RSA_2048_BIT"}=e,c=l({slug:r,environment:i,resourceType:"ses-identity"}),u=o(`${c}-${n.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(a)d.Properties.DkimSigningAttributes={NextSigningKeyLength:s};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let a=0;a<n.length;a++){let s=n[a],c=o(`dkim-${e.replace(/\./g,"")}-${a+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${s}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${s}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:a=!0,sendingEnabled:s=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=i||l({slug:n,environment:r,resourceType:"ses-config"}),m=o(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:a},SendingOptions:{SendingEnabled:s},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,a=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),s=o(a);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:a}},logicalId:s}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:a,recipients:s,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=n,y=l({slug:r,environment:i,resourceType:"ses-rule"}),f=o(y),h=[];if(m)h.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)h.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)h.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:a,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:s,Actions:h.length>0?h:void 0}}},logicalId:f}}static createMxRecord(e,n,r){let i=o(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:i}}static createVerificationRecord(e,n,r){let i=o(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${n}"`]}},logicalId:i}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,n,r){let{includeDomains:i=[],softFail:a=!1}=r||{},s=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=a?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:s}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:a,percentage:s=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${s}`;if(a)m+=`; sp=${a}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:n,environment:r,domain:i,s3BucketName:a,s3KeyPrefix:s="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=k.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=k.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:a,prefix:s},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:C}=k.createMxRecord(i,u,c);return p[C]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:C}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:a,region:s,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=k.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=k.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=k.createSpfRecord(i,a);m[S]=h;let{record:C,logicalId:P}=k.createDmarcRecord(i,a,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[P]=C,c&&u){let E=k.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:s,hostedZoneId:a});Object.assign(m,E.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:f}}}static InboundSmtpEndpoints={"us-east-1":"inbound-smtp.us-east-1.amazonaws.com","us-west-2":"inbound-smtp.us-west-2.amazonaws.com","eu-west-1":"inbound-smtp.eu-west-1.amazonaws.com"};static supportsInboundEmail(e){return e in k.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:a}=e,s=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(s),u=o(`${s}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(a)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:a});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${s}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[R.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:a,configurationSetName:s,timeout:c=30,memorySize:u=256}=e,d=l({slug:n,environment:r,resourceType:"outbound-email"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:a,CONFIGURATION_SET:s||""}},Code:{ZipFile:k.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:a,organizedPrefix:s="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"inbound-email"}),m=o(d),p=o(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:a,ORGANIZED_PREFIX:s}},Code:{ZipFile:k.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:R.Ref("AWS::AccountId")}};return{function:g,permission:y,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:a,convertedPrefix:s="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"email-conversion"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:a,CONVERTED_PREFIX:s}},Code:{ZipFile:k.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:n,prefix:r="inbound/",suffix:i,events:a}=e,s=a??["s3:ObjectCreated:*"],c={};if(r||i){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(i)c.S3Key.Rules.push({Name:"suffix",Value:i})}return{notificationConfiguration:{LambdaConfigurations:[{Event:s[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:a}=e,s=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(s);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:a}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:a,s3BucketArn:s,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=k.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:s,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=k.createOutboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),domain:i,configurationSetName:c});m[S]=h;let C={roleLogicalId:y,outboundLambdaLogicalId:S};if(u){let{function:P,permission:E,logicalId:v,permissionLogicalId:I}=k.createInboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:a});m[v]=P,m[I]=E;let{permission:D,logicalId:N}=k.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:v,s3BucketArn:s});m[N]=D,C.inboundLambdaLogicalId=v}if(d){let{function:P,logicalId:E}=k.createEmailConversionLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:a});m[E]=P,C.conversionLambdaLogicalId=E}return{resources:m,outputs:C}}static LambdaCode={outboundEmail:`
588
+ `}class ot{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:a,performanceMode:s="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:n,environment:r,resourceType:"efs"}),p=o(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:i,PerformanceMode:s,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(a)g.Properties.KmsKeyId=a;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,n){let{slug:r,environment:i,subnetId:a,securityGroups:s,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${a}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:a,SecurityGroups:s}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:a="/",uid:s="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${a.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:P.Ref(e),PosixUser:{Uid:s,Gid:c},RootDirectory:{Path:a,CreationInfo:{OwnerUid:s,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${a}`},{Key:"Environment",Value:i}]}},logicalId:m}}static setLifecyclePolicy(e,n){let{transitionToIA:r,transitionToPrimary:i=!1}=n;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let a=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:a})}if(i)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,n){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=n,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:a=[],sourceCidrBlocks:s=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of s)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:g,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${n} ${r}`,VpcId:i,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,n){let{slug:r,environment:i,subnetIds:a,securityGroupId:s}=n,c=[],u=[];for(let d=0;d<a.length;d++){let m=a[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:m,SecurityGroups:[s]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:a,sourceSecurityGroupIds:s=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=ot.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)ot.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=ot.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s});g[S]=h;let{mountTargets:C,logicalIds:E}=ot.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:a,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 k{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:a=!0,dkimKeyLength:s="RSA_2048_BIT"}=e,c=l({slug:r,environment:i,resourceType:"ses-identity"}),u=o(`${c}-${n.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(a)d.Properties.DkimSigningAttributes={NextSigningKeyLength:s};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let a=0;a<n.length;a++){let s=n[a],c=o(`dkim-${e.replace(/\./g,"")}-${a+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${s}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${s}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:a=!0,sendingEnabled:s=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=i||l({slug:n,environment:r,resourceType:"ses-config"}),m=o(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:a},SendingOptions:{SendingEnabled:s},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,a=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),s=o(a);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:a}},logicalId:s}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:a,recipients:s,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=n,y=l({slug:r,environment:i,resourceType:"ses-rule"}),f=o(y),h=[];if(m)h.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)h.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)h.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:a,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:s,Actions:h.length>0?h:void 0}}},logicalId:f}}static createMxRecord(e,n,r){let i=o(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:i}}static createVerificationRecord(e,n,r){let i=o(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${n}"`]}},logicalId:i}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,n,r){let{includeDomains:i=[],softFail:a=!1}=r||{},s=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=a?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:s}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:a,percentage:s=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${s}`;if(a)m+=`; sp=${a}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:n,environment:r,domain:i,s3BucketName:a,s3KeyPrefix:s="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=k.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=k.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:a,prefix:s},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:C}=k.createMxRecord(i,u,c);return p[C]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:C}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:a,region:s,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=k.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=k.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=k.createSpfRecord(i,a);m[S]=h;let{record:C,logicalId:E}=k.createDmarcRecord(i,a,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[E]=C,c&&u){let w=k.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:s,hostedZoneId:a});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 k.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:a}=e,s=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(s),u=o(`${s}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(a)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:a});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${s}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[P.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:a,configurationSetName:s,timeout:c=30,memorySize:u=256}=e,d=l({slug:n,environment:r,resourceType:"outbound-email"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:a,CONFIGURATION_SET:s||""}},Code:{ZipFile:k.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:a,organizedPrefix:s="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"inbound-email"}),m=o(d),p=o(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:a,ORGANIZED_PREFIX:s}},Code:{ZipFile:k.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName: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:a,convertedPrefix:s="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"email-conversion"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:a,CONVERTED_PREFIX:s}},Code:{ZipFile:k.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:n,prefix:r="inbound/",suffix:i,events:a}=e,s=a??["s3:ObjectCreated:*"],c={};if(r||i){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(i)c.S3Key.Rules.push({Name:"suffix",Value:i})}return{notificationConfiguration:{LambdaConfigurations:[{Event:s[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:a}=e,s=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(s);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:P.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:a}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:a,s3BucketArn:s,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=k.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:s,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=k.createOutboundEmailLambda({slug:n,environment:r,roleArn: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}=k.createInboundEmailLambda({slug:n,environment:r,roleArn:P.GetAtt(y,"Arn"),s3BucketName:a});m[v]=E,m[I]=w;let{permission:D,logicalId:N}=k.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:v,s3BucketArn:s});m[N]=D,C.inboundLambdaLogicalId=v}if(d){let{function:E,logicalId:w}=k.createEmailConversionLambda({slug:n,environment:r,roleArn:P.GetAtt(y,"Arn"),s3BucketName:a});m[w]=E,C.conversionLambdaLogicalId=w}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 Rt{static LambdaCode={incomingCall:yt,voicemail:ln,missedCall:cn};static createConnectInstance(e){let{slug:n,environment:r,instanceAlias:i,inboundCallsEnabled:a=!0,outboundCallsEnabled:s=!0}=e;return{[`${n}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:i,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:a,OutboundCalls:s,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:Rt.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:Rt.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:Rt.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,Rt.createPhoneLambdaRole({slug:e.slug})),Object.assign(n,Rt.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"]},a={Ref:`${e.slug}PhoneNotificationTopic`},s={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(n,Rt.createIncomingCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:a,callLogTable:s,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(n,Rt.createVoicemailLambda({slug:e.slug,roleArn:i,voicemailBucket:c,notificationTopicArn:a,callLogTable:s,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(n,Rt.createMissedCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:a,callLogTable:s,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:a=0,visibilityTimeout:s=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:a,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:s,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:a=3}=n,s=l({slug:r,environment:i,resourceType:"dlq"}),c=o(s),u={Type:"AWS::SQS::Queue",Properties:{QueueName:s,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:R.GetAtt(c,"Arn"),maxReceiveCount:a}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,n){let{slug:r,environment:i,name:a,description:s,enabled:c=!0}=n,u=a||l({slug:r,environment:i,resourceType:"schedule"}),d=o(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:s,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,n,r){let{slug:i,environment:a,name:s,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:y=!1,taskCount:f=1,containerOverrides:h}=r,S=s||l({slug:i,environment:a,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:a,description:s,enabled:c=!0,functionArn:u,input:d}=n,m=a||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:s||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,n){let{slug:r,environment:i,name:a,description:s,enabled:c=!0,queueArn:u,messageGroupId:d}=n,m=a||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:s||`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 a={"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(a[n])return a[n];let s=n.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(s){let m=parseInt(s[1],10),p=s[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:a="exponential",backoffDelay:s=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:n,handler:r,retries:i,backoff:a,backoffDelay:s,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,n)=>{let{backoff:r,backoffDelay:i,maxDelay:a,jitter:s}=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,a||Number.MAX_SAFE_INTEGER),s){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:a={}}=e,s=[{name:"JOB_CLASS",value:r}];if(i)s.push({name:"JOB_DATA",value:JSON.stringify(i)});for(let[c,u]of Object.entries(a))s.push({name:c,value:u});return{name:n,command:["bun","run","app/Jobs/runner.ts"],environment:s}}static createScheduledJob(e){let{slug:n,environment:r,schedule:i,jobClass:a,jobData:s,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,y=ye.rateStringToExpression(i),f=ye.createJobContainerOverride({containerName:g,jobClass:a,jobData:s});return ye.scheduleEcsTask(y,p,{slug:n,environment:r,name:`${n}-${a.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${a}`,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 Gt{static async discoverJobs(e){let{projectRoot:n,jobsPath:r="app/Jobs"}=e,i=`${n}/${r}`,a=[];try{let s=await import("node:fs"),c=await import("node:path");if(!s.existsSync(i))return[];let u=s.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=s.readFileSync(m,"utf-8"),y=Gt.parseJobMetadata(g,p,m);if(y)a.push(y)}}catch{return[]}return a}static parseJobMetadata(e,n,r){let i=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),a=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),s=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:a?.[1]!=="false",retries:s?parseInt(s[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}`,a=[];try{let s=await import("node:fs"),c=await import("node:path");if(!s.existsSync(i))return[];let u=s.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=s.readFileSync(m,"utf-8"),y=Gt.parseActionMetadata(g,p,m);if(y)a.push(y)}}catch{return[]}return a}static parseActionMetadata(e,n,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let a=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:n,path:r,handler:`${n}.handle`,description:a?.[1]}}static generateScheduledJobResources(e){let{slug:n,environment:r,jobs:i,taskDefinitionArn:a,clusterArn:s,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:a,clusterArn:s,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 Rt{static LambdaCode={incomingCall:yt,voicemail:ln,missedCall:cn};static createConnectInstance(e){let{slug:n,environment:r,instanceAlias:i,inboundCallsEnabled:a=!0,outboundCallsEnabled:s=!0}=e;return{[`${n}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:i,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:a,OutboundCalls:s,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:Rt.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:Rt.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:Rt.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,Rt.createPhoneLambdaRole({slug:e.slug})),Object.assign(n,Rt.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"]},a={Ref:`${e.slug}PhoneNotificationTopic`},s={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(n,Rt.createIncomingCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:a,callLogTable:s,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(n,Rt.createVoicemailLambda({slug:e.slug,roleArn:i,voicemailBucket:c,notificationTopicArn:a,callLogTable:s,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(n,Rt.createMissedCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:a,callLogTable:s,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:a=0,visibilityTimeout:s=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:a,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:s,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:a=3}=n,s=l({slug:r,environment:i,resourceType:"dlq"}),c=o(s),u={Type:"AWS::SQS::Queue",Properties:{QueueName:s,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:P.GetAtt(c,"Arn"),maxReceiveCount:a}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,n){let{slug:r,environment:i,name:a,description:s,enabled:c=!0}=n,u=a||l({slug:r,environment:i,resourceType:"schedule"}),d=o(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:s,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,n,r){let{slug:i,environment:a,name:s,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:y=!1,taskCount:f=1,containerOverrides:h}=r,S=s||l({slug:i,environment:a,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:a,description:s,enabled:c=!0,functionArn:u,input:d}=n,m=a||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:s||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,n){let{slug:r,environment:i,name:a,description:s,enabled:c=!0,queueArn:u,messageGroupId:d}=n,m=a||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:s||`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 a={"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(a[n])return a[n];let s=n.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(s){let m=parseInt(s[1],10),p=s[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:a="exponential",backoffDelay:s=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:n,handler:r,retries:i,backoff:a,backoffDelay:s,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,n)=>{let{backoff:r,backoffDelay:i,maxDelay:a,jitter:s}=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,a||Number.MAX_SAFE_INTEGER),s){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:a={}}=e,s=[{name:"JOB_CLASS",value:r}];if(i)s.push({name:"JOB_DATA",value:JSON.stringify(i)});for(let[c,u]of Object.entries(a))s.push({name:c,value:u});return{name:n,command:["bun","run","app/Jobs/runner.ts"],environment:s}}static createScheduledJob(e){let{slug:n,environment:r,schedule:i,jobClass:a,jobData:s,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,y=ye.rateStringToExpression(i),f=ye.createJobContainerOverride({containerName:g,jobClass:a,jobData:s});return ye.scheduleEcsTask(y,p,{slug:n,environment:r,name:`${n}-${a.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${a}`,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 Gt{static async discoverJobs(e){let{projectRoot:n,jobsPath:r="app/Jobs"}=e,i=`${n}/${r}`,a=[];try{let s=await import("node:fs"),c=await import("node:path");if(!s.existsSync(i))return[];let u=s.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=s.readFileSync(m,"utf-8"),y=Gt.parseJobMetadata(g,p,m);if(y)a.push(y)}}catch{return[]}return a}static parseJobMetadata(e,n,r){let i=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),a=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),s=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:a?.[1]!=="false",retries:s?parseInt(s[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}`,a=[];try{let s=await import("node:fs"),c=await import("node:path");if(!s.existsSync(i))return[];let u=s.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=s.readFileSync(m,"utf-8"),y=Gt.parseActionMetadata(g,p,m);if(y)a.push(y)}}catch{return[]}return a}static parseActionMetadata(e,n,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let a=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:n,path:r,handler:`${n}.handle`,description:a?.[1]}}static generateScheduledJobResources(e){let{slug:n,environment:r,jobs:i,taskDefinitionArn:a,clusterArn:s,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:a,clusterArn:s,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:dn,deliveryStatus:un};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let n={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)n.SenderId=e.senderId;if(e.shortCode)n.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:n}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-sms-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:e.pinpointAppId,MESSAGE_LOG_TABLE:e.messageLogTable||"",SMS_SENDER_ID:e.senderId||"",SMS_ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static createReceiveLambda(e){return{[`${e.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:e.optOutTable||"",MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createDeliveryStatusLambda(e){return{[`${e.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let n={},r={};Object.assign(n,Re.createPinpointApp({slug:e.slug})),Object.assign(n,Re.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(n,Re.createSmsLambdaRole({slug:e.slug})),Object.assign(n,Re.createMessageLogTable({slug:e.slug})),Object.assign(n,Re.createOptOutTable({slug:e.slug})),Object.assign(n,Re.createNotificationTopic({slug:e.slug}));let i={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},a={Ref:`${e.slug}PinpointApp`},s={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(n,Re.createSendLambda({slug:e.slug,roleArn:i,pinpointAppId:a,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Re.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:s,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Re.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:s,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:n,outputs:r}}}function ht(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function xr(e,n){let r=(e||n).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${n}`);return r}function kr(e){let n=e.storage;if(n?.type==="efs"){let i="fileSystemId"in n?n.fileSystemId:void 0;if(!i||typeof i==="string"&&!i.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:i,posixProfile:n.posixProfile}}let r=(n?.type==="s3"?n.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function Mr(e,n,r){let i=n.posixProfile??r;if(!i)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let a of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(a)||a<0||a>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${a}`);return{Uid:i.uid,Gid:i.gid,...i.secondaryGids?.length?{SecondaryGids:i.secondaryGids}:{}}}function Lr(e,n){return typeof e==="string"?`/${e}/${n}`:{"Fn::Sub":[`/\${FileSystemId}/${n}`,{FileSystemId:e}]}}function Or(e){return typeof e==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",e)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:e}]}}class Qo{static create(e){let n=kr(e),r=n.type==="efs"?"EFS":"S3",i=e.endpointType??"PUBLIC";if(i==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let a=`${ht(e.slug)}${ht(e.environment)}Sftp`,s=`${a}Server`,c={},u;if(e.logging!==!1){let d=`${a}LoggingRole`;c[d]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[s]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:i,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...i==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=ht(d),g=xr(m.homeDirectory,d),y=`${a}${p}User`,f=m.roleArn;if(!f){let h=`${a}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Or(n.fileSystemId)}];else{let C=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:C,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${C}/${g}/*`}]}c[h]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"SftpHomeDirectory",PolicyDocument:{Version:"2012-10-17",Statement:S}}]}},f={"Fn::GetAtt":[h,"Arn"]}}c[y]={Type:"AWS::Transfer::User",DependsOn:[s],Properties:{ServerId:{Ref:s},UserName:d,Role:f,HomeDirectoryType:"PATH",HomeDirectory:n.type==="efs"?Lr(n.fileSystemId,g):`/${n.bucket}/${g}`,...n.type==="efs"?{PosixProfile:Mr(d,m,n.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:s,domain:r}}}class He{static createBedrockRole(e,n){let{slug:r,environment:i,name:a,models:s=["*"],allowStreaming:c=!0}=n,u=a||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=s.map((y)=>y==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${y}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:n,environment:r,name:i,models:a=["*"],allowInvoke:s=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(s)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=a.map((f)=>f==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${f}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return He.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return He.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return He.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let a=n.map((s)=>s==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${s}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:a}]}}),e}static Models={Claude3_5_Sonnet:"anthropic.claude-3-5-sonnet-20241022-v2:0",Claude3_5_Haiku:"anthropic.claude-3-5-haiku-20241022-v1:0",Claude3_Opus:"anthropic.claude-3-opus-20240229-v1:0",Claude3_Sonnet:"anthropic.claude-3-sonnet-20240229-v1:0",Claude3_Haiku:"anthropic.claude-3-haiku-20240307-v1:0",TitanTextG1Express:"amazon.titan-text-express-v1",TitanTextG1Lite:"amazon.titan-text-lite-v1",TitanEmbedG1Text:"amazon.titan-embed-text-v1",TitanImageG1:"amazon.titan-image-generator-v1",JurassicUltra:"ai21.j2-ultra-v1",JurassicMid:"ai21.j2-mid-v1",CommandText:"cohere.command-text-v14",CommandLight:"cohere.command-light-text-v14",EmbedEnglish:"cohere.embed-english-v3",EmbedMultilingual:"cohere.embed-multilingual-v3",Llama3_2_1B:"meta.llama3-2-1b-instruct-v1:0",Llama3_2_3B:"meta.llama3-2-3b-instruct-v1:0",Llama3_2_11B:"meta.llama3-2-11b-instruct-v1:0",Llama3_2_90B:"meta.llama3-2-90b-instruct-v1:0",Llama3_1_8B:"meta.llama3-1-8b-instruct-v1:0",Llama3_1_70B:"meta.llama3-1-70b-instruct-v1:0",Llama3_1_405B:"meta.llama3-1-405b-instruct-v1:0",Mistral7B:"mistral.mistral-7b-instruct-v0:2",Mixtral8x7B:"mistral.mixtral-8x7b-instruct-v0:1",MistralLarge:"mistral.mistral-large-2402-v1:0",StableDiffusionXL:"stability.stable-diffusion-xl-v1"};static ModelGroups={AllClaude:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","anthropic.claude-3-opus-20240229-v1:0","anthropic.claude-3-sonnet-20240229-v1:0","anthropic.claude-3-haiku-20240307-v1:0"],AllTitan:["amazon.titan-text-express-v1","amazon.titan-text-lite-v1","amazon.titan-embed-text-v1","amazon.titan-image-generator-v1"],AllLlama:["meta.llama3-2-1b-instruct-v1:0","meta.llama3-2-3b-instruct-v1:0","meta.llama3-2-11b-instruct-v1:0","meta.llama3-2-90b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-405b-instruct-v1:0"],TextModels:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","amazon.titan-text-express-v1","meta.llama3-2-11b-instruct-v1:0","mistral.mistral-7b-instruct-v0:2"],EmbeddingModels:["amazon.titan-embed-text-v1","cohere.embed-english-v3","cohere.embed-multilingual-v3"],ImageModels:["amazon.titan-image-generator-v1","stability.stable-diffusion-xl-v1"]}}class Wt{static createPostgres(e){return Wt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Wt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:a,instanceClass:s="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:y,encrypted:f=!0,kmsKeyId:h,multiAz:S=!1,backupRetentionDays:C=7,publiclyAccessible:P=!1,enableCloudwatchLogs:E=!0,deletionProtection:v=!0}=r,I=l({slug:i,environment:a,resourceType:`${e}-db`}),D=o(I),N,M;if(g&&g.length>0){let O=l({slug:i,environment:a,resourceType:"db-subnet-group"});M=o(O),N={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${I}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:a}]}}}let F={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:I,DBInstanceClass:s,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:C,PubliclyAccessible:P,DeletionProtection:v,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:a}]}};if(p)F.Properties.DBName=p;if(h)F.Properties.KmsKeyId=h;if(M)F.Properties.DBSubnetGroupName=R.Ref(M);if(y&&y.length>0)F.Properties.VPCSecurityGroups=y;if(E)F.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:F,subnetGroup:N,logicalId:D,subnetGroupId:M}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:a="db.t3.micro",securityGroupIds:s,publiclyAccessible:c=!1}=n,u=l({slug:r,environment:i,resourceType:"db-replica"}),d=o(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:a,SourceDBInstanceIdentifier:R.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(s&&s.length>0)m.Properties.VPCSecurityGroups=s;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:a,parameters:s={}}=r,c=l({slug:i,environment:a,resourceType:"db-params"}),u=o(c),d=e==="postgres"?`postgres${n.split(".")[0]}`:`mysql${n.split(".")[0]}.${n.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:a,sortKey:s,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:y,pointInTimeRecovery:f=!0,ttlAttribute:h}=e,S=i||l({slug:n,environment:r,resourceType:"table"}),C=o(S),P=[{AttributeName:a.name,AttributeType:a.type}];if(s)P.push({AttributeName:s.name,AttributeType:s.type});let E=[{AttributeName:a.name,KeyType:"HASH"}];if(s)E.push({AttributeName:s.name,KeyType:"RANGE"});let v={Type:"AWS::DynamoDB::Table",Properties:{TableName:S,BillingMode:c,AttributeDefinitions:P,KeySchema:E,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")v.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)v.Properties.StreamSpecification={StreamViewType:p};if(g)v.Properties.SSESpecification={SSEEnabled:!0,SSEType:y?"KMS":"AES256",KMSMasterKeyId:y};if(f)v.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)v.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:v,logicalId:C}}static addGlobalSecondaryIndex(e,n){let{indexName:r,partitionKey:i,sortKey:a,projectionType:s="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=n;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});if(a&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===a.name))e.Properties.AttributeDefinitions.push({AttributeName:a.name,AttributeType:a.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(a)m.push({AttributeName:a.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:s,NonKeyAttributes:s==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,n="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:n},e}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class Ui{static createRedis(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="7.1",port:s=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:y=1,replicasPerNodeGroup:f=1,atRestEncryption:h=!0,transitEncryption:S=!0,authToken:C,kmsKeyId:P,snapshotRetentionDays:E=7,snapshotWindow:v,maintenanceWindow:I}=e,D=l({slug:n,environment:r,resourceType:"redis"}),N=o(D),M,F;if(c&&c.length>0){let G=l({slug:n,environment:r,resourceType:"cache-subnet-group"});F=o(G),M={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:G,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:G},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:a,CacheNodeType:i,Port:s,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit:E,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:r}]}};if(g)O.Properties.NumNodeGroups=y,O.Properties.ReplicasPerNodeGroup=f;else O.Properties.NumCacheClusters=d;if(C)O.Properties.AuthToken=C;if(P)O.Properties.KmsKeyId=P;if(F)O.Properties.CacheSubnetGroupName=R.Ref(F);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(v)O.Properties.SnapshotWindow=v;if(I)O.Properties.PreferredMaintenanceWindow=I;return{replicationGroup:O,subnetGroup:M,logicalId:N,subnetGroupId:F}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="1.6.22",port:s=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,y=l({slug:n,environment:r,resourceType:"memcached"}),f=o(y),h,S;if(u&&u.length>0){let P=l({slug:n,environment:r,resourceType:"cache-subnet-group"});S=o(P),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:P,Description:`Subnet group for ${y}`,SubnetIds:u,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}}}let C={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:y,CacheNodeType:i,Engine:"memcached",EngineVersion:a,NumCacheNodes:c,Port:s,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(S)C.Properties.CacheSubnetGroupName=R.Ref(S);if(d&&d.length>0)C.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)C.Properties.PreferredAvailabilityZones=p;if(g)C.Properties.PreferredMaintenanceWindow=g;return{cluster:C,subnetGroup:h,logicalId:f,subnetGroupId:S}}static enableClusterMode(e,n=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=n,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,n){let{slug:r,environment:i,parameters:a={}}=n,s=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:a={}}=n,s=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Ie{static createUser(e){let{slug:n,environment:r,userName:i,groups:a,managedPolicyArns:s}=e,c=i||l({slug:n,environment:r,resourceType:"user"}),u=o(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(a&&a.length>0)d.Properties.Groups=a;if(s&&s.length>0)d.Properties.ManagedPolicyArns=s;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:a,awsPrincipal:s,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(a)m.Service=a;if(s)m.AWS=s;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:n,environment:r,groupName:i,managedPolicyArns:a}=e,s=i||l({slug:n,environment:r,resourceType:"group"}),c=o(s),u={Type:"AWS::IAM::Group",Properties:{GroupName:s}};if(a&&a.length>0)u.Properties.ManagedPolicyArns=a;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:a,statements:s}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=s.map((p)=>({Sid:p.sid,Effect:p.effect||"Allow",Action:p.actions,Resource:p.resources,Condition:p.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:a||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToUser(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToGroup(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static addInlinePolicyToRole(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static addInlinePolicyToUser(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static createAccessKey(e,n){let{slug:r,environment:i,status:a="Active"}=n,s=l({slug:r,environment:i,resourceType:"access-key"}),c=o(s);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:R.Ref(e),Status:a}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:a}=n,s=a||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(s);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:s,Roles:[R.Ref(e)]}},logicalId:c}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(e){let{slug:n,environment:r,permissions:i,createAccessKey:a=!0}=e,s={},c=[];if(i.s3Buckets&&i.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...i.s3Buckets,...i.s3Buckets.map((f)=>`${f}/*`)]});if(i.cloudFrontDistributions&&i.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:i.cloudFrontDistributions});if(i.ecrRepositories&&i.ecrRepositories.length>0)c.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:i.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(i.ecsServices&&i.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:i.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(i.cloudFormationStacks&&i.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:i.cloudFormationStacks});if(i.lambdaFunctions&&i.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:i.lambdaFunctions});if(i.secretsManagerSecrets&&i.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:i.secretsManagerSecrets});let{policy:u,logicalId:d}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${n} (${r})`,statements:c});s[d]=u;let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[R.Ref(d)]});s[p]=m;let g,y;if(a){let f=Ie.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,s[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:a,permissions:s,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${n} (${r})`,statements:s});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(a)y.StringEquals={"sts:ExternalId":a};let f={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:i.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(y).length>0?{Condition:y}:{}}]},ManagedPolicyArns:[R.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=f,{role:f,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:n,environment:r,permissions:i="readonly"}=e,a={},s=[],c=[];switch(i){case"readonly":c=[Ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":s=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Ie.ManagedPolicies.AdministratorAccess];break}let u,d;if(s.length>0){let f=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${n} (${r})`,statements:s});u=f.policy,d=f.logicalId,a[d]=u,c=[R.Ref(d)]}let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});a[p]=m;let{accessKey:g,logicalId:y}=Ie.createAccessKey(p,{slug:n,environment:r});return a[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((n)=>`${n}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class Yo{static createRestApi(e){let{slug:n,environment:r,name:i,description:a,endpointType:s="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=i||l({slug:n,environment:r,resourceType:"rest-api"}),m=o(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:a||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[s]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:n,environment:r,name:i,description:a,corsEnabled:s=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=i||l({slug:n,environment:r,resourceType:"http-api"}),y=o(g),f={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:a||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(s)f.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:f,logicalId:y}}static createWebSocketApi(e){let{slug:n,environment:r,name:i,description:a}=e,s=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(s);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:s,Description:a||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:s,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:a}=n,s=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(s);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:R.Ref(e),Description:a||`Deployment for ${s}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:a,stageName:s,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:a,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:s||a,RestApiId:R.Ref(e),DeploymentId:R.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:a}]}};if(u)f.Properties.CacheClusterSize=d;if(m)f.Properties.Variables=m;if(p)f.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:f,logicalId:y}}static createAuthorizer(e,n){let{slug:r,environment:i,name:a,type:s,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=a||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:s,RestApiId:R.Ref(e),AuthorizerResultTtlInSeconds:m}};if(s==="TOKEN"||s==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(s==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");y.Properties.ProviderARNs=d,y.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:y,logicalId:g}}static setCors(e,n={}){let{origins:r=["*"],methods:i=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:a=["*"],maxAge:s=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:a,MaxAge:s,AllowCredentials:c},e}static addThrottling(e,n=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:n,ThrottlingRateLimit:r}),e}static enableCaching(e,n="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=n,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),e}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class $e{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:a,encrypted:s=!1,kmsKeyId:c}=e,u=i||l({slug:n,environment:r,resourceType:"topic"}),d=o(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:a||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:a,endpoint:s,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=s.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${a}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:R.Ref(e),Protocol:a,Endpoint:s,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return $e.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return $e.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return $e.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return $e.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return $e.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:a,allowedServices:s,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(a)m.AWS=a;if(s)m.Service=s;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[R.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:R.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,n){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=n,e}static addInlineSubscription(e,n,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:n,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,n,r)=>({[e]:[{numeric:[">=",n,"<=",r]}]}),prefix:(e,n)=>({[e]:[{prefix:n}]}),and:(...e)=>Object.assign({},...e),exists:(e,n)=>({[e]:[{exists:n}]})};static UseCases={createAlertTopic:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class lu{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:a="STANDARD",definition:s,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=i||l({slug:n,environment:r,resourceType:"state-machine"}),p=o(m),g,y,f;if(c)f=c;else{let S=l({slug:n,environment:r,resourceType:"state-machine-role"});y=o(S),g={Type:"AWS::IAM::Role",Properties:{RoleName:S,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"states.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"],Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}},f=R.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:a,DefinitionString:JSON.stringify(s),RoleArn:f,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)h.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((S)=>({CloudWatchLogsLogGroup:{LogGroupArn:S}}))};if(d)h.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:h,logicalId:p,role:g,roleLogicalId:y}}static createLambdaTask(e,n){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:n?.parameters||{"Input.$":"$"}},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createDynamoDBTask(e,n,r,i){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[e],Parameters:{TableName:n,...r},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSNSPublishTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,n){return{Type:"Choice",Choices:e,Default:n}}static createParallelState(e,n){return{Type:"Parallel",Branches:e,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createMapState(e,n){return{Type:"Map",ItemsPath:n?.itemsPath||"$.items",Iterator:e,MaxConcurrency:n?.maxConcurrency,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,n){return{Type:"Fail",Error:e,Cause:n}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(e,n,r,i)=>({ErrorEquals:e,IntervalSeconds:n,MaxAttempts:r,BackoffRate:i})};static CatchPolicies={all:(e,n)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:n||"$.error"}),specific:(e,n,r)=>({ErrorEquals:e,Next:n,ResultPath:r||"$.error"})};static Patterns={sequential:(e,n,r)=>{let i={};return r.forEach((a,s)=>{let c=s===r.length-1;i[a.name]={...a.state,Next:c?void 0:r[s+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:i}},fanout:(e,n,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((i)=>i.definition),End:!0}}}),map:(e,n,r,i)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:i,End:!0}}}),withErrorHandling:(e,n,r,i)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:i,Success:{Type:"Succeed"}}})}}class Fi{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:a,namespace:s,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:y=!0,alarmActions:f,okActions:h,insufficientDataActions:S,dimensions:C,unit:P,datapointsToAlarm:E}=e,v=i||l({slug:n,environment:r,resourceType:"alarm"}),I=o(v),D={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:v,MetricName:a,Namespace:s,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:y}};if(f&&f.length>0)D.Properties.AlarmActions=f;if(h&&h.length>0)D.Properties.OKActions=h;if(S&&S.length>0)D.Properties.InsufficientDataActions=S;if(C)D.Properties.Dimensions=Object.entries(C).map(([N,M])=>({Name:N,Value:M}));if(P)D.Properties.Unit=P;if(E!==void 0)D.Properties.DatapointsToAlarm=E;return{alarm:D,logicalId:I}}static createCompositeAlarm(e){let{slug:n,environment:r,alarmName:i,alarmRule:a,actionsEnabled:s=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=i||l({slug:n,environment:r,resourceType:"composite-alarm"}),p=o(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:a,ActionsEnabled:s}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:n,environment:r,dashboardName:i,widgets:a}=e,s=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(s),u={widgets:a.map((m)=>({type:m.type,x:m.x,y:m.y,width:m.width,height:m.height,properties:m.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:s,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:a,kmsKeyId:s}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(a!==void 0)d.Properties.RetentionInDays=a;if(s)d.Properties.KmsKeyId=s;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:a}=n,s=a||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(s);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:R.Ref(e),LogStreamName:s}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:a,filterPattern:s,metricTransformations:c}=n,u=a||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:R.Ref(e),FilterPattern:s,MetricTransformations:c.map((p)=>({MetricName:p.metricName,MetricNamespace:p.metricNamespace,MetricValue:p.metricValue,DefaultValue:p.defaultValue,Unit:p.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:a?[a]:void 0}),highMemory:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:a?[a]:void 0}),highDisk:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:a?[a]:void 0}),lambdaErrors:(e,n,r,i=5,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:a?[a]:void 0}),lambdaThrottles:(e,n,r,i=10,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:a?[a]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:a?[a]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:a?[a]:void 0}),dynamoDBThrottles:(e,n,r,i=5,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:a?[a]:void 0}),rdsCpu:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:a?[a]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:a?[a]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:a?[a]:void 0}),albUnhealthyTargets:(e,n,r,i,a=1,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:a,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:s?[s]:void 0}),sesBounceRate:(e,n,r=5,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),sesComplaintRate:(e,n,r=0.1,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),smsDeliveryFailure:(e,n,r,i=10,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:a?[a]:void 0}),smsSpendLimit:(e,n,r=100,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),connectMissedCalls:(e,n,r,i=5,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:a?[a]:void 0})};static DashboardWidgets={metric:(e,n,r,i,a,s)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:a,title:s||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,a)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:a}}),log:(e,n,r,i,a,s)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${a.join("' | SOURCE '")}'
2274
+ `;class Re{static LambdaCode={send:ft,receive:dn,deliveryStatus:un};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let n={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)n.SenderId=e.senderId;if(e.shortCode)n.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:n}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-sms-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:e.pinpointAppId,MESSAGE_LOG_TABLE:e.messageLogTable||"",SMS_SENDER_ID:e.senderId||"",SMS_ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static createReceiveLambda(e){return{[`${e.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:e.optOutTable||"",MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createDeliveryStatusLambda(e){return{[`${e.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let n={},r={};Object.assign(n,Re.createPinpointApp({slug:e.slug})),Object.assign(n,Re.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(n,Re.createSmsLambdaRole({slug:e.slug})),Object.assign(n,Re.createMessageLogTable({slug:e.slug})),Object.assign(n,Re.createOptOutTable({slug:e.slug})),Object.assign(n,Re.createNotificationTopic({slug:e.slug}));let i={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},a={Ref:`${e.slug}PinpointApp`},s={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(n,Re.createSendLambda({slug:e.slug,roleArn:i,pinpointAppId:a,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Re.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:s,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Re.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:s,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:n,outputs:r}}}function ht(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function xr(e,n){let r=(e||n).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${n}`);return r}function kr(e){let n=e.storage;if(n?.type==="efs"){let i="fileSystemId"in n?n.fileSystemId:void 0;if(!i||typeof i==="string"&&!i.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:i,posixProfile:n.posixProfile}}let r=(n?.type==="s3"?n.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function Mr(e,n,r){let i=n.posixProfile??r;if(!i)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let a of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(a)||a<0||a>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${a}`);return{Uid:i.uid,Gid:i.gid,...i.secondaryGids?.length?{SecondaryGids:i.secondaryGids}:{}}}function Lr(e,n){return typeof e==="string"?`/${e}/${n}`:{"Fn::Sub":[`/\${FileSystemId}/${n}`,{FileSystemId:e}]}}function Or(e){return typeof e==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",e)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:e}]}}class Qo{static create(e){let n=kr(e),r=n.type==="efs"?"EFS":"S3",i=e.endpointType??"PUBLIC";if(i==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let a=`${ht(e.slug)}${ht(e.environment)}Sftp`,s=`${a}Server`,c={},u;if(e.logging!==!1){let d=`${a}LoggingRole`;c[d]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[s]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:i,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...i==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=ht(d),g=xr(m.homeDirectory,d),y=`${a}${p}User`,f=m.roleArn;if(!f){let h=`${a}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Or(n.fileSystemId)}];else{let C=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:C,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${C}/${g}/*`}]}c[h]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"SftpHomeDirectory",PolicyDocument:{Version:"2012-10-17",Statement:S}}]}},f={"Fn::GetAtt":[h,"Arn"]}}c[y]={Type:"AWS::Transfer::User",DependsOn:[s],Properties:{ServerId:{Ref:s},UserName:d,Role:f,HomeDirectoryType:"PATH",HomeDirectory:n.type==="efs"?Lr(n.fileSystemId,g):`/${n.bucket}/${g}`,...n.type==="efs"?{PosixProfile:Mr(d,m,n.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:s,domain:r}}}class He{static createBedrockRole(e,n){let{slug:r,environment:i,name:a,models:s=["*"],allowStreaming:c=!0}=n,u=a||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=s.map((y)=>y==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${y}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:n,environment:r,name:i,models:a=["*"],allowInvoke:s=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(s)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=a.map((f)=>f==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${f}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return He.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return He.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return He.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let a=n.map((s)=>s==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${s}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:a}]}}),e}static Models={Claude3_5_Sonnet:"anthropic.claude-3-5-sonnet-20241022-v2:0",Claude3_5_Haiku:"anthropic.claude-3-5-haiku-20241022-v1:0",Claude3_Opus:"anthropic.claude-3-opus-20240229-v1:0",Claude3_Sonnet:"anthropic.claude-3-sonnet-20240229-v1:0",Claude3_Haiku:"anthropic.claude-3-haiku-20240307-v1:0",TitanTextG1Express:"amazon.titan-text-express-v1",TitanTextG1Lite:"amazon.titan-text-lite-v1",TitanEmbedG1Text:"amazon.titan-embed-text-v1",TitanImageG1:"amazon.titan-image-generator-v1",JurassicUltra:"ai21.j2-ultra-v1",JurassicMid:"ai21.j2-mid-v1",CommandText:"cohere.command-text-v14",CommandLight:"cohere.command-light-text-v14",EmbedEnglish:"cohere.embed-english-v3",EmbedMultilingual:"cohere.embed-multilingual-v3",Llama3_2_1B:"meta.llama3-2-1b-instruct-v1:0",Llama3_2_3B:"meta.llama3-2-3b-instruct-v1:0",Llama3_2_11B:"meta.llama3-2-11b-instruct-v1:0",Llama3_2_90B:"meta.llama3-2-90b-instruct-v1:0",Llama3_1_8B:"meta.llama3-1-8b-instruct-v1:0",Llama3_1_70B:"meta.llama3-1-70b-instruct-v1:0",Llama3_1_405B:"meta.llama3-1-405b-instruct-v1:0",Mistral7B:"mistral.mistral-7b-instruct-v0:2",Mixtral8x7B:"mistral.mixtral-8x7b-instruct-v0:1",MistralLarge:"mistral.mistral-large-2402-v1:0",StableDiffusionXL:"stability.stable-diffusion-xl-v1"};static ModelGroups={AllClaude:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","anthropic.claude-3-opus-20240229-v1:0","anthropic.claude-3-sonnet-20240229-v1:0","anthropic.claude-3-haiku-20240307-v1:0"],AllTitan:["amazon.titan-text-express-v1","amazon.titan-text-lite-v1","amazon.titan-embed-text-v1","amazon.titan-image-generator-v1"],AllLlama:["meta.llama3-2-1b-instruct-v1:0","meta.llama3-2-3b-instruct-v1:0","meta.llama3-2-11b-instruct-v1:0","meta.llama3-2-90b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-405b-instruct-v1:0"],TextModels:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","amazon.titan-text-express-v1","meta.llama3-2-11b-instruct-v1:0","mistral.mistral-7b-instruct-v0:2"],EmbeddingModels:["amazon.titan-embed-text-v1","cohere.embed-english-v3","cohere.embed-multilingual-v3"],ImageModels:["amazon.titan-image-generator-v1","stability.stable-diffusion-xl-v1"]}}class Wt{static createPostgres(e){return Wt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Wt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:a,instanceClass:s="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:y,encrypted:f=!0,kmsKeyId:h,multiAz:S=!1,backupRetentionDays:C=7,publiclyAccessible:E=!1,enableCloudwatchLogs:w=!0,deletionProtection:v=!0}=r,I=l({slug:i,environment:a,resourceType:`${e}-db`}),D=o(I),N,M;if(g&&g.length>0){let O=l({slug:i,environment:a,resourceType:"db-subnet-group"});M=o(O),N={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${I}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:a}]}}}let F={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:I,DBInstanceClass:s,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:C,PubliclyAccessible:E,DeletionProtection:v,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:a}]}};if(p)F.Properties.DBName=p;if(h)F.Properties.KmsKeyId=h;if(M)F.Properties.DBSubnetGroupName=P.Ref(M);if(y&&y.length>0)F.Properties.VPCSecurityGroups=y;if(w)F.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:F,subnetGroup:N,logicalId:D,subnetGroupId:M}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:a="db.t3.micro",securityGroupIds:s,publiclyAccessible:c=!1}=n,u=l({slug:r,environment:i,resourceType:"db-replica"}),d=o(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:a,SourceDBInstanceIdentifier:P.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(s&&s.length>0)m.Properties.VPCSecurityGroups=s;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:a,parameters:s={}}=r,c=l({slug:i,environment:a,resourceType:"db-params"}),u=o(c),d=e==="postgres"?`postgres${n.split(".")[0]}`:`mysql${n.split(".")[0]}.${n.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:a,sortKey:s,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:y,pointInTimeRecovery:f=!0,ttlAttribute:h}=e,S=i||l({slug:n,environment:r,resourceType:"table"}),C=o(S),E=[{AttributeName:a.name,AttributeType:a.type}];if(s)E.push({AttributeName:s.name,AttributeType:s.type});let w=[{AttributeName:a.name,KeyType:"HASH"}];if(s)w.push({AttributeName:s.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:a,projectionType:s="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=n;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});if(a&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===a.name))e.Properties.AttributeDefinitions.push({AttributeName:a.name,AttributeType:a.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(a)m.push({AttributeName:a.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:s,NonKeyAttributes:s==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,n="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:n},e}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class Ui{static createRedis(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="7.1",port:s=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:y=1,replicasPerNodeGroup:f=1,atRestEncryption:h=!0,transitEncryption:S=!0,authToken:C,kmsKeyId:E,snapshotRetentionDays:w=7,snapshotWindow:v,maintenanceWindow:I}=e,D=l({slug:n,environment:r,resourceType:"redis"}),N=o(D),M,F;if(c&&c.length>0){let G=l({slug:n,environment:r,resourceType:"cache-subnet-group"});F=o(G),M={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:G,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:G},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:a,CacheNodeType:i,Port:s,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit: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(F)O.Properties.CacheSubnetGroupName=P.Ref(F);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(v)O.Properties.SnapshotWindow=v;if(I)O.Properties.PreferredMaintenanceWindow=I;return{replicationGroup:O,subnetGroup:M,logicalId:N,subnetGroupId:F}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="1.6.22",port:s=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,y=l({slug:n,environment:r,resourceType:"memcached"}),f=o(y),h,S;if(u&&u.length>0){let 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:a,NumCacheNodes:c,Port:s,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:a={}}=n,s=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:a={}}=n,s=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Ie{static createUser(e){let{slug:n,environment:r,userName:i,groups:a,managedPolicyArns:s}=e,c=i||l({slug:n,environment:r,resourceType:"user"}),u=o(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(a&&a.length>0)d.Properties.Groups=a;if(s&&s.length>0)d.Properties.ManagedPolicyArns=s;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:a,awsPrincipal:s,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(a)m.Service=a;if(s)m.AWS=s;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:n,environment:r,groupName:i,managedPolicyArns:a}=e,s=i||l({slug:n,environment:r,resourceType:"group"}),c=o(s),u={Type:"AWS::IAM::Group",Properties:{GroupName:s}};if(a&&a.length>0)u.Properties.ManagedPolicyArns=a;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:a,statements:s}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=s.map((p)=>({Sid:p.sid,Effect:p.effect||"Allow",Action:p.actions,Resource:p.resources,Condition:p.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:a||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToUser(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToGroup(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static addInlinePolicyToRole(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static addInlinePolicyToUser(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static createAccessKey(e,n){let{slug:r,environment:i,status:a="Active"}=n,s=l({slug:r,environment:i,resourceType:"access-key"}),c=o(s);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:P.Ref(e),Status:a}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:a}=n,s=a||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(s);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:s,Roles:[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:a=!0}=e,s={},c=[];if(i.s3Buckets&&i.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...i.s3Buckets,...i.s3Buckets.map((f)=>`${f}/*`)]});if(i.cloudFrontDistributions&&i.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:i.cloudFrontDistributions});if(i.ecrRepositories&&i.ecrRepositories.length>0)c.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:i.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(i.ecsServices&&i.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:i.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(i.cloudFormationStacks&&i.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:i.cloudFormationStacks});if(i.lambdaFunctions&&i.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:i.lambdaFunctions});if(i.secretsManagerSecrets&&i.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:i.secretsManagerSecrets});let{policy:u,logicalId:d}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${n} (${r})`,statements:c});s[d]=u;let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[P.Ref(d)]});s[p]=m;let g,y;if(a){let f=Ie.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,s[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:a,permissions:s,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${n} (${r})`,statements:s});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(a)y.StringEquals={"sts:ExternalId":a};let f={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:i.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(y).length>0?{Condition:y}:{}}]},ManagedPolicyArns:[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,a={},s=[],c=[];switch(i){case"readonly":c=[Ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":s=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Ie.ManagedPolicies.AdministratorAccess];break}let u,d;if(s.length>0){let f=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${n} (${r})`,statements:s});u=f.policy,d=f.logicalId,a[d]=u,c=[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});a[p]=m;let{accessKey:g,logicalId:y}=Ie.createAccessKey(p,{slug:n,environment:r});return a[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((n)=>`${n}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class Yo{static createRestApi(e){let{slug:n,environment:r,name:i,description:a,endpointType:s="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=i||l({slug:n,environment:r,resourceType:"rest-api"}),m=o(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:a||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[s]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:n,environment:r,name:i,description:a,corsEnabled:s=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=i||l({slug:n,environment:r,resourceType:"http-api"}),y=o(g),f={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:a||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(s)f.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:f,logicalId:y}}static createWebSocketApi(e){let{slug:n,environment:r,name:i,description:a}=e,s=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(s);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:s,Description:a||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:s,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:a}=n,s=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(s);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:P.Ref(e),Description:a||`Deployment for ${s}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:a,stageName:s,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:a,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:s||a,RestApiId:P.Ref(e),DeploymentId:P.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:a}]}};if(u)f.Properties.CacheClusterSize=d;if(m)f.Properties.Variables=m;if(p)f.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:f,logicalId:y}}static createAuthorizer(e,n){let{slug:r,environment:i,name:a,type:s,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=a||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:s,RestApiId:P.Ref(e),AuthorizerResultTtlInSeconds:m}};if(s==="TOKEN"||s==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(s==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");y.Properties.ProviderARNs=d,y.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:y,logicalId:g}}static setCors(e,n={}){let{origins:r=["*"],methods:i=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:a=["*"],maxAge:s=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:a,MaxAge:s,AllowCredentials:c},e}static addThrottling(e,n=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:n,ThrottlingRateLimit:r}),e}static enableCaching(e,n="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=n,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),e}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class $e{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:a,encrypted:s=!1,kmsKeyId:c}=e,u=i||l({slug:n,environment:r,resourceType:"topic"}),d=o(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:a||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:a,endpoint:s,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=s.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${a}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:P.Ref(e),Protocol:a,Endpoint:s,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return $e.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return $e.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return $e.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return $e.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return $e.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:a,allowedServices:s,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(a)m.AWS=a;if(s)m.Service=s;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[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 $e.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,n){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=n,e}static addInlineSubscription(e,n,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:n,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,n,r)=>({[e]:[{numeric:[">=",n,"<=",r]}]}),prefix:(e,n)=>({[e]:[{prefix:n}]}),and:(...e)=>Object.assign({},...e),exists:(e,n)=>({[e]:[{exists:n}]})};static UseCases={createAlertTopic:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class lu{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:a="STANDARD",definition:s,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=i||l({slug:n,environment:r,resourceType:"state-machine"}),p=o(m),g,y,f;if(c)f=c;else{let S=l({slug:n,environment:r,resourceType:"state-machine-role"});y=o(S),g={Type:"AWS::IAM::Role",Properties:{RoleName:S,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"states.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"],Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}},f=P.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:a,DefinitionString:JSON.stringify(s),RoleArn:f,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)h.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((S)=>({CloudWatchLogsLogGroup:{LogGroupArn:S}}))};if(d)h.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:h,logicalId:p,role:g,roleLogicalId:y}}static createLambdaTask(e,n){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:n?.parameters||{"Input.$":"$"}},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createDynamoDBTask(e,n,r,i){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[e],Parameters:{TableName:n,...r},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSNSPublishTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,n){return{Type:"Choice",Choices:e,Default:n}}static createParallelState(e,n){return{Type:"Parallel",Branches:e,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createMapState(e,n){return{Type:"Map",ItemsPath:n?.itemsPath||"$.items",Iterator:e,MaxConcurrency:n?.maxConcurrency,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,n){return{Type:"Fail",Error:e,Cause:n}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(e,n,r,i)=>({ErrorEquals:e,IntervalSeconds:n,MaxAttempts:r,BackoffRate:i})};static CatchPolicies={all:(e,n)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:n||"$.error"}),specific:(e,n,r)=>({ErrorEquals:e,Next:n,ResultPath:r||"$.error"})};static Patterns={sequential:(e,n,r)=>{let i={};return r.forEach((a,s)=>{let c=s===r.length-1;i[a.name]={...a.state,Next:c?void 0:r[s+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:i}},fanout:(e,n,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((i)=>i.definition),End:!0}}}),map:(e,n,r,i)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:i,End:!0}}}),withErrorHandling:(e,n,r,i)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:i,Success:{Type:"Succeed"}}})}}class Fi{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:a,namespace:s,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:y=!0,alarmActions:f,okActions:h,insufficientDataActions:S,dimensions:C,unit: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:a,Namespace:s,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:y}};if(f&&f.length>0)D.Properties.AlarmActions=f;if(h&&h.length>0)D.Properties.OKActions=h;if(S&&S.length>0)D.Properties.InsufficientDataActions=S;if(C)D.Properties.Dimensions=Object.entries(C).map(([N,M])=>({Name:N,Value:M}));if(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:a,actionsEnabled:s=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=i||l({slug:n,environment:r,resourceType:"composite-alarm"}),p=o(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:a,ActionsEnabled:s}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:n,environment:r,dashboardName:i,widgets:a}=e,s=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(s),u={widgets:a.map((m)=>({type:m.type,x:m.x,y:m.y,width:m.width,height:m.height,properties:m.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:s,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:a,kmsKeyId:s}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(a!==void 0)d.Properties.RetentionInDays=a;if(s)d.Properties.KmsKeyId=s;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:a}=n,s=a||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(s);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:P.Ref(e),LogStreamName:s}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:a,filterPattern:s,metricTransformations:c}=n,u=a||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:P.Ref(e),FilterPattern:s,MetricTransformations:c.map((p)=>({MetricName:p.metricName,MetricNamespace:p.metricNamespace,MetricValue:p.metricValue,DefaultValue:p.defaultValue,Unit:p.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:a?[a]:void 0}),highMemory:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:a?[a]:void 0}),highDisk:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:a?[a]:void 0}),lambdaErrors:(e,n,r,i=5,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:a?[a]:void 0}),lambdaThrottles:(e,n,r,i=10,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:a?[a]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:a?[a]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:a?[a]:void 0}),dynamoDBThrottles:(e,n,r,i=5,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:a?[a]:void 0}),rdsCpu:(e,n,r,i=80,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:a?[a]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:a?[a]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:a?[a]:void 0}),albUnhealthyTargets:(e,n,r,i,a=1,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:a,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:s?[s]:void 0}),sesBounceRate:(e,n,r=5,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),sesComplaintRate:(e,n,r=0.1,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),smsDeliveryFailure:(e,n,r,i=10,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:a?[a]:void 0}),smsSpendLimit:(e,n,r=100,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),connectMissedCalls:(e,n,r,i=5,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:a?[a]:void 0})};static DashboardWidgets={metric:(e,n,r,i,a,s)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:a,title:s||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,a)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:a}}),log:(e,n,r,i,a,s)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${a.join("' | SOURCE '")}'
2275
2275
  | fields @timestamp, @message
2276
2276
  | sort @timestamp desc
2277
2277
  | limit 20`,region:"us-east-1",title:s||"Logs"}})};static RetentionPeriods={ONE_DAY:1,THREE_DAYS:3,FIVE_DAYS:5,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,TWO_MONTHS:60,THREE_MONTHS:90,FOUR_MONTHS:120,FIVE_MONTHS:150,SIX_MONTHS:180,ONE_YEAR:365,THIRTEEN_MONTHS:400,EIGHTEEN_MONTHS:545,TWO_YEARS:731,FIVE_YEARS:1827,TEN_YEARS:3653,NEVER_EXPIRE:void 0};static FilterPatterns={errors:"[time, request_id, event_type = ERROR*, ...]",all:"",jsonField:(e,n)=>`{ $.${e} = "${n}" }`,httpStatus:(e)=>`[..., status_code = ${e}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(e){let{slug:n,environment:r,region:i="us-east-1",components:a={}}=e,s=[],c=0;if(s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:`# ${n.toUpperCase()} Dashboard (${r})`}}),c+=1,a.ec2InstanceIds&&a.ec2InstanceIds.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:a.ec2InstanceIds.map((u)=>["AWS/EC2","CPUUtilization","InstanceId",u]),period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Network Traffic",region:i,metrics:[...a.ec2InstanceIds.flatMap((u)=>[["AWS/EC2","NetworkIn","InstanceId",u,{label:`${u} In`}],["AWS/EC2","NetworkOut","InstanceId",u,{label:`${u} Out`}]])],period:300,stat:"Sum"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Status Checks",region:i,metrics:a.ec2InstanceIds.map((u)=>["AWS/EC2","StatusCheckFailed","InstanceId",u]),period:60,stat:"Maximum"}}),c+=6;if(a.lambdaFunctionNames&&a.lambdaFunctionNames.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Invocations",region:i,metrics:a.lambdaFunctionNames.map((u)=>["AWS/Lambda","Invocations","FunctionName",u]),period:300,stat:"Sum"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Duration",region:i,metrics:a.lambdaFunctionNames.map((u)=>["AWS/Lambda","Duration","FunctionName",u]),period:300,stat:"Average"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Errors",region:i,metrics:a.lambdaFunctionNames.map((u)=>["AWS/Lambda","Errors","FunctionName",u]),period:300,stat:"Sum"}}),c+=6;if(a.ecsClusterName&&a.ecsServiceName)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## ECS Service"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/ECS","CPUUtilization","ClusterName",a.ecsClusterName,"ServiceName",a.ecsServiceName]],period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Memory Utilization",region:i,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",a.ecsClusterName,"ServiceName",a.ecsServiceName]],period:300,stat:"Average"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Running Tasks",region:i,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",a.ecsClusterName,"ServiceName",a.ecsServiceName]],period:60,stat:"Average"}}),c+=6;if(a.albName)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Request Count",region:i,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",a.albName]],period:60,stat:"Sum"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Response Time",region:i,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",a.albName]],period:60,stat:"Average"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"HTTP Errors",region:i,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",a.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",a.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),c+=6;if(a.rdsInstanceId)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## RDS Database"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",a.rdsInstanceId]],period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Database Connections",region:i,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",a.rdsInstanceId]],period:60,stat:"Sum"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Free Storage Space",region:i,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",a.rdsInstanceId]],period:300,stat:"Average"}}),c+=6;if(a.sqsQueueNames&&a.sqsQueueNames.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## SQS Queues"}}),c+=1,s.push({type:"metric",x:0,y:c,width:12,height:6,properties:{title:"Messages Visible",region:i,metrics:a.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",u]),period:60,stat:"Sum"}}),s.push({type:"metric",x:12,y:c,width:12,height:6,properties:{title:"Message Age",region:i,metrics:a.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",u]),period:60,stat:"Maximum"}}),c+=6;if(a.logGroupNames&&a.logGroupNames.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Logs"}}),c+=1,s.push({type:"log",x:0,y:c,width:24,height:6,properties:{query:`SOURCE '${a.logGroupNames.join("' | SOURCE '")}'
2278
2278
  | fields @timestamp, @message
2279
2279
  | filter @message like /ERROR|WARN|Exception/
2280
2280
  | sort @timestamp desc
2281
- | limit 50`,region:i,title:"Recent Errors and Warnings"}}),c+=6;return Fi.createDashboard({slug:n,environment:r,widgets:s})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((n,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${n} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",n],["AWS/Lambda","Duration","FunctionName",n],["AWS/Lambda","Errors","FunctionName",n]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:n,namespace:r,threshold:i,comparisonOperator:a="GreaterThanThreshold",evaluationPeriods:s=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:a,EvaluationPeriods:s,Period:c,Statistic:u,TreatMissingData:d}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Pe{static createUserPool(e){let{slug:n,environment:r,userPoolName:i,aliasAttributes:a,autoVerifiedAttributes:s,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:y}=e,f=i||l({slug:n,environment:r,resourceType:"user-pool"}),h=o(f),S={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:f,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(a&&a.length>0)S.Properties.UsernameAttributes=a;if(s&&s.length>0)S.Properties.AutoVerifiedAttributes=s;if(d)S.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)S.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)S.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)S.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(y)S.Properties.AccountRecoverySetting={RecoveryMechanisms:y.recoveryMechanisms};return{userPool:S,logicalId:h}}static createUserPoolClient(e,n){let{slug:r,environment:i,clientName:a,generateSecret:s=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:C,allowedOAuthFlows:P,allowedOAuthScopes:E,allowedOAuthFlowsUserPoolClient:v,supportedIdentityProviders:I}=n,D=a||l({slug:r,environment:i,resourceType:"user-pool-client"}),N=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:R.Ref(e),GenerateSecret:s,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:C,AllowedOAuthFlows:P,AllowedOAuthScopes:E,AllowedOAuthFlowsUserPoolClient:v,SupportedIdentityProviders:I}},logicalId:N}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:a,customDomainConfig:s}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:a,UserPoolId:R.Ref(e),CustomDomainConfig:s}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:a=!1,cognitoIdentityProviders:s,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=i||l({slug:n,environment:r,resourceType:"identity-pool"}),p=o(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:a,CognitoIdentityProviders:s,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:a,unauthenticatedRole:s,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:a};if(s)m.unauthenticated=s;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:R.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.Ref(i)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"authenticated"}}}]},Policies:[{PolicyName:"CognitoAuthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*","cognito-identity:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},logicalId:s}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.Ref(i)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}}]},Policies:[{PolicyName:"CognitoUnauthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},logicalId:s}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,n,r)=>{let{userPool:i,logicalId:a}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:c}=Pe.createUserPoolClient(a,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Pe.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:a,client:s,clientId:c}},mobileApp:(e,n)=>{let{userPool:r,logicalId:i}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:a,logicalId:s}=Pe.createUserPoolClient(i,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Pe.createIdentityPool({slug:e,environment:n,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:R.Ref(s),ProviderName:R.GetAtt(i,"ProviderName")}]}),{role:d,logicalId:m}=Pe.createAuthenticatedRole({slug:e,environment:n,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=Pe.createIdentityPoolRoleAttachment(u,{slug:e,environment:n,authenticatedRole:R.GetAtt(m,"Arn")});return{userPool:r,poolId:i,client:a,clientId:s,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as $r}from"node:crypto";import{copyFileSync as Gr,existsSync as bt,readdirSync as _r,readFileSync as Xe,statSync as Wr,writeFileSync as et}from"node:fs";import{basename as Hr,dirname as mn,extname as pn,join as We}from"node:path";class De{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:a}=e,s=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(s);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:s,ComputePlatform:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:a,serviceRoleArn:s,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=a||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:R.Ref(e),DeploymentGroupName:f,ServiceRoleArn:s,AutoScalingGroups:c,Ec2TagFilters:u?.map((C)=>({Key:C.key,Value:C.value,Type:C.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((C)=>({Name:C.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((C)=>({Name:C.name})),ElbInfoList:g.elbInfoList?.map((C)=>({Name:C.name}))}:void 0,BlueGreenDeploymentConfiguration:y?{TerminateBlueInstancesOnDeploymentSuccess:y.terminateBlueInstancesOnDeploymentSuccess?{Action:y.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:y.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:y.deploymentReadyOption?{ActionOnTimeout:y.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:y.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:y.greenFleetProvisioningOption?{Action:y.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:i}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:n,environment:r,deploymentConfigName:i,minimumHealthyHosts:a,trafficRoutingConfig:s}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:a?{Type:a.type,Value:a.value}:void 0,TrafficRoutingConfig:s?{Type:s.type,TimeBasedCanary:s.timeBasedCanary?{CanaryPercentage:s.timeBasedCanary.canaryPercentage,CanaryInterval:s.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:s.timeBasedLinear?{LinearPercentage:s.timeBasedLinear.linearPercentage,LinearInterval:s.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,n)=>({type:e,value:n})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,n)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:n}}),linear:(e,n)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:n}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(e,n,r,i)=>{let{application:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,a=5)=>{let{application:s,logicalId:c}=De.createApplication({slug:e,environment:n,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=De.createDeploymentConfig({slug:e,environment:n,trafficRoutingConfig:De.TrafficRouting.canary(i,a)}),{deploymentGroup:m,logicalId:p}=De.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:R.Ref(d),autoRollbackConfiguration:De.RollbackConfigs.onAlarmOrFailure()});return{application:s,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:De.BlueGreenConfigs.standard(),autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,n=5)=>({type:"canary",canaryPercentage:e,canaryInterval:n}),allAtOnce:()=>({type:"all-at-once"})}}class ie{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(e,n="md5"){let r=Xe(e);return $r(n).update(r).digest("hex")}static computeShortHash(e){return ie.computeFileHash(e).slice(0,8)}static getContentType(e){let n=pn(e).toLowerCase();return ie.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...ie.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=pn(e),i=Hr(e,r),a=mn(e);if(a===".")return`${i}.${n}${r}`;return We(a,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!bt(e))return r;let a=_r(e,{withFileTypes:!0});for(let s of a){let c=We(e,s.name);if(s.isDirectory())r.push(...ie.collectFiles(c,i));else if(s.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:a="md5",copyUnhashed:s=!0}=e,c=ie.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=ie.shouldHashFile(g,i),f=Wr(p),h=y?ie.computeFileHash(p,a).slice(0,8):"",S=y?ie.generateHashedFilename(g,h):g,C={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:ie.getContentType(p)};if(u.push(C),d[g]=S,r){let P=We(r,S),E=mn(P);if(!bt(E)){let{mkdirSync:v}=zr("node:fs");v(E,{recursive:!0})}if(y||s)Gr(p,P)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=We(r,"asset-manifest.json");et(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,n){let r=[];if(!e)return["/*"];let i=e.hashMap,a=n.hashMap;for(let[s,c]of Object.entries(a)){let u=i[s];if(!u||u!==c){if(r.push(`/${s}`),u&&u!==c)r.push(`/${u}`)}}for(let[s,c]of Object.entries(i))if(!a[s])r.push(`/${s}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".html")||s.endsWith(".htm"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${ie.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}et(s,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".css"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}et(s,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:a={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ie.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=a.unhashed||"public, max-age=3600";if(d)m=a.html||"public, max-age=0, must-revalidate";else if(u)m=a.hashed||"public, max-age=31536000, immutable";return{localPath:We(n,c.originalPath),s3Key:r?`${r}/${c.hashedPath}`:c.hashedPath,contentType:c.contentType,cacheControl:m,hash:c.hash}})}static compareManifests(e,n){let r={added:[],removed:[],changed:[],unchanged:[]},i=new Set(Object.keys(e.hashMap)),a=new Set(Object.keys(n.hashMap));for(let s of a)if(!i.has(s))r.added.push(s);for(let s of i)if(!a.has(s))r.removed.push(s);for(let s of a)if(i.has(s))if(e.hashMap[s]!==n.hashMap[s])r.changed.push(s);else r.unchanged.push(s);return r}static loadManifest(e){if(!bt(e))return null;try{let n=Xe(e,"utf-8");return JSON.parse(n)}catch{return null}}static saveManifest(e,n){et(n,JSON.stringify(e,null,2))}}class Bi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:a,secretString:s,kmsKeyId:c,tags:u}=e,d=i||l({slug:n,environment:r,resourceType:"secret"}),m=o(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:a,SecretString:s,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,y])=>({Key:g,Value:y})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:n,environment:r,secretName:i,description:a,excludeCharacters:s,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:y,tags:f}=e,h=i||l({slug:n,environment:r,resourceType:"secret"}),S=o(h),C={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:a,GenerateSecretString:{ExcludeCharacters:s,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r},...f?Object.entries(f).map(([P,E])=>({Key:P,Value:E})):[]]}};if(y)C.Properties.KmsKeyId=y;return{secret:C,logicalId:S}}static createDatabaseSecret(e){let{slug:n,environment:r,secretName:i,username:a,dbname:s,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:a};if(s)y.dbname=s;if(c)y.engine=c;if(u)y.host=u;if(d)y.port=d;let f={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${a}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(y),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)f.Properties.KmsKeyId=m;return{secret:f,logicalId:g}}static attachToDatabase(e){let{slug:n,environment:r,secretId:i,targetId:a,targetType:s}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:a,TargetType:s}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:a,automaticallyAfterDays:s,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:n,environment:r,resourceType:"secret-rotation"}),g=o(p),y={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:i,RotationRules:{AutomaticallyAfterDays:s||30}}};if(a)y.Properties.RotationLambdaARN=a;else if(c)y.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:y,logicalId:g}}static SecretTypes={apiKey:(e,n,r)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,n,r)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,n)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class X{static createParameter(e){let{slug:n,environment:r,parameterName:i,value:a,type:s="String",description:c,tier:u="Standard",tags:d}=e,m=i||l({slug:n,environment:r,resourceType:"parameter"}),p=o(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${n}/${r}/${m}`,Type:s,Value:a,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:a})}static createSecureString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:a})}static createStringList(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:a})}static Parameters={databaseUrl:(e,n,r)=>X.createSecureString(e,n,"database-url",r,"Database connection URL"),apiEndpoint:(e,n,r)=>X.createString(e,n,"api-endpoint",r,"API endpoint URL"),appVersion:(e,n,r)=>X.createString(e,n,"app-version",r,"Application version"),featureFlags:(e,n,r)=>X.createStringList(e,n,"feature-flags",r,"Enabled feature flags"),apiKey:(e,n,r,i)=>X.createSecureString(e,n,`${r}-api-key`,i,`API key for ${r}`),oauthCredentials:(e,n,r,i)=>{let a=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),s=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:a,clientSecret:s}},smtpCredentials:(e,n,r,i,a,s)=>{let c=X.createString(e,n,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,n,"smtp-password",i,"SMTP password"),d=X.createString(e,n,"smtp-host",a,"SMTP host"),m=X.createString(e,n,"smtp-port",s.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,n,r)=>X.createSecureString(e,n,"redis-url",r,"Redis connection URL"),s3Bucket:(e,n,r)=>X.createString(e,n,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,n,r)=>X.createString(e,n,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Kt{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:a="OpenSearch_2.11",instanceType:s="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:y=!1,availabilityZoneCount:f=2,vpc:h,encryption:S,enforceHttps:C=!0,tlsSecurityPolicy:P="Policy-Min-TLS-1-2-2019-07",advancedSecurity:E,autoSnapshotHour:v=0,autoTune:I=!0,tags:D={}}=e,N=i||l({slug:n,environment:r,resourceType:"search"}),M=o(N);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:N,EngineVersion:a,ClusterConfig:{InstanceType:s,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||s,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:C,TLSSecurityPolicy:P},SnapshotOptions:{AutomatedSnapshotStartHour:v},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...S&&{EncryptionAtRestOptions:{Enabled:S.atRest??!0,...S.kmsKeyId&&{KmsKeyId:S.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:S.nodeToNode??!0}},...E&&{AdvancedSecurityOptions:{Enabled:E.enabled,InternalUserDatabaseEnabled:E.internalUserDatabase??!0,...E.masterUserName&&E.masterUserPassword&&{MasterUserOptions:{MasterUserName:E.masterUserName,MasterUserPassword:E.masterUserPassword}},...E.masterUserArn&&{MasterUserOptions:{MasterUserARN:E.masterUserArn}}}},...I&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:r},...Object.entries(D).map(([O,G])=>({Key:O,Value:G}))]}},logicalId:M}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:a,vpcEndpoint:s}=n;if(a)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(i&&i.length>0)c.push({Effect:"Allow",Principal:{AWS:i},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,n)=>Kt.createDomain({slug:e,environment:n,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,n,r)=>Kt.createDomain({slug:e,environment:n,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,n)=>Kt.createDomain({slug:e,environment:n,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,n,r)=>Kt.createDomain({slug:e,environment:n,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class It{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:a,protocol:s="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"redirect"}),u=o(c),d=o(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:a,Protocol:s}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:R.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[R.Join("",[R.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:n,environment:r,rules:i}=e,a=l({slug:n,environment:r,resourceType:"cf-redirect"}),s=o(a),c=It.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:a,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:s,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
2281
+ | limit 50`,region:i,title:"Recent Errors and Warnings"}}),c+=6;return Fi.createDashboard({slug:n,environment:r,widgets:s})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((n,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${n} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",n],["AWS/Lambda","Duration","FunctionName",n],["AWS/Lambda","Errors","FunctionName",n]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:n,namespace:r,threshold:i,comparisonOperator:a="GreaterThanThreshold",evaluationPeriods:s=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:a,EvaluationPeriods:s,Period:c,Statistic:u,TreatMissingData:d}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Pe{static createUserPool(e){let{slug:n,environment:r,userPoolName:i,aliasAttributes:a,autoVerifiedAttributes:s,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:y}=e,f=i||l({slug:n,environment:r,resourceType:"user-pool"}),h=o(f),S={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:f,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(a&&a.length>0)S.Properties.UsernameAttributes=a;if(s&&s.length>0)S.Properties.AutoVerifiedAttributes=s;if(d)S.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)S.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)S.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)S.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(y)S.Properties.AccountRecoverySetting={RecoveryMechanisms:y.recoveryMechanisms};return{userPool:S,logicalId:h}}static createUserPoolClient(e,n){let{slug:r,environment:i,clientName:a,generateSecret:s=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:C,allowedOAuthFlows:E,allowedOAuthScopes:w,allowedOAuthFlowsUserPoolClient:v,supportedIdentityProviders:I}=n,D=a||l({slug:r,environment:i,resourceType:"user-pool-client"}),N=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:P.Ref(e),GenerateSecret:s,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:C,AllowedOAuthFlows:E,AllowedOAuthScopes:w,AllowedOAuthFlowsUserPoolClient:v,SupportedIdentityProviders:I}},logicalId:N}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:a,customDomainConfig:s}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:a,UserPoolId:P.Ref(e),CustomDomainConfig:s}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:a=!1,cognitoIdentityProviders:s,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=i||l({slug:n,environment:r,resourceType:"identity-pool"}),p=o(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:a,CognitoIdentityProviders:s,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:a,unauthenticatedRole:s,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:a};if(s)m.unauthenticated=s;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:P.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":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:a},{Key:"Environment",Value:r}]}},logicalId:s}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":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:a},{Key:"Environment",Value:r}]}},logicalId:s}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,n,r)=>{let{userPool:i,logicalId:a}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:c}=Pe.createUserPoolClient(a,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Pe.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:a,client:s,clientId:c}},mobileApp:(e,n)=>{let{userPool:r,logicalId:i}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:a,logicalId:s}=Pe.createUserPoolClient(i,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Pe.createIdentityPool({slug:e,environment:n,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:P.Ref(s),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:a,clientId:s,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as $r}from"node:crypto";import{copyFileSync as Gr,existsSync as bt,readdirSync as _r,readFileSync as Xe,statSync as Wr,writeFileSync as et}from"node:fs";import{basename as Hr,dirname as mn,extname as pn,join as We}from"node:path";class De{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:a}=e,s=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(s);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:s,ComputePlatform:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:a,serviceRoleArn:s,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=a||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:P.Ref(e),DeploymentGroupName:f,ServiceRoleArn:s,AutoScalingGroups:c,Ec2TagFilters:u?.map((C)=>({Key:C.key,Value:C.value,Type:C.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((C)=>({Name:C.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((C)=>({Name:C.name})),ElbInfoList:g.elbInfoList?.map((C)=>({Name:C.name}))}:void 0,BlueGreenDeploymentConfiguration:y?{TerminateBlueInstancesOnDeploymentSuccess:y.terminateBlueInstancesOnDeploymentSuccess?{Action:y.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:y.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:y.deploymentReadyOption?{ActionOnTimeout:y.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:y.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:y.greenFleetProvisioningOption?{Action:y.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:i}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:n,environment:r,deploymentConfigName:i,minimumHealthyHosts:a,trafficRoutingConfig:s}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:a?{Type:a.type,Value:a.value}:void 0,TrafficRoutingConfig:s?{Type:s.type,TimeBasedCanary:s.timeBasedCanary?{CanaryPercentage:s.timeBasedCanary.canaryPercentage,CanaryInterval:s.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:s.timeBasedLinear?{LinearPercentage:s.timeBasedLinear.linearPercentage,LinearInterval:s.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,n)=>({type:e,value:n})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,n)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:n}}),linear:(e,n)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:n}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(e,n,r,i)=>{let{application:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,a=5)=>{let{application:s,logicalId:c}=De.createApplication({slug:e,environment:n,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=De.createDeploymentConfig({slug:e,environment:n,trafficRoutingConfig:De.TrafficRouting.canary(i,a)}),{deploymentGroup:m,logicalId:p}=De.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:P.Ref(d),autoRollbackConfiguration:De.RollbackConfigs.onAlarmOrFailure()});return{application:s,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:De.BlueGreenConfigs.standard(),autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,n=5)=>({type:"canary",canaryPercentage:e,canaryInterval:n}),allAtOnce:()=>({type:"all-at-once"})}}class ie{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(e,n="md5"){let r=Xe(e);return $r(n).update(r).digest("hex")}static computeShortHash(e){return ie.computeFileHash(e).slice(0,8)}static getContentType(e){let n=pn(e).toLowerCase();return ie.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...ie.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=pn(e),i=Hr(e,r),a=mn(e);if(a===".")return`${i}.${n}${r}`;return We(a,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!bt(e))return r;let a=_r(e,{withFileTypes:!0});for(let s of a){let c=We(e,s.name);if(s.isDirectory())r.push(...ie.collectFiles(c,i));else if(s.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:a="md5",copyUnhashed:s=!0}=e,c=ie.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=ie.shouldHashFile(g,i),f=Wr(p),h=y?ie.computeFileHash(p,a).slice(0,8):"",S=y?ie.generateHashedFilename(g,h):g,C={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:ie.getContentType(p)};if(u.push(C),d[g]=S,r){let E=We(r,S),w=mn(E);if(!bt(w)){let{mkdirSync:v}=zr("node:fs");v(w,{recursive:!0})}if(y||s)Gr(p,E)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=We(r,"asset-manifest.json");et(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,n){let r=[];if(!e)return["/*"];let i=e.hashMap,a=n.hashMap;for(let[s,c]of Object.entries(a)){let u=i[s];if(!u||u!==c){if(r.push(`/${s}`),u&&u!==c)r.push(`/${u}`)}}for(let[s,c]of Object.entries(i))if(!a[s])r.push(`/${s}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".html")||s.endsWith(".htm"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${ie.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}et(s,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".css"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}et(s,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:a={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ie.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=a.unhashed||"public, max-age=3600";if(d)m=a.html||"public, max-age=0, must-revalidate";else if(u)m=a.hashed||"public, max-age=31536000, immutable";return{localPath:We(n,c.originalPath),s3Key:r?`${r}/${c.hashedPath}`:c.hashedPath,contentType:c.contentType,cacheControl:m,hash:c.hash}})}static compareManifests(e,n){let r={added:[],removed:[],changed:[],unchanged:[]},i=new Set(Object.keys(e.hashMap)),a=new Set(Object.keys(n.hashMap));for(let s of a)if(!i.has(s))r.added.push(s);for(let s of i)if(!a.has(s))r.removed.push(s);for(let s of a)if(i.has(s))if(e.hashMap[s]!==n.hashMap[s])r.changed.push(s);else r.unchanged.push(s);return r}static loadManifest(e){if(!bt(e))return null;try{let n=Xe(e,"utf-8");return JSON.parse(n)}catch{return null}}static saveManifest(e,n){et(n,JSON.stringify(e,null,2))}}class Bi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:a,secretString:s,kmsKeyId:c,tags:u}=e,d=i||l({slug:n,environment:r,resourceType:"secret"}),m=o(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:a,SecretString:s,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,y])=>({Key:g,Value:y})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:n,environment:r,secretName:i,description:a,excludeCharacters:s,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:y,tags:f}=e,h=i||l({slug:n,environment:r,resourceType:"secret"}),S=o(h),C={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:a,GenerateSecretString:{ExcludeCharacters:s,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r},...f?Object.entries(f).map(([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:a,dbname:s,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:a};if(s)y.dbname=s;if(c)y.engine=c;if(u)y.host=u;if(d)y.port=d;let f={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${a}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(y),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)f.Properties.KmsKeyId=m;return{secret:f,logicalId:g}}static attachToDatabase(e){let{slug:n,environment:r,secretId:i,targetId:a,targetType:s}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:a,TargetType:s}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:a,automaticallyAfterDays:s,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:n,environment:r,resourceType:"secret-rotation"}),g=o(p),y={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:i,RotationRules:{AutomaticallyAfterDays:s||30}}};if(a)y.Properties.RotationLambdaARN=a;else if(c)y.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:y,logicalId:g}}static SecretTypes={apiKey:(e,n,r)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,n,r)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,n)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class X{static createParameter(e){let{slug:n,environment:r,parameterName:i,value:a,type:s="String",description:c,tier:u="Standard",tags:d}=e,m=i||l({slug:n,environment:r,resourceType:"parameter"}),p=o(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${n}/${r}/${m}`,Type:s,Value:a,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:a})}static createSecureString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:a})}static createStringList(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:a})}static Parameters={databaseUrl:(e,n,r)=>X.createSecureString(e,n,"database-url",r,"Database connection URL"),apiEndpoint:(e,n,r)=>X.createString(e,n,"api-endpoint",r,"API endpoint URL"),appVersion:(e,n,r)=>X.createString(e,n,"app-version",r,"Application version"),featureFlags:(e,n,r)=>X.createStringList(e,n,"feature-flags",r,"Enabled feature flags"),apiKey:(e,n,r,i)=>X.createSecureString(e,n,`${r}-api-key`,i,`API key for ${r}`),oauthCredentials:(e,n,r,i)=>{let a=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),s=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:a,clientSecret:s}},smtpCredentials:(e,n,r,i,a,s)=>{let c=X.createString(e,n,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,n,"smtp-password",i,"SMTP password"),d=X.createString(e,n,"smtp-host",a,"SMTP host"),m=X.createString(e,n,"smtp-port",s.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,n,r)=>X.createSecureString(e,n,"redis-url",r,"Redis connection URL"),s3Bucket:(e,n,r)=>X.createString(e,n,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,n,r)=>X.createString(e,n,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Kt{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:a="OpenSearch_2.11",instanceType:s="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:y=!1,availabilityZoneCount:f=2,vpc:h,encryption:S,enforceHttps:C=!0,tlsSecurityPolicy:E="Policy-Min-TLS-1-2-2019-07",advancedSecurity:w,autoSnapshotHour:v=0,autoTune:I=!0,tags:D={}}=e,N=i||l({slug:n,environment:r,resourceType:"search"}),M=o(N);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:N,EngineVersion:a,ClusterConfig:{InstanceType:s,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||s,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:C,TLSSecurityPolicy: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:N},{Key:"Environment",Value:r},...Object.entries(D).map(([O,G])=>({Key:O,Value:G}))]}},logicalId:M}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:a,vpcEndpoint:s}=n;if(a)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(i&&i.length>0)c.push({Effect:"Allow",Principal:{AWS:i},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,n)=>Kt.createDomain({slug:e,environment:n,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,n,r)=>Kt.createDomain({slug:e,environment:n,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,n)=>Kt.createDomain({slug:e,environment:n,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,n,r)=>Kt.createDomain({slug:e,environment:n,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class It{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:a,protocol:s="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"redirect"}),u=o(c),d=o(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:a,Protocol:s}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket: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,a=l({slug:n,environment:r,resourceType:"cf-redirect"}),s=o(a),c=It.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:a,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:s,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
2282
2282
  const request = event.request;
2283
2283
  const uri = request.uri;
2284
2284
  const querystring = request.querystring;
@@ -2332,7 +2332,7 @@ ${e.map((r)=>{let i=r.preserveQueryString!==!1,a=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:a=[]}=e,s={},c=[];for(let d of i){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:y}=It.createDomainRedirectBucket({...d,slug:n,environment:r});s[g]=m,s[y]=p,c.push(g)}let u=null;if(a.length>0){let{function:d,logicalId:m}=It.createPathRedirectFunction({slug:n,environment:r,rules:a});s[m]=d,u=m}return{resources:s,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 a of e){if(i.has(a.source))n.push(`Duplicate source path: ${a.source}`);if(i.add(a.source),a.source===a.target)n.push(`Redirect loop detected: ${a.source} -> ${a.target}`);if(!a.target.startsWith("/")&&!a.target.startsWith("http"))r.push(`Target URL should start with / or http: ${a.target}`);if(!a.source||a.source.trim()==="")n.push("Source path cannot be empty");if(!a.target||a.target.trim()==="")n.push("Target path cannot be empty")}for(let a of e){let s=e.find((c)=>c.source===a.target);if(s)r.push(`Potential redirect chain: ${a.source} -> ${a.target} -> ${s.target}`)}return{valid:n.length===0,errors:n,warnings:r}}}class ke{static generate(e){let n={},{slug:r,environment:i,region:a="us-east-1"}=e,s=ke.createLambdaExecutionRole(r,i);if(Object.assign(n,s.resources),e.email?.enabled){let c=ke.generateEmailResources(e,s.roleArn);Object.assign(n,c)}if(e.phone?.enabled){let c=ke.generatePhoneResources(e,s.roleArn);Object.assign(n,c)}if(e.sms?.enabled){let c=ke.generateSmsResources(e,s.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:a}=e;if(!a)return{};let s={},c=`${r}-${i}`,u=`${c}-email-storage`,d=o(u);s[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:a.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:a.server.storage.archiveAfterDays}]:[],ExpirationInDays:a.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let m=o(`${c}-ses-identity`);if(s[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:a.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},a.notifications?.bounces||a.notifications?.complaints){let p=o(`${c}-bounce-topic`);s[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=o(`${c}-complaint-topic`);s[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(a.server?.enabled){let p=o(`${c}-inbound-email`);s[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:a.domain}}}};let g=o(`${c}-outbound-email`);s[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:a.domain}}}}}if(a.advanced?.analytics){let p=o(`${c}-email-analytics`);s[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(a.advanced?.scheduling){let p=o(`${c}-email-scheduler`);s[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`);s[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(a.advanced?.threading){let p=o(`${c}-email-threading`);s[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(a.advanced?.rules){let p=o(`${c}-email-rules`);s[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(a.advanced?.sharedMailboxes){let p=o(`${c}-shared-mailboxes`);s[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(a.advanced?.search){let p=o(`${c}-email-search`);s[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 s}static generatePhoneResources(e,n){let{slug:r,environment:i,phone:a}=e;if(!a)return{};let s={},c=`${r}-${i}`,u=o(`${c}-call-log`);if(s[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}}},a.voicemail?.enabled){let p=o(`${c}-voicemail`);s[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=o(`${c}-phone-notifications`);s[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=o(`${c}-incoming-call`);if(s[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)}}}},a.voicemail?.enabled){let p=o(`${c}-voicemail-handler`);s[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:a.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ke.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(a.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:R.Ref(d)}}}}}if(a.advanced?.recording){let p=o(`${c}-call-recordings`);s[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(a.advanced?.callbacks){let p=o(`${c}-callbacks`);s[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(a.advanced?.analytics){let p=o(`${c}-call-metrics`);s[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 s}static generateSmsResources(e,n){let{slug:r,environment:i,sms:a}=e;if(!a)return{};let s={},c=`${r}-${i}`,u=o(`${c}-pinpoint-app`);s[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=o(`${c}-sms-channel`);s[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:R.Ref(u),Enabled:!0,SenderId:a.senderId}};let m=o(`${c}-sms-log`);if(s[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}}},a.optOut?.enabled){let f=o(`${c}-sms-optout`);s[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`);s[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=o(`${c}-send-sms`);s[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:a.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:a.messageType||"TRANSACTIONAL"}}}};let y=o(`${c}-receive-sms`);if(s[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:a.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:R.Ref(p)}}}},a.advanced?.campaigns){let f=o(`${c}-sms-campaigns`);s[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(a.advanced?.analytics){let f=o(`${c}-sms-analytics`);s[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(a.advanced?.linkTracking){let f=o(`${c}-short-links`);s[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(a.advanced?.chatbot){let f=o(`${c}-chatbot-sessions`);s[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`);s[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(a.advanced?.abTesting){let f=o(`${c}-ab-tests`);s[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(a.advanced?.mms){let f=o(`${c}-mms-media`);s[f]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return s}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:a=[]}=e,s={},c=[];for(let d of i){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:y}=It.createDomainRedirectBucket({...d,slug:n,environment:r});s[g]=m,s[y]=p,c.push(g)}let u=null;if(a.length>0){let{function:d,logicalId:m}=It.createPathRedirectFunction({slug:n,environment:r,rules:a});s[m]=d,u=m}return{resources:s,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 a of e){if(i.has(a.source))n.push(`Duplicate source path: ${a.source}`);if(i.add(a.source),a.source===a.target)n.push(`Redirect loop detected: ${a.source} -> ${a.target}`);if(!a.target.startsWith("/")&&!a.target.startsWith("http"))r.push(`Target URL should start with / or http: ${a.target}`);if(!a.source||a.source.trim()==="")n.push("Source path cannot be empty");if(!a.target||a.target.trim()==="")n.push("Target path cannot be empty")}for(let a of e){let s=e.find((c)=>c.source===a.target);if(s)r.push(`Potential redirect chain: ${a.source} -> ${a.target} -> ${s.target}`)}return{valid:n.length===0,errors:n,warnings:r}}}class ke{static generate(e){let n={},{slug:r,environment:i,region:a="us-east-1"}=e,s=ke.createLambdaExecutionRole(r,i);if(Object.assign(n,s.resources),e.email?.enabled){let c=ke.generateEmailResources(e,s.roleArn);Object.assign(n,c)}if(e.phone?.enabled){let c=ke.generatePhoneResources(e,s.roleArn);Object.assign(n,c)}if(e.sms?.enabled){let c=ke.generateSmsResources(e,s.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:a}=e;if(!a)return{};let s={},c=`${r}-${i}`,u=`${c}-email-storage`,d=o(u);s[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:a.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:a.server.storage.archiveAfterDays}]:[],ExpirationInDays:a.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let m=o(`${c}-ses-identity`);if(s[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:a.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},a.notifications?.bounces||a.notifications?.complaints){let p=o(`${c}-bounce-topic`);s[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=o(`${c}-complaint-topic`);s[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(a.server?.enabled){let p=o(`${c}-inbound-email`);s[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:a.domain}}}};let g=o(`${c}-outbound-email`);s[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:a.domain}}}}}if(a.advanced?.analytics){let p=o(`${c}-email-analytics`);s[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(a.advanced?.scheduling){let p=o(`${c}-email-scheduler`);s[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`);s[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(a.advanced?.threading){let p=o(`${c}-email-threading`);s[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(a.advanced?.rules){let p=o(`${c}-email-rules`);s[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(a.advanced?.sharedMailboxes){let p=o(`${c}-shared-mailboxes`);s[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(a.advanced?.search){let p=o(`${c}-email-search`);s[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 s}static generatePhoneResources(e,n){let{slug:r,environment:i,phone:a}=e;if(!a)return{};let s={},c=`${r}-${i}`,u=o(`${c}-call-log`);if(s[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}}},a.voicemail?.enabled){let p=o(`${c}-voicemail`);s[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=o(`${c}-phone-notifications`);s[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=o(`${c}-incoming-call`);if(s[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)}}}},a.voicemail?.enabled){let p=o(`${c}-voicemail-handler`);s[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:a.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ke.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(a.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:P.Ref(d)}}}}}if(a.advanced?.recording){let p=o(`${c}-call-recordings`);s[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(a.advanced?.callbacks){let p=o(`${c}-callbacks`);s[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(a.advanced?.analytics){let p=o(`${c}-call-metrics`);s[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 s}static generateSmsResources(e,n){let{slug:r,environment:i,sms:a}=e;if(!a)return{};let s={},c=`${r}-${i}`,u=o(`${c}-pinpoint-app`);s[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=o(`${c}-sms-channel`);s[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:P.Ref(u),Enabled:!0,SenderId:a.senderId}};let m=o(`${c}-sms-log`);if(s[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}}},a.optOut?.enabled){let f=o(`${c}-sms-optout`);s[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`);s[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=o(`${c}-send-sms`);s[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:a.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:a.messageType||"TRANSACTIONAL"}}}};let y=o(`${c}-receive-sms`);if(s[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:a.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:P.Ref(p)}}}},a.advanced?.campaigns){let f=o(`${c}-sms-campaigns`);s[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(a.advanced?.analytics){let f=o(`${c}-sms-analytics`);s[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(a.advanced?.linkTracking){let f=o(`${c}-short-links`);s[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(a.advanced?.chatbot){let f=o(`${c}-chatbot-sessions`);s[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`);s[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(a.advanced?.abTesting){let f=o(`${c}-ab-tests`);s[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(a.advanced?.mms){let f=o(`${c}-mms-media`);s[f]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return s}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) => {
@@ -2458,7 +2458,7 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
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 Bm(e){let{name:n,slug:r,domain:i,repository:a,phpVersion:s="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:i}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[s],default:s},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:i,phpVersion:s,repository:{...a,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function jm(e){let{name:n,slug:r,domain:i,layers:a,phpVersion:s="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:y="us-east-1"}=e;return{project:{name:n,slug:r,region:y},mode:"serverless",environments:{production:{type:"production",domain:i,app:{kind:"php",runtime:"provided.al2023",phpVersion:s,architecture:c,layers:a,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:i}}}}}function Vm(e){return{root:e.root??"packages/ui/dist",deploy:"server",type:"static",domain:e.domain,build:e.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:e.username??"admin",password:e.password}}}var du=sa,uu="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function Si(e){let n=e.split(".").filter(Boolean);return n.length<=2?e:n.slice(-2).join(".")}function Ai(e){let n=2166136261;for(let r=0;r<e.length;r++)n^=e.charCodeAt(r),n=Math.imul(n,16777619);return n>>>0}var pu=20000,mu=12000;function gu(e){return pu+Ai(e)%mu}function Bn(e,n){let r=Si(e);if(r===e)return`dashboard.${r}`;for(let i of n)if(i===r)return`dashboard.${r}`;return`dashboard.${e}`}function Fn(e,n){let r=[],i=e.infrastructure?.dns?.domain;if(i&&!e.cloud?.attachTo)r.push(i);if(n&&e.environments?.[n]?.domain)r.push(e.environments[n].domain);for(let a of Object.values(e.sites??{})){let s=a;if(!s||s.redirect)continue;let c=s.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((a)=>a&&!a.startsWith("dashboard."))}function fu(e,n,r){if(r)return r;let i=Fn(e,n),a=i[0];if(!a)return null;return Bn(a,i)}function hu(e,n,r){if(r)return[r];let i=Fn(e,n),a=[];for(let s of i){let c=Bn(s,i);if(!a.includes(c))a.push(c)}return a}function Jt(e){return Object.entries(e.sites??{}).some(([n,r])=>{if(!r)return!1;let i=r.root??"";return Br(n)||i==="ui/dist"||i.endsWith("/ui/dist")||i.endsWith("/dist/ui")})}var dl="dashboard-";function ul(e){return dl+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Br(e){return e==="dashboard"||e.startsWith(dl)}function ji(e,n,r){if(Jt(e))return[];if(e.cloud?.attachTo)return[];let i=r.password?{auth:{username:r.username||"admin",password:r.password,realm:r.realm}}:{},a=r.build===!1||r.build===void 0?{}:{build:r.build};if(r.live!==!1){let c=fu(e,n,r.domain);if(!c)return[];let u=r.port??gu(c),d=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,m={root:r.uiRoot,deploy:"server",domain:c,preStart:["bun install --production --no-save"],start:`bun ${uu} --box --host 127.0.0.1 --port ${u}`,port:u,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...d?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:d.password}:{}},zeroDowntime:!1,sharedPaths:[du],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:ul(c),site:m}]}return hu(e,n,r.domain).map((c)=>({name:ul(c),site:{root:r.uiRoot,deploy:"server",type:"static",domain:c,ssl:{provider:"letsencrypt"},...a,...i}}))}function zm(e,n,r){return ji(e,n,r)[0]??null}function vt(e,n){let r={...e};for(let i in n){let a=n[i],s=r[i];if(a===void 0)continue;if(Array.isArray(a)&&Array.isArray(s))r[i]=[...s,...a];else if(typeof a==="object"&&a!==null&&!Array.isArray(a)&&typeof s==="object"&&s!==null&&!Array.isArray(s))r[i]=vt(s,a);else r[i]=a}return r}function pl(e,n){return vt(e,n)}function Hm(...e){return e.reduce((n,r)=>vt(n,r),{})}function qm(e,n){return(r)=>{let i=e(r);if(typeof n==="function")return pl(i,n(i,r));return pl(i,n)}}function An(e){return{infrastructure:e}}function Gm(e){return An({monitoring:e})}function Wm(e){return An({security:e})}function Km(e){return An({databases:e})}function Jm(e){return An({cache:e})}function Xm(e){return An({cdn:e})}function Qm(e){return An({queues:e})}import{existsSync as Gn,readFileSync as Tt}from"node:fs";import{homedir as _n}from"node:os";import{join as Wn}from"node:path";function yu(){let e=process.env.AWS_ACCESS_KEY_ID,n=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!n)return null;return{accessKeyId:e,secretAccessKey:n,sessionToken:process.env.AWS_SESSION_TOKEN}}function bu(e){let n=e?.profile||process.env.AWS_PROFILE||"default",r=e?.credentialsFile||Wn(_n(),".aws","credentials");if(!Gn(r))return null;try{let i=Tt(r,"utf-8");return Ci(i,n)}catch{return null}}function Ci(e,n){let r=e.split(`
2459
2459
  `),i=null,a,s,c;for(let u of r){let d=u.trim();if(!d||d.startsWith("#")||d.startsWith(";"))continue;let m=d.match(/^\[([^\]]+)\]$/);if(m){if(i===n&&a&&s)return{accessKeyId:a,secretAccessKey:s,sessionToken:c};i=m[1],a=void 0,s=void 0,c=void 0;continue}if(i===n){let[p,...g]=d.split("="),y=g.join("=").trim();switch(p.trim().toLowerCase()){case"aws_access_key_id":a=y;break;case"aws_secret_access_key":s=y;break;case"aws_session_token":c=y;break}}}if(i===n&&a&&s)return{accessKeyId:a,secretAccessKey:s,sessionToken:c};return null}async function Su(e){let n=e?.timeout??1000,r="http://169.254.169.254";try{let i=await Ke("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},n);if(!i.ok)return null;let a=await i.text(),s=await Ke("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":a}},n);if(!s.ok)return null;let c=(await s.text()).trim(),u=await Ke(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":a}},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function vu(e){let n=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,i=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,a=null;if(r)a=`http://169.254.170.2${r}`;else if(i)a=i;if(!a)return null;try{let s={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)s.Authorization=c;let u=await Ke(a,{headers:s},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Cu(e){let n=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,i=process.env.AWS_ROLE_ARN,a=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!i)return null;try{let s=Tt(r,"utf-8").trim(),c=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",u=c.startsWith("us-gov")?`https://sts.${c}.amazonaws.com`:c==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${c}.amazonaws.com`,d=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:i,RoleSessionName:a,WebIdentityToken:s}),m=await Ke(`${u}/?${d.toString()}`,{method:"POST"},n);if(!m.ok)return null;let p=await m.text(),g=Ue(p,"AccessKeyId"),y=Ue(p,"SecretAccessKey"),f=Ue(p,"SessionToken"),h=Ue(p,"Expiration");if(!g||!y)return null;return{accessKeyId:g,secretAccessKey:y,sessionToken:f??void 0,expiration:h?new Date(h):void 0}}catch{return null}}async function Vi(e){let n=yu();if(n)return n;let r=bu(e);if(r)return r;let i=await Cu(e);if(i)return i;let a=await vu(e);if(a)return a;let s=await Su(e);if(s)return s;throw Error("Could not find AWS credentials. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or configure ~/.aws/credentials, or run on an EC2 instance with an IAM role.")}function Ym(e){let n=null,r=null;return async()=>{if(n){if(!n.expiration)return n;let i=300000;if(n.expiration.getTime()-Date.now()>i)return n}if(r)return r;return r=Vi(e).then((i)=>(n=i,r=null,i)).catch((i)=>{throw r=null,i}),r}}async function Ke(e,n,r){let i=new AbortController,a=setTimeout(()=>i.abort(),r);try{let s=await fetch(e,{...n,signal:i.signal});return clearTimeout(a),s}catch(s){throw clearTimeout(a),s}}function Ue(e,n){let r=new RegExp(`<${n}>([^<]+)</${n}>`),i=e.match(r);return i?i[1]:null}async function Rn(e){return Vi({profile:e})}function Tu(e){let n=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(n)return n;let r=Wn(_n(),".aws","config");if(Gn(r))try{let i=Tt(r,"utf-8"),a=e||process.env.AWS_PROFILE||"default",s=a==="default"?"[default]":`[profile ${a}]`,c=i.split(`
2460
2460
  `),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===s;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function ml(e){let n=e||await Vi(),r=Tu(),{signRequest:i}=await import("./chunk-hzc049ns.js"),a=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,s="Action=GetCallerIdentity&Version=2011-06-15",c=i({method:"POST",url:a,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...n,service:"sts",region:r}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:c.body});if(!u.ok)throw Error(`Failed to get account ID: ${await u.text()}`);let d=await u.text(),m=Ue(d,"Account");if(!m)throw Error("Failed to parse account ID from response");return m}class Eu{profile;credentials=null;region;constructor(e="us-east-1",n="default"){this.profile=n;this.region=e}async init(){if(this.credentials=await Rn(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,n){let r=await this.ensureCredentials(),i={Action:e,Version:"2010-05-15",...Et(n)},a=new URLSearchParams(i).toString(),c=await(await kt({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:a,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken})).text();return vi(c)}async createStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[a,[s,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${a+1}.ParameterKey`]=s,n[`Parameters.member.${a+1}.ParameterValue`]=c;if(e.capabilities)for(let[a,s]of e.capabilities.entries())n[`Capabilities.member.${a+1}`]=s;if(e.tags)for(let[a,[s,c]]of Object.entries(e.tags).entries())n[`Tags.member.${a+1}.Key`]=s,n[`Tags.member.${a+1}.Value`]=c;if(e.timeoutInMinutes)n.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)n.OnFailure=e.onFailure;let r=await this.request("CreateStack",n);return(r?.CreateStackResult||r?.CreateStackResponse?.CreateStackResult||r)?.StackId}async updateStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[a,[s,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${a+1}.ParameterKey`]=s,n[`Parameters.member.${a+1}.ParameterValue`]=c;if(e.capabilities)for(let[a,s]of e.capabilities.entries())n[`Capabilities.member.${a+1}`]=s;if(e.tags)for(let[a,[s,c]]of Object.entries(e.tags).entries())n[`Tags.member.${a+1}.Key`]=s,n[`Tags.member.${a+1}.Value`]=c;let r=await this.request("UpdateStack",n);return(r?.UpdateStackResult||r?.UpdateStackResponse?.UpdateStackResult||r)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,a=Array.isArray(i)?i[0]:i;if(!a)throw Error(`Stack ${e} not found`);return Ti(a)}async listStacks(e){let n={};if(e)for(let[i,a]of e.entries())n[`StackStatusFilter.member.${i+1}`]=a;let r=await this.request("ListStacks",n);return Ri(r)}async describeStackEvents(e){let n=await this.request("DescribeStackEvents",{StackName:e});return Pi(n)}async waitForStack(e,n,r){let s=0,c=null;while(s<360){s++;let u=await this.describeStack(e);if(r)try{let d=await this.describeStackEvents(e),m=[];if(c){for(let p of d){if(p.EventId===c)break;m.push(p)}m.reverse()}else if(d.length>0)m=[d[0]];for(let p of m)r(p);if(d.length>0)c=d[0].EventId}catch{}if(u.StackStatus&&n.includes(u.StackStatus))return u;if(u.StackStatus?.includes("FAILED")||u.StackStatus?.includes("ROLLBACK"))throw Error(`Stack reached failed state: ${u.StackStatus}
2461
- Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,n,r){let a={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!a)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,a,r)}async createChangeSet(e){let n={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[a,s]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=a,n[`Parameters.member.${i+1}.ParameterValue`]=s;if(e.capabilities)for(let[i,a]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=a;return(await this.request("CreateChangeSet",n)).ChangeSetId}async executeChangeSet(e,n){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:n})}async describeStacks(e){let n=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(n)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,a=Array.isArray(i)?i[0]:i;if(!a)return{};let s={},c=a.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)s[d.OutputKey]=d.OutputValue}return s}}function Et(e,n=""){let r={};for(let[i,a]of Object.entries(e)){let s=n?`${n}.${i}`:i;if(Array.isArray(a))a.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Et(c,`${s}.${u+1}`));else r[`${s}.${u+1}`]=String(c)});else if(typeof a==="object"&&a!==null)Object.assign(r,Et(a,s));else if(a!==void 0&&a!==null)r[s]=String(a)}return r}function vi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(a,s,c){let u=1,d=c,m=`<${s}`,p=`</${s}>`;while(d<a.length&&u>0){let g=a.indexOf(m,d),y=a.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=a[g+m.length];if(f===">"||f===" "||f==="/"){let h=a.indexOf(">",g);if(h!==-1&&a[h-1]==="/")d=h+1;else u++,d=h+1}else d=g+m.length}else{if(u--,u===0)return y;d=y+p.length}}return-1}function r(a,s){while(s<a.length&&/\s/.test(a[s]))s++;if(s>=a.length||a[s]!=="<"){let S=a.indexOf("<",s);if(S===-1)return{value:a.slice(s).trim(),end:a.length};return{value:a.slice(s,S).trim(),end:S}}if(a[s+1]==="/")return{value:void 0,end:s};let c=a.slice(s).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:s+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:s+c[0].length};let m=s+c[0].length,p=`</${u}>`,g=n(a,u,m);if(g===-1)return{value:void 0,end:s+c[0].length};let y=a.slice(m,g).trim();if(!y.includes("<"))return{value:y,end:g+p.length};let f={},h=m;while(h<g){while(h<g&&/\s/.test(a[h]))h++;if(h>=g)break;if(a[h]!=="<"||a[h+1]==="/")break;let S=a.slice(h).match(/^<(\w+)/);if(!S)break;let C=S[1],P=r(a,h);if(P.value===void 0){h++;continue}if(C==="member"||f[C]!==void 0){if(!Array.isArray(f[C]))f[C]=f[C]!==void 0?[f[C]]:[];f[C].push(P.value)}else f[C]=P.value;h=P.end}return{value:f,end:g+p.length}}return r(e,0).value||{}}function Ti(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Ri(e){let r=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((a)=>({StackName:a.StackName||"",StackId:a.StackId,StackStatus:a.StackStatus,CreationTime:a.CreationTime,LastUpdatedTime:a.LastUpdatedTime,StackStatusReason:a.StackStatusReason,Description:a.Description}))}function Pi(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((a)=>({StackId:a.StackId||"",EventId:a.EventId||"",StackName:a.StackName||"",LogicalResourceId:a.LogicalResourceId||"",PhysicalResourceId:a.PhysicalResourceId,ResourceType:a.ResourceType||"",Timestamp:a.Timestamp||"",ResourceStatus:a.ResourceStatus||"",ResourceStatusReason:a.ResourceStatusReason}))}var Ei=5242880,wt=5242880;var wi=5242880;class Aa{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(e={}){this.region=e.region||process.env.AWS_REGION||"us-east-1",this.endpoint=e.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=e.forcePathStyle||!1,this.credentials=e.credentials,this.credentialOptions=e.credentialOptions,this.retryOptions=e.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return Vi(this.credentialOptions)}buildUrl(e,n){let r=n?encodeURIComponent(n).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return n?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let i=new URL(this.endpoint);return i.hostname=`${e}.${i.hostname}`,n?`${i.origin}/${r}`:i.origin}async get(e,n,r={}){let i=await this.getCredentials(),a=this.buildUrl(e,n),s={};if(r.range)s.Range=r.range;if(r.ifModifiedSince)s["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)s["If-Match"]=r.ifMatch;if(r.ifNoneMatch)s["If-None-Match"]=r.ifNoneMatch;let c=new URL(a);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=Y({method:"GET",url:c.toString(),headers:s,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new be(`Failed to get object: ${m}`,d.status,e,n)}return d}async getText(e,n,r={}){return(await this.get(e,n,r)).text()}async getJSON(e,n,r={}){return(await this.get(e,n,r)).json()}async getBuffer(e,n,r={}){return(await this.get(e,n,r)).arrayBuffer()}async put(e,n,r,i={}){let a,s;if(typeof r==="string")a=new TextEncoder().encode(r).length,s=r;else if(r instanceof ArrayBuffer)a=r.byteLength,s=r;else if(r instanceof Uint8Array)a=r.byteLength,s=r;else if(r instanceof Blob)a=r.size,s=r;else return this.uploadMultipart(e,n,r,{...i,partSize:wt});if(a>wi){let c=Ni(s).stream();return this.uploadMultipart(e,n,c,{...i,partSize:wt})}return this.putSimple(e,n,s,a,i)}async putSimple(e,n,r,i,a){let s=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":a.contentType||Vn(n)};if(a.contentEncoding)u["Content-Encoding"]=a.contentEncoding;if(a.cacheControl)u["Cache-Control"]=a.cacheControl;if(a.contentDisposition)u["Content-Disposition"]=a.contentDisposition;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.serverSideEncryption)u["x-amz-server-side-encryption"]=a.serverSideEncryption;if(a.acl)u["x-amz-acl"]=a.acl;if(a.tagging)u["x-amz-tagging"]=a.tagging;if(a.metadata)for(let[y,f]of Object.entries(a.metadata))u[`x-amz-meta-${y.toLowerCase()}`]=f;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=Y({method:"PUT",url:c,headers:u,body:d,...s,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let y=await p.text();throw new be(`Failed to put object: ${y}`,p.status,e,n)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),a=Y({method:"DELETE",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok&&s.status!==204){let c=await s.text();throw new be(`Failed to delete object: ${c}`,s.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,s=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${Di(h)}</Key></Object>`).join("")}</Delete>`,c=Y({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:s,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:s});if(!u.ok){let h=await u.text();throw new be(`Failed to delete objects: ${h}`,u.status,e)}let d=await u.text(),m=[],p=[],g=/<Deleted><Key>([^<]+)<\/Key>/g,y;while((y=g.exec(d))!==null)m.push(y[1]);let f=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((y=f.exec(d))!==null)p.push({key:y[1],error:`${y[2]}: ${y[3]}`});return{deleted:m,errors:p}}async list(e,n={}){let r=await this.getCredentials(),i=new URL(this.buildUrl(e));if(i.searchParams.set("list-type","2"),n.prefix)i.searchParams.set("prefix",n.prefix);if(n.delimiter)i.searchParams.set("delimiter",n.delimiter);if(n.maxKeys)i.searchParams.set("max-keys",String(n.maxKeys));if(n.continuationToken)i.searchParams.set("continuation-token",n.continuationToken);if(n.startAfter)i.searchParams.set("start-after",n.startAfter);let a=Y({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok){let u=await s.text();throw new be(`Failed to list objects: ${u}`,s.status,e)}let c=await s.text();return Ii(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let a of i.contents)yield a;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),a=Y({method:"HEAD",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(s.status===404)return null;if(!s.ok){let u=await s.text();throw new be(`Failed to head object: ${u}`,s.status,e,n)}let c={};return s.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(s.headers.get("Content-Length")||0),contentType:s.headers.get("Content-Type")||"application/octet-stream",etag:(s.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(s.headers.get("Last-Modified")||0),metadata:c,storageClass:s.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:s.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,n){return await this.head(e,n)!==null}async copy(e,n,r,i,a={}){let s=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(a.metadataDirective)u["x-amz-metadata-directive"]=a.metadataDirective;if(a.contentType)u["Content-Type"]=a.contentType;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.acl)u["x-amz-acl"]=a.acl;if(a.metadata)for(let[f,h]of Object.entries(a.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=Y({method:"PUT",url:c,headers:u,...s,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let f=await m.text();throw new be(`Failed to copy object: ${f}`,m.status,r,i)}let g=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:g?g[1]:""}}async getPresignedUrl(e,n,r={}){let i=await this.getCredentials(),a=this.buildUrl(e,n);return is({url:a,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let a=await this.getCredentials(),s=Math.max(i.partSize||wt,Ei),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,n,i);try{let p=await this.uploadParts(e,n,m,d,c,s,a,u,i.concurrency||4,i.onProgress);return await this.completeMultipartUpload(e,n,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,n,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,n,r){let i=await this.getCredentials(),a=this.buildUrl(e,n),s=`${a}?uploads`,c={"Content-Type":r.contentType||Vn(n)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[y,f]of Object.entries(r.metadata))c[`x-amz-meta-${y.toLowerCase()}`]=f;let u=Y({method:"POST",url:s,headers:c,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let y=await d.text();throw new be(`Failed to initiate multipart upload: ${y}`,d.status,e,n)}let p=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!p)throw new be("Failed to parse upload ID from response",0,e,n);let g=a;if(d.url)try{let y=new URL(d.url);y.search="",g=y.toString()}catch{}return{uploadId:p[1],baseUrl:g}}async uploadParts(e,n,r,i,a,s,c,u,d,m){let p=[],g=a.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/s):void 0,C=new Map,P=async(v,I)=>{let D=`${r}?partNumber=${I}&uploadId=${encodeURIComponent(i)}`,N={"Content-Length":String(v.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},M=Y({method:"PUT",url:D,headers:N,...c,service:"s3",region:this.region}),F=await fetch(M.url,{method:M.method,headers:M.headers,body:v,redirect:"error"});if(!F.ok){let G=await F.text();throw new be(`Failed to upload part ${I}: ${G}`,F.status,e,n)}let O=(F.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new be(`Missing ETag for part ${I}`,F.status,e,n);return{partNumber:I,etag:O}},E=async()=>{let v=await Promise.race(C.values());C.delete(v.partNumber),p.push(v)};while(!0){let{done:v,value:I}=await g.read();if(I){let D=new Uint8Array(f.length+I.length);D.set(f),D.set(I,f.length),f=D}while(f.length>=s||v&&f.length>0){let D=f.slice(0,s);f=f.slice(s);let N=y++;if(C.size>=d)await E();if(C.set(N,P(D,N)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:N,totalParts:S||N})}if(v)break}while(C.size>0)await E();return p.sort((v,I)=>v.partNumber-I.partNumber),p}async completeMultipartUpload(e,n,r,i,a){let s=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${a.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=Y({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...s,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:d});if(!p.ok){let h=await p.text();throw new be(`Failed to complete multipart upload: ${h}`,p.status,e,n)}let y=(await p.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:y?y[1]:""}}async abortMultipartUpload(e,n,r,i){let a=await this.getCredentials(),s=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=Y({method:"DELETE",url:s,...a,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let r=[];for await(let c of this.listAll(e,{}))if(r.push(c.key),r.length>=1000)await this.deleteMany(e,r),r=[];if(r.length>0)await this.deleteMany(e,r);let i=await this.getCredentials(),a=this.buildUrl(e),s=Y({method:"DELETE",url:a,...i,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.headers})}}class be extends Error{statusCode;bucket;key;constructor(e,n,r,i){super(e);this.statusCode=n;this.bucket=r;this.key=i;this.name="S3Error"}}function Ii(e){let n=[],r=[],i=/<Contents>([\s\S]*?)<\/Contents>/g,a;while((a=i.exec(e))!==null){let c=a[1];n.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let s=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((a=s.exec(e))!==null)r.push(a[1]);return{contents:n,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,n){let r=new RegExp(`<${n}>([^<]*)</${n}>`),i=e.match(r);return i?i[1]:null}function Di(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function Vn(e){let n=e.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[n||""]||"application/octet-stream"}function Ni(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function wu(e){return new Aa(e)}class Au{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Rn(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let n=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,i=`<?xml version="1.0" encoding="UTF-8"?>
2461
+ Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,n,r){let a={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!a)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,a,r)}async createChangeSet(e){let n={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[a,s]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=a,n[`Parameters.member.${i+1}.ParameterValue`]=s;if(e.capabilities)for(let[i,a]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=a;return(await this.request("CreateChangeSet",n)).ChangeSetId}async executeChangeSet(e,n){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:n})}async describeStacks(e){let n=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(n)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,a=Array.isArray(i)?i[0]:i;if(!a)return{};let s={},c=a.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)s[d.OutputKey]=d.OutputValue}return s}}function Et(e,n=""){let r={};for(let[i,a]of Object.entries(e)){let s=n?`${n}.${i}`:i;if(Array.isArray(a))a.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Et(c,`${s}.${u+1}`));else r[`${s}.${u+1}`]=String(c)});else if(typeof a==="object"&&a!==null)Object.assign(r,Et(a,s));else if(a!==void 0&&a!==null)r[s]=String(a)}return r}function vi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(a,s,c){let u=1,d=c,m=`<${s}`,p=`</${s}>`;while(d<a.length&&u>0){let g=a.indexOf(m,d),y=a.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=a[g+m.length];if(f===">"||f===" "||f==="/"){let h=a.indexOf(">",g);if(h!==-1&&a[h-1]==="/")d=h+1;else u++,d=h+1}else d=g+m.length}else{if(u--,u===0)return y;d=y+p.length}}return-1}function r(a,s){while(s<a.length&&/\s/.test(a[s]))s++;if(s>=a.length||a[s]!=="<"){let S=a.indexOf("<",s);if(S===-1)return{value:a.slice(s).trim(),end:a.length};return{value:a.slice(s,S).trim(),end:S}}if(a[s+1]==="/")return{value:void 0,end:s};let c=a.slice(s).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:s+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:s+c[0].length};let m=s+c[0].length,p=`</${u}>`,g=n(a,u,m);if(g===-1)return{value:void 0,end:s+c[0].length};let y=a.slice(m,g).trim();if(!y.includes("<"))return{value:y,end:g+p.length};let f={},h=m;while(h<g){while(h<g&&/\s/.test(a[h]))h++;if(h>=g)break;if(a[h]!=="<"||a[h+1]==="/")break;let S=a.slice(h).match(/^<(\w+)/);if(!S)break;let C=S[1],E=r(a,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((a)=>({StackName:a.StackName||"",StackId:a.StackId,StackStatus:a.StackStatus,CreationTime:a.CreationTime,LastUpdatedTime:a.LastUpdatedTime,StackStatusReason:a.StackStatusReason,Description:a.Description}))}function Pi(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((a)=>({StackId:a.StackId||"",EventId:a.EventId||"",StackName:a.StackName||"",LogicalResourceId:a.LogicalResourceId||"",PhysicalResourceId:a.PhysicalResourceId,ResourceType:a.ResourceType||"",Timestamp:a.Timestamp||"",ResourceStatus:a.ResourceStatus||"",ResourceStatusReason:a.ResourceStatusReason}))}var Ei=5242880,wt=5242880;var wi=5242880;class Aa{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(e={}){this.region=e.region||process.env.AWS_REGION||"us-east-1",this.endpoint=e.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=e.forcePathStyle||!1,this.credentials=e.credentials,this.credentialOptions=e.credentialOptions,this.retryOptions=e.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return Vi(this.credentialOptions)}buildUrl(e,n){let r=n?encodeURIComponent(n).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return n?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let i=new URL(this.endpoint);return i.hostname=`${e}.${i.hostname}`,n?`${i.origin}/${r}`:i.origin}async get(e,n,r={}){let i=await this.getCredentials(),a=this.buildUrl(e,n),s={};if(r.range)s.Range=r.range;if(r.ifModifiedSince)s["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)s["If-Match"]=r.ifMatch;if(r.ifNoneMatch)s["If-None-Match"]=r.ifNoneMatch;let c=new URL(a);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=Y({method:"GET",url:c.toString(),headers:s,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new be(`Failed to get object: ${m}`,d.status,e,n)}return d}async getText(e,n,r={}){return(await this.get(e,n,r)).text()}async getJSON(e,n,r={}){return(await this.get(e,n,r)).json()}async getBuffer(e,n,r={}){return(await this.get(e,n,r)).arrayBuffer()}async put(e,n,r,i={}){let a,s;if(typeof r==="string")a=new TextEncoder().encode(r).length,s=r;else if(r instanceof ArrayBuffer)a=r.byteLength,s=r;else if(r instanceof Uint8Array)a=r.byteLength,s=r;else if(r instanceof Blob)a=r.size,s=r;else return this.uploadMultipart(e,n,r,{...i,partSize:wt});if(a>wi){let c=Ni(s).stream();return this.uploadMultipart(e,n,c,{...i,partSize:wt})}return this.putSimple(e,n,s,a,i)}async putSimple(e,n,r,i,a){let s=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":a.contentType||Vn(n)};if(a.contentEncoding)u["Content-Encoding"]=a.contentEncoding;if(a.cacheControl)u["Cache-Control"]=a.cacheControl;if(a.contentDisposition)u["Content-Disposition"]=a.contentDisposition;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.serverSideEncryption)u["x-amz-server-side-encryption"]=a.serverSideEncryption;if(a.acl)u["x-amz-acl"]=a.acl;if(a.tagging)u["x-amz-tagging"]=a.tagging;if(a.metadata)for(let[y,f]of Object.entries(a.metadata))u[`x-amz-meta-${y.toLowerCase()}`]=f;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=Y({method:"PUT",url:c,headers:u,body:d,...s,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let y=await p.text();throw new be(`Failed to put object: ${y}`,p.status,e,n)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),a=Y({method:"DELETE",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok&&s.status!==204){let c=await s.text();throw new be(`Failed to delete object: ${c}`,s.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,s=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${Di(h)}</Key></Object>`).join("")}</Delete>`,c=Y({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:s,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:s});if(!u.ok){let h=await u.text();throw new be(`Failed to delete objects: ${h}`,u.status,e)}let d=await u.text(),m=[],p=[],g=/<Deleted><Key>([^<]+)<\/Key>/g,y;while((y=g.exec(d))!==null)m.push(y[1]);let f=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((y=f.exec(d))!==null)p.push({key:y[1],error:`${y[2]}: ${y[3]}`});return{deleted:m,errors:p}}async list(e,n={}){let r=await this.getCredentials(),i=new URL(this.buildUrl(e));if(i.searchParams.set("list-type","2"),n.prefix)i.searchParams.set("prefix",n.prefix);if(n.delimiter)i.searchParams.set("delimiter",n.delimiter);if(n.maxKeys)i.searchParams.set("max-keys",String(n.maxKeys));if(n.continuationToken)i.searchParams.set("continuation-token",n.continuationToken);if(n.startAfter)i.searchParams.set("start-after",n.startAfter);let a=Y({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok){let u=await s.text();throw new be(`Failed to list objects: ${u}`,s.status,e)}let c=await s.text();return Ii(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let a of i.contents)yield a;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),a=Y({method:"HEAD",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(s.status===404)return null;if(!s.ok){let u=await s.text();throw new be(`Failed to head object: ${u}`,s.status,e,n)}let c={};return s.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(s.headers.get("Content-Length")||0),contentType:s.headers.get("Content-Type")||"application/octet-stream",etag:(s.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(s.headers.get("Last-Modified")||0),metadata:c,storageClass:s.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:s.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,n){return await this.head(e,n)!==null}async copy(e,n,r,i,a={}){let s=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(a.metadataDirective)u["x-amz-metadata-directive"]=a.metadataDirective;if(a.contentType)u["Content-Type"]=a.contentType;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.acl)u["x-amz-acl"]=a.acl;if(a.metadata)for(let[f,h]of Object.entries(a.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=Y({method:"PUT",url:c,headers:u,...s,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let f=await m.text();throw new be(`Failed to copy object: ${f}`,m.status,r,i)}let g=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:g?g[1]:""}}async getPresignedUrl(e,n,r={}){let i=await this.getCredentials(),a=this.buildUrl(e,n);return is({url:a,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let a=await this.getCredentials(),s=Math.max(i.partSize||wt,Ei),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,n,i);try{let p=await this.uploadParts(e,n,m,d,c,s,a,u,i.concurrency||4,i.onProgress);return await this.completeMultipartUpload(e,n,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,n,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,n,r){let i=await this.getCredentials(),a=this.buildUrl(e,n),s=`${a}?uploads`,c={"Content-Type":r.contentType||Vn(n)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[y,f]of Object.entries(r.metadata))c[`x-amz-meta-${y.toLowerCase()}`]=f;let u=Y({method:"POST",url:s,headers:c,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let y=await d.text();throw new be(`Failed to initiate multipart upload: ${y}`,d.status,e,n)}let p=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!p)throw new be("Failed to parse upload ID from response",0,e,n);let g=a;if(d.url)try{let y=new URL(d.url);y.search="",g=y.toString()}catch{}return{uploadId:p[1],baseUrl:g}}async uploadParts(e,n,r,i,a,s,c,u,d,m){let p=[],g=a.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/s):void 0,C=new Map,E=async(v,I)=>{let D=`${r}?partNumber=${I}&uploadId=${encodeURIComponent(i)}`,N={"Content-Length":String(v.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},M=Y({method:"PUT",url:D,headers:N,...c,service:"s3",region:this.region}),F=await fetch(M.url,{method:M.method,headers:M.headers,body:v,redirect:"error"});if(!F.ok){let G=await F.text();throw new be(`Failed to upload part ${I}: ${G}`,F.status,e,n)}let O=(F.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new be(`Missing ETag for part ${I}`,F.status,e,n);return{partNumber:I,etag:O}},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>=s||v&&f.length>0){let D=f.slice(0,s);f=f.slice(s);let N=y++;if(C.size>=d)await w();if(C.set(N,E(D,N)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:N,totalParts:S||N})}if(v)break}while(C.size>0)await w();return p.sort((v,I)=>v.partNumber-I.partNumber),p}async completeMultipartUpload(e,n,r,i,a){let s=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${a.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=Y({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...s,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:d});if(!p.ok){let h=await p.text();throw new be(`Failed to complete multipart upload: ${h}`,p.status,e,n)}let y=(await p.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:y?y[1]:""}}async abortMultipartUpload(e,n,r,i){let a=await this.getCredentials(),s=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=Y({method:"DELETE",url:s,...a,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let r=[];for await(let c of this.listAll(e,{}))if(r.push(c.key),r.length>=1000)await this.deleteMany(e,r),r=[];if(r.length>0)await this.deleteMany(e,r);let i=await this.getCredentials(),a=this.buildUrl(e),s=Y({method:"DELETE",url:a,...i,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.headers})}}class be extends Error{statusCode;bucket;key;constructor(e,n,r,i){super(e);this.statusCode=n;this.bucket=r;this.key=i;this.name="S3Error"}}function Ii(e){let n=[],r=[],i=/<Contents>([\s\S]*?)<\/Contents>/g,a;while((a=i.exec(e))!==null){let c=a[1];n.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let s=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((a=s.exec(e))!==null)r.push(a[1]);return{contents:n,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,n){let r=new RegExp(`<${n}>([^<]*)</${n}>`),i=e.match(r);return i?i[1]:null}function Di(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function Vn(e){let n=e.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[n||""]||"application/octet-stream"}function Ni(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function wu(e){return new Aa(e)}class Au{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Rn(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let n=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,i=`<?xml version="1.0" encoding="UTF-8"?>
2462
2462
  <InvalidationBatch>
2463
2463
  <Paths>
2464
2464
  <Quantity>${e.paths.length}</Quantity>
@@ -3748,7 +3748,7 @@ Scanning image: ${r}`),console.log(`Scanner: ${n.scanner}`);let i=`scan-result-$
3748
3748
  Scan Results:`),console.log(` Total vulnerabilities: ${s.total}`),console.log(` Critical: ${s.critical}`),console.log(` High: ${s.high}`),console.log(` Medium: ${s.medium}`),console.log(` Low: ${s.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 jf=new Ul;class Fl{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[a,s]of Object.entries(i.env))r.push(`ENV ${a}=${s}`);for(let a of i.commands)r.push(a);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)})),a=i.reduce((u,d)=>u+d.size,0),s=i.filter((u)=>!u.cacheable&&u.size>100).length,c={id:r,imageId:e,layers:i,totalSize:a,unnecessaryLayers:s};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=[],a=n.layers.filter((m)=>m.command.startsWith("RUN"));if(a.length>5)i.push({type:"layer_reduction",priority:"high",title:"Combine RUN commands",description:`${a.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 s=n.layers[0];if(s.command.includes("ubuntu")||s.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 Vf=new Fl;class za{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 up=new za;class Ha{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 pp=new Ha;class Bl{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,a={id:r,layerName:n.layerName,version:i,createdAt:new Date,compatibleRuntimes:n.compatibleRuntimes,size:n.size,codeHash:this.generateHash()};return this.versions.set(r,a),n.version=i,n.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${i}`,a}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 zf=new Bl;class jl{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((a)=>a.functionName===e.functionName&&a.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 Hf=new jl;class Vl{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 Vl;class zl{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((s)=>s.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++}`,a={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,a),a}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 Gf=new zl;class Hl{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),a=[],s=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!s&&!c)a.push("Add NAT Gateway for internet access");if(!i.includes("com.amazonaws.us-east-1.s3"))a.push("Add S3 VPC endpoint to reduce NAT costs");if(!i.includes("com.amazonaws.us-east-1.dynamodb"))a.push("Add DynamoDB VPC endpoint for private access");let u={id:n,functionName:e.functionName,hasInternetAccess:s||c,hasNATGateway:s,hasVPCEndpoints:i.length>0,endpoints:i,recommendations:a};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 Wf=new Hl;class ql{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let n=`dlq-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.dlqConfigs.set(n,r),r}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let n=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:n.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),n}sendToDLQ(e){let n=`message-${Date.now()}-${this.messageCounter++}`,r={id:n,timestamp:new Date,...e};return this.messages.set(n,r),r}createDLQAlarm(e){let n=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:n,...e};return this.alarms.set(n,r),r}createAgeAlarm(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${n.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let n=this.messages.get(e);if(!n)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((s)=>s.functionName===n.functionName);if(!r)throw Error(`DLQ config not found for function: ${n.functionName}`);let i=`reprocess-${Date.now()}-${this.reprocessCounter++}`,a={id:i,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(i,a),setTimeout(()=>{a.status="processing",setTimeout(()=>{let s=Math.random()>0.3;if(a.status=s?"success":"failed",a.completedAt=new Date,!s)a.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),a}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((a)=>a.functionName===n.functionName).slice(0,e.maxMessages||10).map((a)=>this.reprocessMessage(a.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={},a=0;for(let c of r)i[c.errorType]=(i[c.errorType]||0)+1,a+=c.attemptCount;let s=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:s.length>0?new Date(Math.min(...s.map((c)=>c.getTime()))):void 0,newestMessage:s.length>0?new Date(Math.max(...s.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?a/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 Kf=new ql;class qa{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 a=e.childHealthChecks.filter((s)=>this.healthChecks.get(s)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=a>=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,a)=>{let s=`endpoint${a}`;n[s]={type:"value",value:i.endpoint},r.push({endpointReference:s,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 mp=new qa;class Gl{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,a=r&&i,s=[];if(!r)s.push("DNSKEY record not found");if(!i)s.push("RRSIG record not found");let c;if(!r&&!i)c="INSECURE";else if(r&&i&&a)c="VALID";else if(r||i)c="BOGUS",s.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:n,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:i,validSignature:a,errors:s};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 Jf=new Gl;class Wl{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,a)=>({id:`rule-${n}-${a}`,...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,a)=>({id:`assoc-${n}-${a}`,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 Xf=new Wl;class Kl{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,a=r.filter((p)=>p.bounceType==="Permanent").length,s=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:a,transientBounces:s,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,a=new Set;for(let d of r)for(let m of d.recipients)a.add(m);let s=a.size,c=i*1000,u=i/c*100;return{totalComplaints:i,uniqueComplainters:s,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,n=new Date,r=new Date(n.getTime()-86400000),i=this.getBounceStatistics(r,n),a=this.getComplaintStatistics(r,n),s;if(i.bounceRate>10||a.complaintRate>0.5)s="Shutdown";else if(i.bounceRate>5||a.complaintRate>0.1)s="Probation";else if(i.bounceRate>2||a.complaintRate>0.05)s="Warning";else s="Good";let c={id:e,timestamp:n,bounceRate:i.bounceRate,complaintRate:a.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:i.totalBounces*10,reputationStatus:s};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 Qf=new Kl;class Jl{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,a=r.filter((v)=>v.eventType==="delivery").length,s=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?a/i*100:0,p=a>0?s/a*100:0,g=a>0?c/a*100:0,y=s>0?c/s*100:0,f=i>0?u/i*100:0,h=a>0?d/a*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),P={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"))P.mobile++;else if(I.includes("tablet"))P.tablet++;else if(I.includes("mozilla"))P.desktop++;else P.unknown++}let E={id:n,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:i,totalDelivered:a,totalOpened:s,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,a)=>({id:`variant-${n}-${a}`,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 a of n.variants){let s=a.sentCount>0?a.openCount/a.sentCount:0;if(s>i)i=s,r=a}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 Yf=new Jl;class Xl{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),a=Math.max(0,100-n*10-r*100-i*2),s=[];if(n>2)s.push("Reduce bounce rate by cleaning email list");if(r>0.1)s.push("Review email content and unsubscribe process");if(i>5)s.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:a,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:s};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 s=0;s<e.durationDays;s++)r.push(Math.floor(e.initialDailyLimit+i*s));let a={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,a),a}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,a=e.delivered>0?e.clicked/e.delivered*100:0,s=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=i*0.4+a*0.6,d=Math.max(0,100-s*10-c*100+u*0.2),m={id:n,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:i,clickRate:a,bounceRate:s,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 Zf=new Xl;class Ql{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 Vf=new Fl;class za{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 up=new za;class Ha{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 pp=new Ha;class Bl{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,a={id:r,layerName:n.layerName,version:i,createdAt:new Date,compatibleRuntimes:n.compatibleRuntimes,size:n.size,codeHash:this.generateHash()};return this.versions.set(r,a),n.version=i,n.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${i}`,a}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 zf=new Bl;class jl{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((a)=>a.functionName===e.functionName&&a.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 Hf=new jl;class Vl{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 Vl;class zl{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((s)=>s.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++}`,a={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,a),a}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 Gf=new zl;class Hl{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),a=[],s=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!s&&!c)a.push("Add NAT Gateway for internet access");if(!i.includes("com.amazonaws.us-east-1.s3"))a.push("Add S3 VPC endpoint to reduce NAT costs");if(!i.includes("com.amazonaws.us-east-1.dynamodb"))a.push("Add DynamoDB VPC endpoint for private access");let u={id:n,functionName:e.functionName,hasInternetAccess:s||c,hasNATGateway:s,hasVPCEndpoints:i.length>0,endpoints:i,recommendations:a};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 Wf=new Hl;class ql{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let n=`dlq-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.dlqConfigs.set(n,r),r}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let n=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:n.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),n}sendToDLQ(e){let n=`message-${Date.now()}-${this.messageCounter++}`,r={id:n,timestamp:new Date,...e};return this.messages.set(n,r),r}createDLQAlarm(e){let n=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:n,...e};return this.alarms.set(n,r),r}createAgeAlarm(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${n.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let n=this.messages.get(e);if(!n)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((s)=>s.functionName===n.functionName);if(!r)throw Error(`DLQ config not found for function: ${n.functionName}`);let i=`reprocess-${Date.now()}-${this.reprocessCounter++}`,a={id:i,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(i,a),setTimeout(()=>{a.status="processing",setTimeout(()=>{let s=Math.random()>0.3;if(a.status=s?"success":"failed",a.completedAt=new Date,!s)a.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),a}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((a)=>a.functionName===n.functionName).slice(0,e.maxMessages||10).map((a)=>this.reprocessMessage(a.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={},a=0;for(let c of r)i[c.errorType]=(i[c.errorType]||0)+1,a+=c.attemptCount;let s=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:s.length>0?new Date(Math.min(...s.map((c)=>c.getTime()))):void 0,newestMessage:s.length>0?new Date(Math.max(...s.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?a/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 Kf=new ql;class qa{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 a=e.childHealthChecks.filter((s)=>this.healthChecks.get(s)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=a>=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,a)=>{let s=`endpoint${a}`;n[s]={type:"value",value:i.endpoint},r.push({endpointReference:s,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 mp=new qa;class Gl{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,a=r&&i,s=[];if(!r)s.push("DNSKEY record not found");if(!i)s.push("RRSIG record not found");let c;if(!r&&!i)c="INSECURE";else if(r&&i&&a)c="VALID";else if(r||i)c="BOGUS",s.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:n,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:i,validSignature:a,errors:s};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 Jf=new Gl;class Wl{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,a)=>({id:`rule-${n}-${a}`,...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,a)=>({id:`assoc-${n}-${a}`,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 Xf=new Wl;class Kl{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,a=r.filter((p)=>p.bounceType==="Permanent").length,s=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:a,transientBounces:s,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,a=new Set;for(let d of r)for(let m of d.recipients)a.add(m);let s=a.size,c=i*1000,u=i/c*100;return{totalComplaints:i,uniqueComplainters:s,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,n=new Date,r=new Date(n.getTime()-86400000),i=this.getBounceStatistics(r,n),a=this.getComplaintStatistics(r,n),s;if(i.bounceRate>10||a.complaintRate>0.5)s="Shutdown";else if(i.bounceRate>5||a.complaintRate>0.1)s="Probation";else if(i.bounceRate>2||a.complaintRate>0.05)s="Warning";else s="Good";let c={id:e,timestamp:n,bounceRate:i.bounceRate,complaintRate:a.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:i.totalBounces*10,reputationStatus:s};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 Qf=new Kl;class Jl{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,a=r.filter((v)=>v.eventType==="delivery").length,s=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?a/i*100:0,p=a>0?s/a*100:0,g=a>0?c/a*100:0,y=s>0?c/s*100:0,f=i>0?u/i*100:0,h=a>0?d/a*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:a,totalOpened:s,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,a)=>({id:`variant-${n}-${a}`,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 a of n.variants){let s=a.sentCount>0?a.openCount/a.sentCount:0;if(s>i)i=s,r=a}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 Yf=new Jl;class Xl{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),a=Math.max(0,100-n*10-r*100-i*2),s=[];if(n>2)s.push("Reduce bounce rate by cleaning email list");if(r>0.1)s.push("Review email content and unsubscribe process");if(i>5)s.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:a,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:s};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 s=0;s<e.durationDays;s++)r.push(Math.floor(e.initialDailyLimit+i*s));let a={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,a),a}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,a=e.delivered>0?e.clicked/e.delivered*100:0,s=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=i*0.4+a*0.6,d=Math.max(0,100-s*10-c*100+u*0.2),m={id:n,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:i,clickRate:a,bounceRate:s,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 Zf=new Xl;class Ql{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 cs}from"node:child_process";import{createHash as ls}from"node:crypto";import{cpSync as us,mkdtempSync as ds,rmSync as ms,writeFileSync as ps}from"node:fs";import{tmpdir as gs}from"node:os";import{dirname as ys,isAbsolute as fs,join as xe,resolve as hs}from"node:path";import{fileURLToPath as bs}from"node:url";var Ss=["adapter.ts","recursion.ts","auto-recursion.ts"];function As(){return xe(ys(bs(import.meta.url)),"runtime")}function gp(e,n,r){for(let i of e??[])r?.(`build: ${i}`),cs(i,{stdio:"inherit",cwd:n})}function es(e){return ls("sha256").update(e).digest("hex")}function Ga(e,n,r){return`deployments/${e}/${n}/${r}.zip`}async function In(e){let n=hs(e.projectRoot??process.cwd()),{app:r}=e;if(!e.skipBuild)gp(r.build,n,e.onStep);let i=r.entry;if(!i)throw Error("serverless app: `entry` is required to package a Node/Bun application");let a=fs(i)?i:xe(n,i),s=ds(xe(gs(),"tscloud-pkg-"));try{for(let y of Ss)us(xe(As(),y),xe(s,y));let c=xe(s,"bootstrap.ts");ps(c,sd({entryImport:a,adapterImport:"./adapter"})),e.onStep?.("bundling application");let u=await Bun.build({entrypoints:[c],target:r.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!u.success){let y=u.logs.map((f)=>String(f)).join(`
7250
7250
  `);throw Error(`serverless app bundle failed:
7251
- ${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Dt([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:es(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{ms(s,{recursive:!0,force:!0})}}var fp=["18","20","22"];function Cs(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function qi(e){let n=e.kind??"node";if(n==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(n==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=Cs(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&fp.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function Qt(e,n,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${n}-${r}-default`}];return e.queues.map((i)=>{if(typeof i==="string")return{name:`${n}-${r}-${i}`};let[a,s]=Object.entries(i)[0];return{name:`${n}-${r}-${a}`,concurrency:s}})}function Wa(e,n,r){return Qt(e,n,r).map((i)=>i.name)}function Ka(e){let{app:n,environment:r,handlers:i}=e,a=e.config.project.slug,s=qi(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${a}-${r}-http`,queue:`${a}-${r}-queue`,cli:`${a}-${r}-cli`};if(n.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let m=Qt(n,a,r),p=m.map((x)=>x.name),g=p.length>0,y=n.logRetention??14,f=n.packaging==="image";if(f&&n.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let h=(n.scheduler??"on")!=="off",S=(n.cache?.driver??"dynamodb")==="dynamodb",C=Boolean(n.assets),P=Li(a,r),E=n.tmpStorage??512,v={},I={},D=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:t.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${a}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${a}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${a}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${P}`),t.sub(`arn:aws:s3:::${P}/*`),...n.storage?.bucket?[t.sub(`arn:aws:s3:::${n.storage.bucket}`),t.sub(`arn:aws:s3:::${n.storage.bucket}/*`)]:[]]}]}}];if(g)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${a}-${r}-*`)});if(S)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${a}-${r}-cache*`)});let N=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)N.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)N.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");v.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${a}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:N,Policies:D}};let M=(x)=>({TSCLOUD_LAMBDA_MODE:x,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${a}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),F=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},G=O.mountPath??"/mnt/local",U=F&&!O.accessPointArn,ce=O.accessPointArn??(U?t.getAtt("EfsAccessPoint","Arn"):void 0),q=n.vpc?.subnets??[],J=q.length>0,K=n.cache?.driver==="elasticache"||n.database?.connection==="aurora-serverless"||Boolean(n.rdsProxy)||F;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Q=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ge=U?q.map((x,_)=>`EfsMountTarget${_}`):[],Te=F?{FileSystemConfigs:[{Arn:ce,LocalMountPath:G}]}:{};if(F)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function te(x,_,V,W,ee,mt,Be,he=E){v[`${x}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${_}`,RetentionInDays:y}};let Fe=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],rn=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[V]}}}:{Runtime:s,Handler:V,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Fe.length?{Layers:[...new Set(Fe)]}:{}};v[x]={Type:"AWS::Lambda::Function",DependsOn:[`${x}LogGroup`,...ge],Properties:{FunctionName:_,Architectures:[c],MemorySize:ee,Timeout:mt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:M(W)},EphemeralStorage:{Size:he},...rn,...Be!==void 0?{ReservedConcurrentExecutions:Be}:{},...Q,...Te}}}if(te("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,E),te("CliFunction",d.cli,i.cli,"cli",n.cliMemory??1024,n.cliTimeout??900,void 0,n.cliTmpStorage??E),g)te("QueueFunction",d.queue,i.queue,"queue",n.queueMemory??1024,n.queueTimeout??120,void 0,n.queueTmpStorage??E);let Z=(n.provisionedConcurrency??0)>0?n.provisionedConcurrency:0,re=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(Z)for(let x of re)v[`${x}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(x)}},v[`${x}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(x),Name:"live",FunctionVersion:t.getAtt(`${x}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Z}}};let fe=(x)=>Z?t.ref(`${x}Alias`):t.getAtt(x,"Arn"),ae=(x)=>Z?t.ref(`${x}Alias`):t.ref(x);v.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${a}-${r}`,ProtocolType:"HTTP"}},v.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},v.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},v.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},v.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},I.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},I.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ue=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(ue.length){if(!n.certificateArn&&!n.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let x=n.certificateArn;if(!x)v.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ue[0],...ue.length>1?{SubjectAlternativeNames:ue.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ue.map((_)=>({DomainName:_,HostedZoneId:n.hostedZoneId}))}},x=t.ref("HttpCertificate");ue.forEach((_,V)=>{let W=`HttpDomain${V}`;if(v[W]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:_,DomainNameConfigurations:[{CertificateArn:x,EndpointType:"REGIONAL"}]}},v[`HttpApiMapping${V}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(W),Stage:"$default"}},n.hostedZoneId)v[`HttpDomainRecord${V}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:_,Type:"A",AliasTarget:{DNSName:t.getAtt(W,"RegionalDomainName"),HostedZoneId:t.getAtt(W,"RegionalHostedZoneId")}}};I[`CustomDomain${V}`]={Description:`Custom domain ${_}`,Value:_},I[`CustomDomainTarget${V}`]={Description:`Point ${_} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(W,"RegionalDomainName")}})}if(g)v.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${a}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((x,_)=>{let V=`AppQueue${_}`,W=n.queueTimeout??120;v[V]={Type:"AWS::SQS::Queue",Properties:{QueueName:x.name,VisibilityTimeout:Math.min(43200,W*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let ee=x.concurrency??n.queueConcurrency;v[`${V}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(V,"Arn"),FunctionName:ae("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ee?{ScalingConfig:{MaximumConcurrency:Math.max(2,ee)}}:{}}},I[`QueueUrl${_}`]={Description:`Queue URL: ${x.name}`,Value:t.ref(V)}});if(h)v.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},v.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(n.warm&&n.warm>0){let _={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},V=(n.warmFunctions??["http"]).filter((W)=>W!=="queue"||g);for(let W of V){let ee=W.charAt(0).toUpperCase()+W.slice(1),mt=Math.ceil(n.warm/5),Be=0;for(let he=0;he<mt;he++){let Fe=Math.min(5,n.warm-Be);v[`Warmer${ee}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-warmer-${W}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Fe},(rn,lr)=>({Id:`warm-${W}-${he}-${lr}`,Arn:t.getAtt(_[W],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Be+=Fe}v[`Warmer${ee}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(_[W]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${a}-${r}-warmer-${W}-*`)}}}}if(S)v.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},I.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(C){if(v.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:P,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},v.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${a}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},v.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...n.assetDomain?{Aliases:[n.assetDomain],ViewerCertificate:{AcmCertificateArn:n.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},n.assetDomain){if(!n.assetCertificateArn){if(!n.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(u!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);v.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)v.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};I.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}v.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${P}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},I.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},I.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(n.firewall?.enabled){let x=[],_=0;if(n.firewall.rateLimit)x.push({Name:"rate-limit",Priority:_++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-rate`}});let V={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let W of n.firewall.rules??[]){let ee=V[W];if(!ee)continue;x.push({Name:`managed-${W}`,Priority:_++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ee}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-${W}`}})}v.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${a}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:x,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-waf`}}},I.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:t.getAtt("WebAcl","Arn")}}if(J&&K){if(!n.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");v.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${a}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(U)v.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${a}-${r}-efs`}]}},q.forEach((x,_)=>{v[`EfsMountTarget${_}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:x,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),v.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},I.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")v.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${a}-${r} cache subnets`,SubnetIds:q}},v.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${a}-${r}-cache`,ReplicationGroupDescription:`${a}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},I.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")v.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${a}-${r} db subnets`,SubnetIds:q}},v.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${a}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},v.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${a}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:n.database?.minCapacity??0.5,MaxCapacity:n.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},v.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},I.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")v.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},v.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${a}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},v.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},I.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(I.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},I.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)I.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${a}-${r})`,Parameters:f?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:v,Outputs:I},Le={};for(let x of Object.values(v))Le[x.Type]=(Le[x.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Le}}var hp=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function yp(e){let n=`php${e.replace(".","")}`;return hp.map((r)=>`${n}-php-${r}`)}function Ja(e,n){let r=`php${e.replace(".","")}`,i=yp(e).join(" \\\n "),a=`/opt/remi/${r}/root`,s=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
7251
+ ${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Dt([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:es(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{ms(s,{recursive:!0,force:!0})}}var fp=["18","20","22"];function Cs(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function qi(e){let n=e.kind??"node";if(n==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(n==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=Cs(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&fp.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function Qt(e,n,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${n}-${r}-default`}];return e.queues.map((i)=>{if(typeof i==="string")return{name:`${n}-${r}-${i}`};let[a,s]=Object.entries(i)[0];return{name:`${n}-${r}-${a}`,concurrency:s}})}function Wa(e,n,r){return Qt(e,n,r).map((i)=>i.name)}function Ka(e){let{app:n,environment:r,handlers:i}=e,a=e.config.project.slug,s=qi(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${a}-${r}-http`,queue:`${a}-${r}-queue`,cli:`${a}-${r}-cli`};if(n.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let m=Qt(n,a,r),p=m.map((x)=>x.name),g=p.length>0,y=n.logRetention??14,f=n.packaging==="image";if(f&&n.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let h=(n.scheduler??"on")!=="off",S=(n.cache?.driver??"dynamodb")==="dynamodb",C=Boolean(n.assets),E=Li(a,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:${a}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${a}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${a}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${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}:${a}-${r}-*`)});if(S)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${a}-${r}-cache*`)});let N=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)N.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)N.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");v.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${a}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:N,Policies:D}};let M=(x)=>({TSCLOUD_LAMBDA_MODE:x,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${a}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),F=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},G=O.mountPath??"/mnt/local",U=F&&!O.accessPointArn,ce=O.accessPointArn??(U?t.getAtt("EfsAccessPoint","Arn"):void 0),q=n.vpc?.subnets??[],J=q.length>0,K=n.cache?.driver==="elasticache"||n.database?.connection==="aurora-serverless"||Boolean(n.rdsProxy)||F;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Q=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ge=U?q.map((x,_)=>`EfsMountTarget${_}`):[],Te=F?{FileSystemConfigs:[{Arn:ce,LocalMountPath:G}]}:{};if(F)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function te(x,_,V,W,ee,mt,Be,he=w){v[`${x}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${_}`,RetentionInDays:y}};let Fe=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],rn=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[V]}}}:{Runtime:s,Handler:V,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Fe.length?{Layers:[...new Set(Fe)]}:{}};v[x]={Type:"AWS::Lambda::Function",DependsOn:[`${x}LogGroup`,...ge],Properties:{FunctionName:_,Architectures:[c],MemorySize:ee,Timeout:mt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:M(W)},EphemeralStorage:{Size:he},...rn,...Be!==void 0?{ReservedConcurrentExecutions:Be}:{},...Q,...Te}}}if(te("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,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 x of re)v[`${x}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(x)}},v[`${x}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(x),Name:"live",FunctionVersion:t.getAtt(`${x}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Z}}};let fe=(x)=>Z?t.ref(`${x}Alias`):t.getAtt(x,"Arn"),ae=(x)=>Z?t.ref(`${x}Alias`):t.ref(x);v.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${a}-${r}`,ProtocolType:"HTTP"}},v.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},v.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},v.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},v.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},I.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},I.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ue=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(ue.length){if(!n.certificateArn&&!n.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let x=n.certificateArn;if(!x)v.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ue[0],...ue.length>1?{SubjectAlternativeNames:ue.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ue.map((_)=>({DomainName:_,HostedZoneId:n.hostedZoneId}))}},x=t.ref("HttpCertificate");ue.forEach((_,V)=>{let W=`HttpDomain${V}`;if(v[W]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:_,DomainNameConfigurations:[{CertificateArn:x,EndpointType:"REGIONAL"}]}},v[`HttpApiMapping${V}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(W),Stage:"$default"}},n.hostedZoneId)v[`HttpDomainRecord${V}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:_,Type:"A",AliasTarget:{DNSName:t.getAtt(W,"RegionalDomainName"),HostedZoneId:t.getAtt(W,"RegionalHostedZoneId")}}};I[`CustomDomain${V}`]={Description:`Custom domain ${_}`,Value:_},I[`CustomDomainTarget${V}`]={Description:`Point ${_} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(W,"RegionalDomainName")}})}if(g)v.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${a}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((x,_)=>{let V=`AppQueue${_}`,W=n.queueTimeout??120;v[V]={Type:"AWS::SQS::Queue",Properties:{QueueName:x.name,VisibilityTimeout:Math.min(43200,W*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let ee=x.concurrency??n.queueConcurrency;v[`${V}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(V,"Arn"),FunctionName:ae("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ee?{ScalingConfig:{MaximumConcurrency:Math.max(2,ee)}}:{}}},I[`QueueUrl${_}`]={Description:`Queue URL: ${x.name}`,Value:t.ref(V)}});if(h)v.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},v.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(n.warm&&n.warm>0){let _={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},V=(n.warmFunctions??["http"]).filter((W)=>W!=="queue"||g);for(let W of V){let ee=W.charAt(0).toUpperCase()+W.slice(1),mt=Math.ceil(n.warm/5),Be=0;for(let he=0;he<mt;he++){let Fe=Math.min(5,n.warm-Be);v[`Warmer${ee}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-warmer-${W}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Fe},(rn,lr)=>({Id:`warm-${W}-${he}-${lr}`,Arn:t.getAtt(_[W],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Be+=Fe}v[`Warmer${ee}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(_[W]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${a}-${r}-warmer-${W}-*`)}}}}if(S)v.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},I.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(C){if(v.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:E,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},v.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${a}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},v.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...n.assetDomain?{Aliases:[n.assetDomain],ViewerCertificate:{AcmCertificateArn:n.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},n.assetDomain){if(!n.assetCertificateArn){if(!n.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(u!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);v.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)v.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};I.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}v.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${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 x=[],_=0;if(n.firewall.rateLimit)x.push({Name:"rate-limit",Priority:_++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-rate`}});let V={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let W of n.firewall.rules??[]){let ee=V[W];if(!ee)continue;x.push({Name:`managed-${W}`,Priority:_++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ee}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-${W}`}})}v.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${a}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:x,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-waf`}}},I.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:t.getAtt("WebAcl","Arn")}}if(J&&K){if(!n.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");v.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${a}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(U)v.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${a}-${r}-efs`}]}},q.forEach((x,_)=>{v[`EfsMountTarget${_}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:x,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),v.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},I.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")v.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${a}-${r} cache subnets`,SubnetIds:q}},v.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${a}-${r}-cache`,ReplicationGroupDescription:`${a}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},I.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")v.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${a}-${r} db subnets`,SubnetIds:q}},v.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${a}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},v.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${a}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:n.database?.minCapacity??0.5,MaxCapacity:n.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},v.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},I.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")v.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},v.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${a}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},v.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},I.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(I.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},I.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)I.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${a}-${r})`,Parameters:f?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:v,Outputs:I},Le={};for(let x of Object.values(v))Le[x.Type]=(Le[x.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Le}}var hp=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function yp(e){let n=`php${e.replace(".","")}`;return hp.map((r)=>`${n}-php-${r}`)}function Ja(e,n){let r=`php${e.replace(".","")}`,i=yp(e).join(" \\\n "),a=`/opt/remi/${r}/root`,s=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
7252
7252
 
7253
7253
  # Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
7254
7254
  # cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
@@ -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 ks}from"node:fs";import{dirname as Ms,join as rr}from"node:path";import{fileURLToPath as Ls}from"node:url";function Os(){return rr(Ms(Ls(import.meta.url)),"runtime-assets")}function Pn(){let e=Os(),n=(r)=>ks(rr(e,r),"utf-8");return[{path:"bootstrap",contents:n("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:n("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:n("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:n("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:n("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:hd(),mode:420}]}function rc(e={}){let n=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:n,CACHE_DRIVER:n,SESSION_DRIVER:n,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var yd=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as dt}from"node:child_process";import{existsSync as $s,mkdirSync as Bs,mkdtempSync as Fs,readdirSync as Gs,readFileSync as _s,rmSync as Ws,statSync as ir,writeFileSync as Vs}from"node:fs";import{tmpdir as Us}from"node:os";import{join as Me,relative as Hs}from"node:path";function*ar(e){for(let n of Gs(e)){let r=Me(e,n);if(ir(r).isDirectory())yield*ar(r);else yield r}}function dh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),a=Fs(Me(Us(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{Vs(Me(a,"Dockerfile"),ad(e)),i("Building PHP runtime image (docker)"),dt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",a],{stdio:"inherit"}),i("Extracting /opt/php from image");let c=dt("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Me(a,"opt");Bs(u,{recursive:!0});try{dt("docker",["cp",`${c}:/opt/php`,Me(u,"php")],{stdio:"inherit"})}finally{dt("docker",["rm",c],{stdio:"ignore"})}if(!$s(Me(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of ar(u)){let f=Hs(u,y).replace(/\\/g,"/"),h=ir(y).mode&73?493:420;d.push({name:f,data:_s(y),mode:h})}i("Injecting runtime assets");let m=new Set(Pn().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of Pn())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:Dt(p),architecture:n,fileCount:p.length}}finally{Ws(a,{recursive:!0,force:!0})}}import{execSync as js}from"node:child_process";import{createHash as Ks}from"node:crypto";import{readdirSync as qs,readFileSync as zs,statSync as sr}from"node:fs";import{join as Qs,relative as or,resolve as nn}from"node:path";var Ap=[".git",".github","node_modules","tests","storage/logs","storage/framework/cache","storage/framework/sessions","storage/framework/views",".env",".env.local",".vapor",".ts-cloud","dist-lambda"];function Js(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*cr(e,n,r){for(let i of qs(e)){let a=Qs(e,i),s=or(n,a).replace(/\\/g,"/");if(Js(s,r))continue;if(sr(a).isDirectory())yield*cr(a,n,r);else yield a}}function rs(e){if(e.skipBuild)return;let n=nn(e.projectRoot??process.cwd()),r=e.app.build??yd;for(let i of r)e.onStep?.(`build: ${i}`),js(i,{stdio:"inherit",cwd:n})}function ns(e,n=[]){let r=nn(e),i=[...Ap,Cn(),...n],a=[];for(let s of cr(r,r,i)){let c=or(r,s).replace(/\\/g,"/"),u=(sr(s).mode&73)!==0;a.push({name:c,data:zs(s),mode:u?493:420})}return a}function nc(e){let n=nn(e.projectRoot??process.cwd());rs(e),e.onStep?.("packaging application tree");let r=ns(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=Dt(r),a=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:Ks("sha256").update(i).digest("hex"),handlers:{http:a,queue:e.app.handlers?.queue??a,cli:e.app.handlers?.cli??a},fileCount:r.length}}class bd{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let n=`asset-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.optimizations.set(n,r),r}createImageOptimization(e){let n=`image-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.imageConfigs.set(n,r),r}createSSGConfig(e){let n=`ssg-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.ssgConfigs.set(n,r),r}createPrerenderConfig(e){let n=`prerender-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.prerenderConfigs.set(n,r),r}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var uh=new bd;class ic{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(e,n){let r=`lifecycle-${Date.now()}-${this.counter++}`,i={id:r,transitions:e,expiration:n};return this.policies.set(r,i),i}enableVersioning(e=!1){let n=`versioning-${Date.now()}-${this.counter++}`,r={id:n,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(n,r),r}createReplicationRule(e,n,r){let i=`replication-${Date.now()}-${this.counter++}`,a={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,a),a}createIntelligentTiering(e,n){let r=`tiering-${Date.now()}-${this.counter++}`,i={id:r,archiveDays:e,deepArchiveDays:n};return this.tieringConfigs.set(r,i),i}enableObjectLock(e){let n=`object-lock-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(n,r),r}enableTransferAcceleration(e){let n=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(n,r),r}createAccessPoint(e){let n=`access-point-${Date.now()}-${this.counter++}`,r={id:n,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(n,r),r}createGlacierArchive(e){let n=`glacier-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(n,r),r}createInventory(e){let n=`inventory-${Date.now()}-${this.counter++}`,r={id:n,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(n,r),r}createBatchOperation(e){let n=`batch-op-${Date.now()}-${this.counter++}`,r={id:n,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(n,r),r}executeBatchOperation(e){let n=this.batchOps.get(e);if(!n)throw Error(`Batch operation not found: ${e}`);return n.status="in_progress",n.totalObjects=1000,n.processedObjects=0,n}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSQSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSNSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}generateObjectLockCF(e){let n={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)n.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)n.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return n}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let n=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",i={Event:e.events[0],[r]:e.destination.arn};if(e.filter)i.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[n]:[i]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var Rp=new ic;class Sd{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,a={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,a),a}createSyntheticMonitor(e,n,r,i){let a=`synthetic-${Date.now()}-${this.counter++}`,s={id:a,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(a,s),s}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,a=n/(n+r)*100,s={id:i,resource:e,uptime:n,downtime:r,availability:a};return this.uptimeTrackers.set(i,s),s}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var ph=new Sd;class vd{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let a=`waf-${Date.now()}-${this.counter++}`,s={id:a,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(a,s),s}enableShield(e,n="standard"){let r=`shield-${Date.now()}-${this.counter++}`,i={id:r,resourceArn:e,protectionType:n};return this.shieldProtections.set(r,i),i}createSecurityGroup(e,n,r){let i=`sg-${Date.now()}-${this.counter++}`,a={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,a),a}createNACL(e,n){let r=`nacl-${Date.now()}-${this.counter++}`,i={id:r,vpcId:e,rules:n};return this.nacls.set(r,i),i}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var mh=new vd;class Cd{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,n){let r=`tagging-${Date.now()}-${this.counter++}`,i={id:r,tags:e,resources:n};return this.strategies.set(r,i),i}createCostAllocation(e,n){let r=`cost-${Date.now()}-${this.counter++}`,i={id:r,tagKey:e,allocations:n};return this.allocations.set(r,i),i}createResourceGroup(e,n,r){let i=`group-${Date.now()}-${this.counter++}`,a={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,a),a}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var gh=new Cd;export{hm,ym,sa,Zc,aa,ca,Cn,je,A,la,el,H,Ur,w,eu,ne,Fr,da,qo,le,B,Go,tu,ru,nu,iu,l,o,bm,Sm,T,ua,pa,ma,vm,Cm,Oe,ga,Li,ou,Tm,Em,Ve,At,fa,tl,rl,wm,nl,il,ol,Wo,ha,it,Ko,Tn,Mi,En,ze,su,Jo,Xo,ya,ba,Sa,va,Ca,Ta,Ae,j,au,cu,sl,b,L,ot,k,al,Rt,ye,Gt,Am,cl,Re,Qo,He,Wt,Ui,Ie,Yo,$e,lu,Fi,Pe,De,ie,Bi,X,Kt,It,ke,t,wn,Rm,ll,Ea,Im,Pm,Dm,km,wa,Nm,xm,_m,Om,$m,Lm,Mm,Um,Fm,Bm,jm,Vm,du,uu,pu,mu,gu,fu,hu,Jt,dl,ul,Br,ji,zm,pl,Hm,qm,An,Gm,Wm,Km,Jm,Xm,Qm,yu,bu,Su,vu,Cu,Vi,Ym,Rn,Tu,ml,Eu,Aa,be,wu,Au,Pt,Zo,Xt,Ru,gl,Iu,Pu,Du,fl,Se,Zm,eg,tg,rg,ku,ng,Ne,ig,og,sg,Ra,Ia,Nu,hl,yl,ag,cg,lg,dg,ug,xu,Pa,pg,mg,gg,fg,hg,_u,Ou,yg,bg,Sg,vg,Cg,Tg,Eg,$u,wg,bl,Da,Ag,Rg,Ig,Pg,Sl,vl,Cl,Dg,ka,Lu,Mu,Uu,Fu,Na,Bu,kg,Ng,xg,_g,Og,$g,Lg,ju,Vu,zu,Hu,Tl,Mg,Ug,Fg,Bg,jg,Vg,zg,Hg,qg,qu,Gu,Wu,Ku,Gg,Wg,El,Kg,wl,Al,Rl,Il,Jg,Xg,Qg,Yg,st,zi,Zg,ef,tf,rf,nf,of,sf,af,Ju,cf,lf,Pl,Dl,df,uf,Xu,pf,mf,gf,ff,hf,yf,bf,Sf,vf,Cf,Tf,Ef,wf,Af,Rf,If,Pf,Df,kf,Nf,xf,xa,Qu,_a,Yu,Oa,Zu,$a,ep,La,tp,jr,rp,Ma,np,Hi,ip,Ua,op,Fa,sp,kl,_f,Nl,Of,Ba,ap,Vr,cp,xl,$f,ja,lp,_l,Lf,Ol,Mf,$l,Uf,Va,dp,Ll,Ff,Ml,Bf,Ul,jf,Fl,Vf,za,up,Ha,pp,Bl,zf,jl,Hf,Vl,qf,zl,Gf,Hl,Wf,ql,Kf,qa,mp,Gl,Jf,Wl,Xf,Kl,Qf,Jl,Yf,Xl,Zf,Ql,eh,Yl,Zl,ed,td,rd,th,nd,rh,id,nh,od,ih,Dt,sd,gp,es,Ga,In,fp,qi,Qt,Wa,Ka,hp,yp,Ja,ad,Xa,cd,oh,sh,Qa,Ya,Za,ld,Gi,dd,ud,ts,ec,tc,pd,bp,Sp,vp,ah,md,gd,ch,Cp,fd,Tp,Ep,wp,lh,hd,Pn,rc,yd,dh,Ap,rs,ns,nc,bd,uh,ic,Rp,Sd,ph,vd,mh,Cd,gh};
7329
+ `}import{readFileSync as ks}from"node:fs";import{dirname as Ms,join as rr}from"node:path";import{fileURLToPath as Ls}from"node:url";function Os(){return rr(Ms(Ls(import.meta.url)),"runtime-assets")}function Pn(){let e=Os(),n=(r)=>ks(rr(e,r),"utf-8");return[{path:"bootstrap",contents:n("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:n("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:n("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:n("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:n("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:hd(),mode:420}]}function rc(e={}){let n=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:n,CACHE_DRIVER:n,SESSION_DRIVER:n,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var yd=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as dt}from"node:child_process";import{existsSync as $s,mkdirSync as Bs,mkdtempSync as Fs,readdirSync as Gs,readFileSync as _s,rmSync as Ws,statSync as ir,writeFileSync as Vs}from"node:fs";import{tmpdir as Us}from"node:os";import{join as Me,relative as Hs}from"node:path";function*ar(e){for(let n of Gs(e)){let r=Me(e,n);if(ir(r).isDirectory())yield*ar(r);else yield r}}function dh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),a=Fs(Me(Us(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{Vs(Me(a,"Dockerfile"),ad(e)),i("Building PHP runtime image (docker)"),dt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",a],{stdio:"inherit"}),i("Extracting /opt/php from image");let c=dt("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Me(a,"opt");Bs(u,{recursive:!0});try{dt("docker",["cp",`${c}:/opt/php`,Me(u,"php")],{stdio:"inherit"})}finally{dt("docker",["rm",c],{stdio:"ignore"})}if(!$s(Me(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of ar(u)){let f=Hs(u,y).replace(/\\/g,"/"),h=ir(y).mode&73?493:420;d.push({name:f,data:_s(y),mode:h})}i("Injecting runtime assets");let m=new Set(Pn().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of Pn())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:Dt(p),architecture:n,fileCount:p.length}}finally{Ws(a,{recursive:!0,force:!0})}}import{execSync as js}from"node:child_process";import{createHash as Ks}from"node:crypto";import{readdirSync as qs,readFileSync as zs,statSync as sr}from"node:fs";import{join as Qs,relative as or,resolve as nn}from"node:path";var Ap=[".git",".github","node_modules","tests","storage/logs","storage/framework/cache","storage/framework/sessions","storage/framework/views",".env",".env.local",".vapor",".ts-cloud","dist-lambda"];function Js(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*cr(e,n,r){for(let i of qs(e)){let a=Qs(e,i),s=or(n,a).replace(/\\/g,"/");if(Js(s,r))continue;if(sr(a).isDirectory())yield*cr(a,n,r);else yield a}}function rs(e){if(e.skipBuild)return;let n=nn(e.projectRoot??process.cwd()),r=e.app.build??yd;for(let i of r)e.onStep?.(`build: ${i}`),js(i,{stdio:"inherit",cwd:n})}function ns(e,n=[]){let r=nn(e),i=[...Ap,Cn(),...n],a=[];for(let s of cr(r,r,i)){let c=or(r,s).replace(/\\/g,"/"),u=(sr(s).mode&73)!==0;a.push({name:c,data:zs(s),mode:u?493:420})}return a}function nc(e){let n=nn(e.projectRoot??process.cwd());rs(e),e.onStep?.("packaging application tree");let r=ns(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=Dt(r),a=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:Ks("sha256").update(i).digest("hex"),handlers:{http:a,queue:e.app.handlers?.queue??a,cli:e.app.handlers?.cli??a},fileCount:r.length}}class bd{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let n=`asset-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.optimizations.set(n,r),r}createImageOptimization(e){let n=`image-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.imageConfigs.set(n,r),r}createSSGConfig(e){let n=`ssg-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.ssgConfigs.set(n,r),r}createPrerenderConfig(e){let n=`prerender-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.prerenderConfigs.set(n,r),r}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var uh=new bd;class ic{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(e,n){let r=`lifecycle-${Date.now()}-${this.counter++}`,i={id:r,transitions:e,expiration:n};return this.policies.set(r,i),i}enableVersioning(e=!1){let n=`versioning-${Date.now()}-${this.counter++}`,r={id:n,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(n,r),r}createReplicationRule(e,n,r){let i=`replication-${Date.now()}-${this.counter++}`,a={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,a),a}createIntelligentTiering(e,n){let r=`tiering-${Date.now()}-${this.counter++}`,i={id:r,archiveDays:e,deepArchiveDays:n};return this.tieringConfigs.set(r,i),i}enableObjectLock(e){let n=`object-lock-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(n,r),r}enableTransferAcceleration(e){let n=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(n,r),r}createAccessPoint(e){let n=`access-point-${Date.now()}-${this.counter++}`,r={id:n,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(n,r),r}createGlacierArchive(e){let n=`glacier-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(n,r),r}createInventory(e){let n=`inventory-${Date.now()}-${this.counter++}`,r={id:n,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(n,r),r}createBatchOperation(e){let n=`batch-op-${Date.now()}-${this.counter++}`,r={id:n,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(n,r),r}executeBatchOperation(e){let n=this.batchOps.get(e);if(!n)throw Error(`Batch operation not found: ${e}`);return n.status="in_progress",n.totalObjects=1000,n.processedObjects=0,n}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSQSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}createSNSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(n,r),r}generateObjectLockCF(e){let n={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)n.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)n.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return n}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let n=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",i={Event:e.events[0],[r]:e.destination.arn};if(e.filter)i.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[n]:[i]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var Rp=new ic;class Sd{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,a={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,a),a}createSyntheticMonitor(e,n,r,i){let a=`synthetic-${Date.now()}-${this.counter++}`,s={id:a,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(a,s),s}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,a=n/(n+r)*100,s={id:i,resource:e,uptime:n,downtime:r,availability:a};return this.uptimeTrackers.set(i,s),s}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var ph=new Sd;class vd{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let a=`waf-${Date.now()}-${this.counter++}`,s={id:a,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(a,s),s}enableShield(e,n="standard"){let r=`shield-${Date.now()}-${this.counter++}`,i={id:r,resourceArn:e,protectionType:n};return this.shieldProtections.set(r,i),i}createSecurityGroup(e,n,r){let i=`sg-${Date.now()}-${this.counter++}`,a={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,a),a}createNACL(e,n){let r=`nacl-${Date.now()}-${this.counter++}`,i={id:r,vpcId:e,rules:n};return this.nacls.set(r,i),i}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var mh=new vd;class Cd{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,n){let r=`tagging-${Date.now()}-${this.counter++}`,i={id:r,tags:e,resources:n};return this.strategies.set(r,i),i}createCostAllocation(e,n){let r=`cost-${Date.now()}-${this.counter++}`,i={id:r,tagKey:e,allocations:n};return this.allocations.set(r,i),i}createResourceGroup(e,n,r){let i=`group-${Date.now()}-${this.counter++}`,a={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,a),a}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var gh=new Cd;export{hm,ym,sa,Zc,aa,ca,Cn,je,R,la,el,H,Ur,A,eu,ne,Fr,da,qo,le,B,Go,tu,ru,nu,iu,l,o,bm,Sm,T,ua,pa,ma,vm,Cm,Oe,ga,Li,ou,Tm,Em,Ve,At,fa,tl,rl,wm,nl,il,ol,Wo,ha,it,Ko,Tn,Mi,En,ze,su,Jo,Xo,ya,ba,Sa,va,Ca,Ta,Ae,j,au,cu,sl,b,L,ot,k,al,Rt,ye,Gt,Am,cl,Re,Qo,He,Wt,Ui,Ie,Yo,$e,lu,Fi,Pe,De,ie,Bi,X,Kt,It,ke,t,wn,Rm,ll,Ea,Im,Pm,Dm,km,wa,Nm,xm,_m,Om,$m,Lm,Mm,Um,Fm,Bm,jm,Vm,du,uu,pu,mu,gu,fu,hu,Jt,dl,ul,Br,ji,zm,pl,Hm,qm,An,Gm,Wm,Km,Jm,Xm,Qm,yu,bu,Su,vu,Cu,Vi,Ym,Rn,Tu,ml,Eu,Aa,be,wu,Au,Pt,Zo,Xt,Ru,gl,Iu,Pu,Du,fl,Se,Zm,eg,tg,rg,ku,ng,Ne,ig,og,sg,Ra,Ia,Nu,hl,yl,ag,cg,lg,dg,ug,xu,Pa,pg,mg,gg,fg,hg,_u,Ou,yg,bg,Sg,vg,Cg,Tg,Eg,$u,wg,bl,Da,Ag,Rg,Ig,Pg,Sl,vl,Cl,Dg,ka,Lu,Mu,Uu,Fu,Na,Bu,kg,Ng,xg,_g,Og,$g,Lg,ju,Vu,zu,Hu,Tl,Mg,Ug,Fg,Bg,jg,Vg,zg,Hg,qg,qu,Gu,Wu,Ku,Gg,Wg,El,Kg,wl,Al,Rl,Il,Jg,Xg,Qg,Yg,st,zi,Zg,ef,tf,rf,nf,of,sf,af,Ju,cf,lf,Pl,Dl,df,uf,Xu,pf,mf,gf,ff,hf,yf,bf,Sf,vf,Cf,Tf,Ef,wf,Af,Rf,If,Pf,Df,kf,Nf,xf,xa,Qu,_a,Yu,Oa,Zu,$a,ep,La,tp,jr,rp,Ma,np,Hi,ip,Ua,op,Fa,sp,kl,_f,Nl,Of,Ba,ap,Vr,cp,xl,$f,ja,lp,_l,Lf,Ol,Mf,$l,Uf,Va,dp,Ll,Ff,Ml,Bf,Ul,jf,Fl,Vf,za,up,Ha,pp,Bl,zf,jl,Hf,Vl,qf,zl,Gf,Hl,Wf,ql,Kf,qa,mp,Gl,Jf,Wl,Xf,Kl,Qf,Jl,Yf,Xl,Zf,Ql,eh,Yl,Zl,ed,td,rd,th,nd,rh,id,nh,od,ih,Dt,sd,gp,es,Ga,In,fp,qi,Qt,Wa,Ka,hp,yp,Ja,ad,Xa,cd,oh,sh,Qa,Ya,Za,ld,Gi,dd,ud,ts,ec,tc,pd,bp,Sp,vp,ah,md,gd,ch,Cp,fd,Tp,Ep,wp,lh,hd,Pn,rc,yd,dh,Ap,rs,ns,nc,bd,uh,ic,Rp,Sd,ph,vd,mh,Cd,gh};