@stacksjs/ts-cloud 0.12.16 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aws/index.js +1 -1
- package/dist/bin/{chunk-9wjgxjqp.js → chunk-22c3pk8s.js} +48 -48
- package/dist/bin/chunk-2ahgpy3j.js +2 -0
- package/dist/bin/chunk-2synp9gh.js +1 -0
- package/dist/bin/{chunk-zhpzxnpg.js → chunk-2v0qm547.js} +1 -1
- package/dist/bin/{chunk-52wgrpe8.js → chunk-88ysj8n5.js} +1 -1
- package/dist/bin/{chunk-6tty6sjf.js → chunk-8bbw6qc2.js} +1 -1
- package/dist/bin/{chunk-2shtky1g.js → chunk-9qndhwbe.js} +1 -1
- package/dist/bin/{chunk-a76krpa1.js → chunk-bdgkeqv6.js} +1 -1
- package/dist/bin/chunk-c82rh7qe.js +1 -0
- package/dist/bin/{chunk-e3d9m062.js → chunk-d4bb9qg9.js} +1 -1
- package/dist/bin/{chunk-tpjepvwa.js → chunk-d6kqbp8q.js} +1 -1
- package/dist/bin/{chunk-a8rn2wym.js → chunk-dk38j1qr.js} +9 -9
- package/dist/bin/{chunk-9vrnrxay.js → chunk-e1cxh9rj.js} +2 -2
- package/dist/bin/{chunk-9k60q9qz.js → chunk-edaq5jef.js} +3 -3
- package/dist/bin/{chunk-srw2jmh3.js → chunk-fbycbnvj.js} +4 -4
- package/dist/bin/chunk-fj89173b.js +1 -0
- package/dist/bin/{chunk-xyk8qe2c.js → chunk-gxwsq3k0.js} +21 -21
- package/dist/bin/{chunk-ebdybz7x.js → chunk-hwp5xp1c.js} +35 -35
- package/dist/bin/{chunk-ndbtr4mb.js → chunk-jee6msvx.js} +3 -3
- package/dist/bin/chunk-kjatss6s.js +1 -0
- package/dist/bin/{chunk-mekcw1zn.js → chunk-kxa4t4wh.js} +2 -2
- package/dist/bin/{chunk-8sxb2rr0.js → chunk-m5sjzxm3.js} +1 -1
- package/dist/bin/{chunk-7xszcdqn.js → chunk-n56c0j1e.js} +4 -4
- package/dist/bin/{chunk-be7rhw60.js → chunk-rzt92fwv.js} +3 -3
- package/dist/bin/{chunk-zav02r6k.js → chunk-vwzgtsn9.js} +1 -1
- package/dist/bin/{chunk-dvm4n8m8.js → chunk-w0g72e50.js} +1 -1
- package/dist/bin/chunk-wb8y7zey.js +1 -0
- package/dist/bin/{chunk-y24gfke7.js → chunk-x4gsw45d.js} +5 -5
- package/dist/bin/{chunk-hzj5r6b7.js → chunk-xs62dg7t.js} +2 -2
- package/dist/bin/{chunk-k7w2ztw9.js → chunk-xtp2zf3j.js} +1 -1
- package/dist/bin/{chunk-5qann9n2.js → chunk-xw9vcdwt.js} +1 -1
- package/dist/bin/{chunk-3zq0wkz2.js → chunk-y671cgz5.js} +1 -1
- package/dist/bin/cli.js +76 -76
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/chunk-05qawkra.js +1 -0
- package/dist/{chunk-qszktnnz.js → chunk-0g2jkhy5.js} +1 -1
- package/dist/{chunk-crpjqnjb.js → chunk-2s65yj3g.js} +4 -4
- package/dist/chunk-3qtce4mm.js +1 -0
- package/dist/chunk-3tt5em2c.js +1 -0
- package/dist/{chunk-hw3p6pth.js → chunk-42kv07cs.js} +1 -1
- package/dist/{chunk-nr1bdzwy.js → chunk-65ajja2a.js} +1 -1
- package/dist/{chunk-rtg6nw3n.js → chunk-6gtqjsg9.js} +3 -3
- package/dist/{chunk-a7v15116.js → chunk-8s9m8pyb.js} +1 -1
- package/dist/chunk-a1p70h5d.js +2 -0
- package/dist/{chunk-j9rv5m58.js → chunk-asmv4fw1.js} +19 -19
- package/dist/{chunk-a6zymyfs.js → chunk-ds92qg3g.js} +4 -4
- package/dist/{chunk-93mgdgd5.js → chunk-dzqz1sm0.js} +3 -3
- package/dist/{chunk-wz57brcf.js → chunk-hyj2ymp1.js} +6 -6
- package/dist/{chunk-1zz5n6q8.js → chunk-j7vsrx9g.js} +5 -5
- package/dist/chunk-jdq95b4h.js +1 -0
- package/dist/{chunk-wxv3ypt5.js → chunk-m5r0dt28.js} +2 -2
- package/dist/{chunk-bga3mw5f.js → chunk-mcfdtg5w.js} +1 -1
- package/dist/{chunk-4ywy6dp5.js → chunk-ngdhqwf3.js} +3 -3
- package/dist/{chunk-6znnde1s.js → chunk-nhtz2k8d.js} +5 -5
- package/dist/{chunk-kazw813q.js → chunk-nw0tvrrr.js} +1 -1
- package/dist/{chunk-d1tv3wx0.js → chunk-p9fqsz06.js} +2 -2
- package/dist/{chunk-qzwack6w.js → chunk-r4dpn715.js} +7 -7
- package/dist/{chunk-ajq92t46.js → chunk-t5tvt2r3.js} +124 -124
- package/dist/{chunk-jk7ecnmc.js → chunk-vk513ge7.js} +78 -78
- package/dist/{chunk-mherymtx.js → chunk-w5fmaaxa.js} +4 -4
- package/dist/chunk-wr7tn9j5.js +1 -0
- package/dist/{chunk-7hjsnwcv.js → chunk-xqx5szta.js} +27 -27
- package/dist/{chunk-thghrpf9.js → chunk-y13zcbnp.js} +101 -101
- package/dist/{chunk-bgrre2px.js → chunk-z7v4evbh.js} +2 -2
- package/dist/deploy/index.js +1 -1
- package/dist/dns/delegate-from-config.d.ts +50 -0
- package/dist/dns/delegate-from-config.test.d.ts +1 -0
- package/dist/dns/delegation.d.ts +110 -0
- package/dist/dns/delegation.test.d.ts +1 -0
- package/dist/dns/index.d.ts +4 -0
- package/dist/dns/index.js +1 -1
- package/dist/dns/porkbun-nameservers.test.d.ts +1 -0
- package/dist/drivers/index.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +49 -49
- package/dist/operations/index.js +1 -1
- package/dist/protection/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +6 -6
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +1 -1
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +2 -2
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +5 -5
- package/dist/ui/operations/maintenance.html +5 -5
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +2 -2
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +6 -6
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +6 -6
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +2 -2
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +5 -5
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +5 -5
- package/package.json +3 -3
- package/dist/bin/chunk-005sxfmc.js +0 -1
- package/dist/bin/chunk-4vgbynq6.js +0 -1
- package/dist/bin/chunk-bwvnfc74.js +0 -1
- package/dist/bin/chunk-cy4wwpnf.js +0 -1
- package/dist/bin/chunk-dxfsq94k.js +0 -2
- package/dist/bin/chunk-dy10cmt9.js +0 -1
- package/dist/chunk-8fcrgq31.js +0 -1
- package/dist/chunk-8msfne57.js +0 -2
- package/dist/chunk-eadp23eh.js +0 -1
- package/dist/chunk-jpbgr1wg.js +0 -1
- package/dist/chunk-w7710vzg.js +0 -1
- package/dist/chunk-xfdpxsbc.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as ar}from"node:module";import{isAbsolute as $t,join as ut,relative as ur}from"node:path";import{existsSync as Ge,readdirSync as Rr}from"node:fs";import{join as ce}from"node:path";import{createHash as Gr}from"node:crypto";import{copyFileSync as Ur,existsSync as Ct,readdirSync as Fr,readFileSync as tt,statSync as Vr,writeFileSync as at}from"node:fs";import{basename as jr,dirname as sa,extname as oa,join as Ue}from"node:path";import{existsSync as Na,readFileSync as
|
|
1
|
+
import{createRequire as ar}from"node:module";import{isAbsolute as $t,join as ut,relative as ur}from"node:path";import{existsSync as Ge,readdirSync as Rr}from"node:fs";import{join as ce}from"node:path";import{createHash as Gr}from"node:crypto";import{copyFileSync as Ur,existsSync as Ct,readdirSync as Fr,readFileSync as tt,statSync as Vr,writeFileSync as at}from"node:fs";import{basename as jr,dirname as sa,extname as oa,join as Ue}from"node:path";import{existsSync as Na,readFileSync as Gt}from"node:fs";import{homedir as Da}from"node:os";import{join as ka}from"node:path";import{createHash as $a}from"node:crypto";import{existsSync as nt,mkdirSync as Hn,readdirSync as da,readFileSync as ma,unlinkSync as Fe,writeFileSync as qn}from"node:fs";import{join as It}from"node:path";import{createHash as Kt}from"node:crypto";import{createReadStream as zn,readdirSync as Qn,statSync as dt}from"node:fs";import{join as Jn,relative as Yn}from"node:path";import{deflateRawSync as oi}from"node:zlib";import{execSync as Ci}from"node:child_process";import{createHash as Ti}from"node:crypto";import{cpSync as vi,mkdtempSync as wi,rmSync as Ei,writeFileSync as Pi}from"node:fs";import{tmpdir as Ii}from"node:os";import{dirname as Ri,isAbsolute as Ni,join as Ie,resolve as Di}from"node:path";import{fileURLToPath as ki}from"node:url";import{execFileSync as ht}from"node:child_process";import{mkdtempSync as xa,readFileSync as yt,rmSync as Oa}from"node:fs";import{tmpdir as Ba}from"node:os";import{dirname as xi,join as ue}from"node:path";import{fileURLToPath as Oi}from"node:url";import{AsyncLocalStorage as _i}from"node:async_hooks";import{createHash as Wi}from"node:crypto";import{readFileSync as Ki}from"node:fs";import{dirname as Hi,join as ja}from"node:path";import{fileURLToPath as qi}from"node:url";import{execFileSync as it}from"node:child_process";import{existsSync as Qi,mkdirSync as Ji,mkdtempSync as Yi,readdirSync as Zi,readFileSync as Xi,rmSync as es,statSync as Ha,writeFileSync as ts}from"node:fs";import{tmpdir as as}from"node:os";import{join as Re,relative as rs}from"node:path";import{execSync as ns}from"node:child_process";import{createHash as is}from"node:crypto";import{readdirSync as ss,readFileSync as os,statSync as za}from"node:fs";import{join as cs,relative as er,resolve as ia}from"node:path";var rr=Object.defineProperty,nr=(e)=>e;function ir(e,a){this[e]=nr.bind(null,a)}var xe=(e,a)=>{for(var r in a)rr(e,r,{get:a[r],enumerable:!0,configurable:!0,set:ir.bind(a,r)})},sr=(e,a,r)=>()=>{if(e)try{a=e(e=0)}catch(n){r=[n]}if(r)throw r[0];return a},or=ar(import.meta.url);function Wa(e){let a=typeof e==="string"?new URL(e):e,{hostname:r,pathname:n}=a;if(r.endsWith(".on.aws")){let u=r.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(u)return{service:"lambda",region:u[1]};return{service:"",region:""}}if(r.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(r.endsWith(".backblazeb2.com")){let u=r.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(u)return{service:"s3",region:u[1]};return{service:"",region:""}}let i=r.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!i)return{service:"",region:""};let o=i[1],c=i[2]||"";if(c==="us-gov")c="us-gov-west-1";else if(c==="s3"||c==="s3-accelerate")c="us-east-1",o="s3";else if(o==="iot")if(r.startsWith("iot."))o="execute-api";else if(r.startsWith("data.jobs.iot."))o="iot-jobs-data";else o=n==="/mqtt"?"iotdevicegateway":"iotdata";else if(o==="autoscaling");else if(!c&&o.startsWith("s3-"))c=o.slice(3).replace(/^fips-|^external-1/,""),o="s3";else if(o.endsWith("-fips"))o=o.slice(0,-5);else if(c&&/-\d$/.test(o)&&!/-\d$/.test(c))[o,c]=[c,o];return o=Ta[o]||o,{service:o,region:c||"us-east-1"}}function oe(e){let{method:a,url:r,body:n="",accessKeyId:i,secretAccessKey:o,sessionToken:c,signQuery:u=!1,expiresIn:d=86400,datetime:m}=e,p=new URL(r),g=p.hostname,h=Wa(p),y=e.service||h.service,f=e.region||h.region;if(!y)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!f)throw Error("Could not detect region from URL. Please provide region explicitly.");let b=m||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),v=b.substring(0,8),P=[v,f,y,"aws4_request"].join("/"),R="AWS4-HMAC-SHA256";if(u)return cr({urlObj:p,method:a,body:n,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:y,region:f,timestamp:b,date:v,credentialScope:P,algorithm:R,expiresIn:d,cache:e.cache});let T=p.pathname||"/",N=pt(p.searchParams),I={host:g,"x-amz-date":b,...e.headers};if(c)I["x-amz-security-token"]=c;let k=Object.keys(I).some((de)=>de.toLowerCase()==="content-type");if(n&&!k)I["content-type"]="application/x-amz-json-1.0";if(y==="s3"&&!I["x-amz-content-sha256"])I["x-amz-content-sha256"]=je(n);let x=ha(I),L=ya(I),O=I["x-amz-content-sha256"]||je(n),W=[a,gt(T),N,x,L,O].join(`
|
|
2
2
|
`),K=je(W),Z=[R,b,P,K].join(`
|
|
3
3
|
`),z=e.cache??ye,J=Sa(o,v,f,y,Z,z),H=[`${R} Credential=${i}/${P}`,`SignedHeaders=${L}`,`Signature=${J}`].join(", ");return I.authorization=H,{url:r,method:a,headers:I,body:n||void 0}}async function Ga(e){let{method:a,url:r,body:n="",accessKeyId:i,secretAccessKey:o,sessionToken:c,signQuery:u=!1,expiresIn:d=86400,datetime:m}=e,p=new URL(r),g=p.hostname,h=Wa(p),y=e.service||h.service,f=e.region||h.region;if(!y)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!f)throw Error("Could not detect region from URL. Please provide region explicitly.");let b=m||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),v=b.substring(0,8),P=[v,f,y,"aws4_request"].join("/"),R="AWS4-HMAC-SHA256";if(u)return lr({urlObj:p,method:a,body:n,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:y,region:f,timestamp:b,date:v,credentialScope:P,algorithm:R,expiresIn:d,cache:e.cache});let T=p.pathname||"/",N=pt(p.searchParams),I={host:g,"x-amz-date":b,...e.headers};if(c)I["x-amz-security-token"]=c;let k=Object.keys(I).some((Oe)=>Oe.toLowerCase()==="content-type");if(n&&!k)I["content-type"]="application/x-amz-json-1.0";let x=await ot(n);if(y==="s3"&&!I["x-amz-content-sha256"])I["x-amz-content-sha256"]=x;let L=ha(I),O=ya(I),W=I["x-amz-content-sha256"]||x,K=[a,gt(T),N,L,O,W].join(`
|
|
4
4
|
`),Z=await ot(K),z=[R,b,P,Z].join(`
|
|
@@ -10,7 +10,7 @@ import{createRequire as ar}from"node:module";import{isAbsolute as $t,join as ut,
|
|
|
10
10
|
`),k=[h,m,g,await ot(I)].join(`
|
|
11
11
|
`),x=await ba(o,p,d,u,k,f??ye);return b.searchParams.set("X-Amz-Signature",x),{url:b.toString(),method:r,headers:{},body:n||void 0}}function Yl(e){let{url:a,method:r="GET",expiresIn:n=3600,...i}=e,o=Math.min(n,604800);return oe({...i,url:a,method:r,signQuery:!0,expiresIn:o}).url}async function Mu(e){let{url:a,method:r="GET",expiresIn:n=3600,...i}=e,o=Math.min(n,604800);return(await Ga({...i,url:a,method:r,signQuery:!0,expiresIn:o})).url}function ha(e){return Object.keys(e).sort().map((a)=>`${a.toLowerCase()}:${e[a].trim().replace(/\s+/g," ")}`).join(`
|
|
12
12
|
`)+`
|
|
13
|
-
`}function ya(e){return Object.keys(e).sort().map((a)=>a.toLowerCase()).join(";")}function pt(e){let a=[];return e.forEach((r,n)=>{a.push([kt(n),kt(r)])}),a.sort((r,n)=>{if(r[0]<n[0])return-1;if(r[0]>n[0])return 1;if(r[1]<n[1])return-1;if(r[1]>n[1])return 1;return 0}),a.map(([r,n])=>`${r}=${n}`).join("&")}function gt(e){return e.split("/").map((a)=>kt(a)).join("/")}function kt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(a)=>`%${a.charCodeAt(0).toString(16).toUpperCase()}`)}function je(e){if(!$e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return $e.createHash("sha256").update(e,"utf8").digest("hex")}function _e(e,a){if(!$e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return $e.createHmac("sha256",e).update(a,"utf8").digest()}async function ot(e){let a=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",a);return fa(new Uint8Array(r))}async function We(e,a){let r=new TextEncoder,n=typeof e==="string"?r.encode(e):e,i=r.encode(a),o=await crypto.subtle.importKey("raw",n.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),c=await crypto.subtle.sign("HMAC",o,i.buffer);return new Uint8Array(c)}function fa(e){return Array.from(e).map((a)=>a.toString(16).padStart(2,"0")).join("")}function Sa(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let d=_e(`AWS4${e}`,a),m=_e(d,r),p=_e(m,n);if(u=_e(p,"aws4_request"),o.size>=Ca){let g=o.keys().next().value;if(g)o.delete(g)}o.set(c,u)}return _e(u,i).toString("hex")}async function ba(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let m=await We(`AWS4${e}`,a),p=await We(m,r),g=await We(p,n);if(u=await We(g,"aws4_request"),o.size>=Ca){let h=o.keys().next().value;if(h)o.delete(h)}o.set(c,u)}let d=await We(u,i);return fa(d)}function Aa(e,a){return a.includes(e)}function ct(e,a,r){let n=a*Math.pow(2,e),i=Math.random()*0.3*n;return Math.min(n+i,r)}function lt(e){return new Promise((a)=>setTimeout(a,e))}async function ui(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u,d;for(let m=0;m<=r;m++){let p=oe(e),g={method:p.method,headers:p.headers};if(p.body)g.body=p.body;let h=new AbortController,y=setTimeout(()=>h.abort(),c);g.signal=h.signal;try{let f=await fetch(p.url,g);if(clearTimeout(y),d=f,f.ok)return f;if(m<r&&Aa(f.status,o)){let v=ct(m,n,i);await lt(v);continue}let b=await f.text();throw Error(`AWS API request failed (${f.status}): ${b}`)}catch(f){if(clearTimeout(y),u=f,f instanceof Error&&f.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(m<r&&!(f instanceof Error&&f.message.includes("AWS API request failed"))){let b=ct(m,n,i);await lt(b);continue}throw u}}throw u??Error("Request failed after retries")}async function Uu(e){return ui(e,{maxRetries:0})}async function Bu(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u;for(let d=0;d<=r;d++){let m=await Ga(e),p={method:m.method,headers:m.headers};if(m.body)p.body=m.body;let g=new AbortController,h=setTimeout(()=>g.abort(),c);p.signal=g.signal;try{let y=await fetch(m.url,p);if(clearTimeout(h),y.ok)return y;if(d<r&&Aa(y.status,o)){let b=ct(d,n,i);await lt(b);continue}let f=await y.text();throw Error(`AWS API request failed (${y.status}): ${f}`)}catch(y){if(clearTimeout(h),u=y,y instanceof Error&&y.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(d<r&&!(y instanceof Error&&y.message.includes("AWS API request failed"))){let f=ct(d,n,i);await lt(f);continue}throw u}}throw u??Error("Request failed after retries")}async function Ds(e){let a=await e.text(),r={},n=/<(\w+)>([^<]+)<\/\1>/g,i;while((i=n.exec(a))!==null){let[,o,c]=i;r[o]=c}return r}async function Fu(e){return await e.json()}function ju(){ye.clear()}function Vu(){return ye.size}function zu(){return $e!==void 0}function qu(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var $e,ye,Ca=100,Ta,ze=sr(async()=>{try{$e=await import("node:crypto")}catch{}ye=new Map,Ta={appstream2:"appstream",cloudhsmv2:"cloudhsm",email:"ses",marketplace:"aws-marketplace",mobile:"AWSMobileHubService",pinpoint:"mobiletargeting",queue:"sqs","git-codecommit":"codecommit","mturk-requester-sandbox":"mturk-requester","personalize-runtime":"personalize"}}),Hu={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}},Wu={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}}}},Ka=".ts-cloud",Ja="TS_CLOUD_STATE_DIR",_t=null;function ks(e){_t=e?.trim()||null}function xs(){return Boolean(process.env[Ja]?.trim()||_t)}function ho(){return process.env[Ja]?.trim()||_t||Ka}function Je(...e){return ut(ho(),...e)}function A(e,...a){let r=ho();return $t(r)?ut(r,...a):ut(e,r,...a)}function _s(e,a=process.cwd()){let r=(i,o)=>{let c=ur(i,o);return c===""||!c.startsWith("..")&&!$t(c)},n=$t(e)?e:ut(a,e);return r(A(a),n)}function Xa(e){let a=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((n)=>n?.app!=null);return{server:a,serverless:r}}function V(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:a}=Xa(e);return a?"serverless":"server"}function wr(e){let{server:a,serverless:r}=Xa(e);if(a&&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&&!a)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&a&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function C(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function dr(e){return typeof e==="object"&&e!==null?e:{}}function Zl(e){return e===!0||typeof e==="object"&&e!==null}function mr(e,a){let r=a?e.environments?.[a]:void 0;if(r?.domain)return r.domain;let n=Object.values(e.sites??{}),i=e.sites?.main?.domain??n.find((o)=>o.domain)?.domain;if(i)return i;return`${e.project?.slug??"app"}.local`}function pr(e){let a=e.indexOf(".");return a>0?e.slice(a+1):void 0}function pi(e,a={}){let r=e.infrastructure?.compute?.managedServices?.mail,n=dr(r),i=a.environmentType??(a.environment?e.environments?.[a.environment]?.type:void 0),o=n.mode??(i==="production"?"server":"catcher"),c=o==="server",u=mr(e,a.environment),d=n.hostname??(c?`mail.${u}`:"localhost"),m=n.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=n.tls??{},h=g.enabled??c,y=!!(g.certPath&&g.keyPath),f=(n.accounts??[]).map((L)=>({address:L.address,password:L.password})),b=typeof n.dkim==="object"&&n.dkim!==null?n.dkim:{},v=n.dkim===!1?!1:n.dkim===!0||c,P=typeof n.webmail==="object"&&n.webmail!==null?n.webmail:{},R=n.webmail===!1?!1:P.enabled??!0,T=n.spam??{},N=n.delivery??(c?"direct":"none"),I=n.expose??c,k=pr(d),x=[...new Set([d,...k?[k]:[],...n.domains??[]])];return{enabled:Zl(r),mode:o,version:n.version,hostname:d,domains:x,ports:p,tls:{enabled:h,acme:h&&!y&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(h&&c),acmeEmail:g.acmeEmail??f[0]?.address},dkim:{enabled:v,selector:b.selector??"default",rotate:b.rotate??!1,rotateIntervalDays:b.rotateIntervalDays??90},webmail:{enabled:R,port:P.port??p.webmail,domain:P.domain},delivery:N,sesRegion:n.sesRegion??"us-east-1",accounts:f,storagePath:n.storagePath??"/var/lib/mail",maxMessageSize:n.maxMessageSize??26214400,spam:{enabled:T.enabled??c,enforce:T.enforce??!1,junkScore:T.junkScore??5,rejectScore:T.rejectScore??12,dnsbl:T.dnsbl??c,greylist:T.greylist??!1},webhookUrl:n.webhookUrl,expose:I,bindAddress:I?"0.0.0.0":"127.0.0.1"}}function $s(e){if(!e.enabled||!e.expose)return[];let a=[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)a.push(e.webmail.port);return[...new Set(a)].sort((r,n)=>r-n)}function Os(e){if(!e.enabled)return{};let a=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(a)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let n=e.accounts[0];if(n)r.MAIL_USERNAME=n.address,r.MAIL_PASSWORD=n.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function U(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class yo{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,a){return this.template.Resources[e]=a,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,a){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=a,this}addOutput(e,a){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=a,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,a=0){let r=" ".repeat(a),n="";for(let[i,o]of Object.entries(e)){if(o===null||o===void 0)continue;if(typeof o==="object"&&!Array.isArray(o))n+=`${r}${i}:
|
|
13
|
+
`}function ya(e){return Object.keys(e).sort().map((a)=>a.toLowerCase()).join(";")}function pt(e){let a=[];return e.forEach((r,n)=>{a.push([kt(n),kt(r)])}),a.sort((r,n)=>{if(r[0]<n[0])return-1;if(r[0]>n[0])return 1;if(r[1]<n[1])return-1;if(r[1]>n[1])return 1;return 0}),a.map(([r,n])=>`${r}=${n}`).join("&")}function gt(e){return e.split("/").map((a)=>kt(a)).join("/")}function kt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(a)=>`%${a.charCodeAt(0).toString(16).toUpperCase()}`)}function je(e){if(!$e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return $e.createHash("sha256").update(e,"utf8").digest("hex")}function _e(e,a){if(!$e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return $e.createHmac("sha256",e).update(a,"utf8").digest()}async function ot(e){let a=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",a);return fa(new Uint8Array(r))}async function We(e,a){let r=new TextEncoder,n=typeof e==="string"?r.encode(e):e,i=r.encode(a),o=await crypto.subtle.importKey("raw",n.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),c=await crypto.subtle.sign("HMAC",o,i.buffer);return new Uint8Array(c)}function fa(e){return Array.from(e).map((a)=>a.toString(16).padStart(2,"0")).join("")}function Sa(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let d=_e(`AWS4${e}`,a),m=_e(d,r),p=_e(m,n);if(u=_e(p,"aws4_request"),o.size>=Ca){let g=o.keys().next().value;if(g)o.delete(g)}o.set(c,u)}return _e(u,i).toString("hex")}async function ba(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let m=await We(`AWS4${e}`,a),p=await We(m,r),g=await We(p,n);if(u=await We(g,"aws4_request"),o.size>=Ca){let h=o.keys().next().value;if(h)o.delete(h)}o.set(c,u)}let d=await We(u,i);return fa(d)}function Aa(e,a){return a.includes(e)}function ct(e,a,r){let n=a*Math.pow(2,e),i=Math.random()*0.3*n;return Math.min(n+i,r)}function lt(e){return new Promise((a)=>setTimeout(a,e))}async function ui(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u,d;for(let m=0;m<=r;m++){let p=oe(e),g={method:p.method,headers:p.headers};if(p.body)g.body=p.body;let h=new AbortController,y=setTimeout(()=>h.abort(),c);g.signal=h.signal;try{let f=await fetch(p.url,g);if(clearTimeout(y),d=f,f.ok)return f;if(m<r&&Aa(f.status,o)){let v=ct(m,n,i);await lt(v);continue}let b=await f.text();throw Error(`AWS API request failed (${f.status}): ${b}`)}catch(f){if(clearTimeout(y),u=f,f instanceof Error&&f.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(m<r&&!(f instanceof Error&&f.message.includes("AWS API request failed"))){let b=ct(m,n,i);await lt(b);continue}throw u}}throw u??Error("Request failed after retries")}async function Uu(e){return ui(e,{maxRetries:0})}async function Bu(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u;for(let d=0;d<=r;d++){let m=await Ga(e),p={method:m.method,headers:m.headers};if(m.body)p.body=m.body;let g=new AbortController,h=setTimeout(()=>g.abort(),c);p.signal=g.signal;try{let y=await fetch(m.url,p);if(clearTimeout(h),y.ok)return y;if(d<r&&Aa(y.status,o)){let b=ct(d,n,i);await lt(b);continue}let f=await y.text();throw Error(`AWS API request failed (${y.status}): ${f}`)}catch(y){if(clearTimeout(h),u=y,y instanceof Error&&y.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(d<r&&!(y instanceof Error&&y.message.includes("AWS API request failed"))){let f=ct(d,n,i);await lt(f);continue}throw u}}throw u??Error("Request failed after retries")}async function Ds(e){let a=await e.text(),r={},n=/<(\w+)>([^<]+)<\/\1>/g,i;while((i=n.exec(a))!==null){let[,o,c]=i;r[o]=c}return r}async function Fu(e){return await e.json()}function ju(){ye.clear()}function Vu(){return ye.size}function zu(){return $e!==void 0}function qu(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var $e,ye,Ca=100,Ta,ze=sr(async()=>{try{$e=await import("node:crypto")}catch{}ye=new Map,Ta={appstream2:"appstream",cloudhsmv2:"cloudhsm",email:"ses",marketplace:"aws-marketplace",mobile:"AWSMobileHubService",pinpoint:"mobiletargeting",queue:"sqs","git-codecommit":"codecommit","mturk-requester-sandbox":"mturk-requester","personalize-runtime":"personalize"}}),Hu={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}},Wu={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}}}},Ka=".ts-cloud",Ja="TS_CLOUD_STATE_DIR",Ot=null;function ks(e){Ot=e?.trim()||null}function xs(){return Boolean(process.env[Ja]?.trim()||Ot)}function ho(){return process.env[Ja]?.trim()||Ot||Ka}function Qe(...e){return ut(ho(),...e)}function A(e,...a){let r=ho();return $t(r)?ut(r,...a):ut(e,r,...a)}function _s(e,a=process.cwd()){let r=(i,o)=>{let c=ur(i,o);return c===""||!c.startsWith("..")&&!$t(c)},n=$t(e)?e:ut(a,e);return r(A(a),n)}function Xa(e){let a=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((n)=>n?.app!=null);return{server:a,serverless:r}}function V(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:a}=Xa(e);return a?"serverless":"server"}function wr(e){let{server:a,serverless:r}=Xa(e);if(a&&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&&!a)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&a&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function C(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function dr(e){return typeof e==="object"&&e!==null?e:{}}function Zl(e){return e===!0||typeof e==="object"&&e!==null}function mr(e,a){let r=a?e.environments?.[a]:void 0;if(r?.domain)return r.domain;let n=Object.values(e.sites??{}),i=e.sites?.main?.domain??n.find((o)=>o.domain)?.domain;if(i)return i;return`${e.project?.slug??"app"}.local`}function pr(e){let a=e.indexOf(".");return a>0?e.slice(a+1):void 0}function pi(e,a={}){let r=e.infrastructure?.compute?.managedServices?.mail,n=dr(r),i=a.environmentType??(a.environment?e.environments?.[a.environment]?.type:void 0),o=n.mode??(i==="production"?"server":"catcher"),c=o==="server",u=mr(e,a.environment),d=n.hostname??(c?`mail.${u}`:"localhost"),m=n.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=n.tls??{},h=g.enabled??c,y=!!(g.certPath&&g.keyPath),f=(n.accounts??[]).map((L)=>({address:L.address,password:L.password})),b=typeof n.dkim==="object"&&n.dkim!==null?n.dkim:{},v=n.dkim===!1?!1:n.dkim===!0||c,P=typeof n.webmail==="object"&&n.webmail!==null?n.webmail:{},R=n.webmail===!1?!1:P.enabled??!0,T=n.spam??{},N=n.delivery??(c?"direct":"none"),I=n.expose??c,k=pr(d),x=[...new Set([d,...k?[k]:[],...n.domains??[]])];return{enabled:Zl(r),mode:o,version:n.version,hostname:d,domains:x,ports:p,tls:{enabled:h,acme:h&&!y&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(h&&c),acmeEmail:g.acmeEmail??f[0]?.address},dkim:{enabled:v,selector:b.selector??"default",rotate:b.rotate??!1,rotateIntervalDays:b.rotateIntervalDays??90},webmail:{enabled:R,port:P.port??p.webmail,domain:P.domain},delivery:N,sesRegion:n.sesRegion??"us-east-1",accounts:f,storagePath:n.storagePath??"/var/lib/mail",maxMessageSize:n.maxMessageSize??26214400,spam:{enabled:T.enabled??c,enforce:T.enforce??!1,junkScore:T.junkScore??5,rejectScore:T.rejectScore??12,dnsbl:T.dnsbl??c,greylist:T.greylist??!1},webhookUrl:n.webhookUrl,expose:I,bindAddress:I?"0.0.0.0":"127.0.0.1"}}function $s(e){if(!e.enabled||!e.expose)return[];let a=[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)a.push(e.webmail.port);return[...new Set(a)].sort((r,n)=>r-n)}function Os(e){if(!e.enabled)return{};let a=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(a)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let n=e.accounts[0];if(n)r.MAIL_USERNAME=n.address,r.MAIL_PASSWORD=n.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function U(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class yo{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,a){return this.template.Resources[e]=a,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,a){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=a,this}addOutput(e,a){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=a,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,a=0){let r=" ".repeat(a),n="";for(let[i,o]of Object.entries(e)){if(o===null||o===void 0)continue;if(typeof o==="object"&&!Array.isArray(o))n+=`${r}${i}:
|
|
14
14
|
${this.convertToYAML(o,a+1)}`;else if(Array.isArray(o)){n+=`${r}${i}:
|
|
15
15
|
`;for(let c of o)if(typeof c==="object")n+=`${r} -
|
|
16
16
|
${this.convertToYAML(c,a+2)}`;else n+=`${r} - ${c}
|
|
@@ -103,7 +103,7 @@ echo "Image: $IMAGE_URI:${n}"
|
|
|
103
103
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
|
104
104
|
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
|
|
105
105
|
${JSON.stringify(a,null,2).replace(/"/g,"").replace(/,\n/g,`
|
|
106
|
-
`)}`}};static DockerfileTemplates={bunServer:(e,a=3000)=>vt.generateBunDockerfile({serverPath:e,port:a}),bunWithBuild:(e,a,r=3000)=>vt.generateBunDockerfile({serverPath:e,port:r,buildCommands:[a]}),bunFullStack:(e,a=3000)=>vt.generateBunDockerfile({serverPath:e,port:a,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,a=3000)=>vt.generateBunDockerfile({serverPath:e,port:a,healthCheckEndpoint:"/api/health"})}}class
|
|
106
|
+
`)}`}};static DockerfileTemplates={bunServer:(e,a=3000)=>vt.generateBunDockerfile({serverPath:e,port:a}),bunWithBuild:(e,a,r=3000)=>vt.generateBunDockerfile({serverPath:e,port:r,buildCommands:[a]}),bunFullStack:(e,a=3000)=>vt.generateBunDockerfile({serverPath:e,port:a,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,a=3000)=>vt.generateBunDockerfile({serverPath:e,port:a,healthCheckEndpoint:"/api/health"})}}class Ye{static createDistribution(e){let{slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p}=e,g=l({slug:a,environment:r,resourceType:"cdn"}),h=s(g),y={Id:"DefaultOrigin",DomainName:n.domainName,OriginPath:n.originPath||""},f;if(n.type==="s3"){let v=`${h}OAC`;f={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${g}-oac`,Description:`Origin Access Control for ${g}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},y.OriginAccessControlId=w.Ref(v)}else if(n.type==="alb"||n.type==="custom")y.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${g}`,DefaultRootObject:"index.html",Origins:[y],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(i&&o)b.Properties.DistributionConfig.Aliases=[i],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)b.Properties.DistributionConfig.CustomErrorResponses=c.map((v)=>({ErrorCode:v.errorCode,ResponseCode:v.responseCode,ResponsePagePath:v.responsePagePath}));if(d&&d.length>0)b.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((v)=>({EventType:v.event,LambdaFunctionARN:v.functionArn}));return{distribution:b,originAccessControl:f,logicalId:h}}static setCustomDomain(e,a,r){return e.Properties.DistributionConfig.Aliases=[a],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,a){return e.Properties.DistributionConfig.CustomErrorResponses=a.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,a,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:a,LambdaFunctionARN:r}),e}static setCachePolicy(e,a){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${a.default||86400}s)`,e}static createSpaDistribution(e){return Ye.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:a,environment:r}=e,n=l({slug:a,environment:r,resourceType:"edge-docs"}),i=s(n),o=s(`${n}-role`),c=s(`${n}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${n}-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=`
|
|
107
107
|
'use strict';
|
|
108
108
|
|
|
109
109
|
exports.handler = async (event) => {
|
|
@@ -136,7 +136,7 @@ exports.handler = async (event) => {
|
|
|
136
136
|
|
|
137
137
|
return request;
|
|
138
138
|
};
|
|
139
|
-
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:n,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:w.GetAtt(o,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:i,roleLogicalId:o,versionLogicalId:c}}static createDocsDistribution(e){let{slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,lambdaEdgeFunctionArn:c}=e,u=
|
|
139
|
+
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:n,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:w.GetAtt(o,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:i,roleLogicalId:o,versionLogicalId:c}}static createDocsDistribution(e){let{slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,lambdaEdgeFunctionArn:c}=e,u=Ye.createDistribution({slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,comment:`Docs CDN for ${a}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(c)Ye.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:a,environment:r,albDomainName:n,customDomain:i,certificateArn:o,pathPattern:c="/api/*",forwardHeaders:u=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:d="all",whitelistedCookies:m,customOriginHeaders:p={}}=e,g=l({slug:a,environment:r,resourceType:"cdn-api"}),h=s(g),y=Object.entries(p).map(([P,R])=>({HeaderName:P,HeaderValue:R})),f={Id:"ALBOrigin",DomainName:n,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(y.length>0)f.OriginCustomHeaders=y;let b={Forward:d};if(d==="whitelist"&&m)b.WhitelistedNames=m;let v={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${g}`,Origins:[f],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:b}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(i&&o)v.Properties.DistributionConfig.Aliases=[i],v.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:v,logicalId:h}}static createMultiOriginDistribution(e){let{slug:a,environment:r,s3BucketDomainName:n,albDomainName:i,apiPathPattern:o="/api/*",customDomain:c,certificateArn:u,customOriginHeaders:d={}}=e,m=l({slug:a,environment:r,resourceType:"cdn"}),p=s(m),g=`${p}OAC`,h={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${m}-oac`,Description:`Origin Access Control for ${m}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},y=Object.entries(d).map(([P,R])=>({HeaderName:P,HeaderValue:R})),f={Id:"S3Origin",DomainName:n,OriginAccessControlId:w.Ref(g)},b={Id:"ALBOrigin",DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(y.length>0)b.OriginCustomHeaders=y;let v={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${m}`,DefaultRootObject:"index.html",Origins:[f,b],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:o,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)v.Properties.DistributionConfig.Aliases=[c],v.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:u,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:v,originAccessControl:h,logicalId:p,oacLogicalId:g}}static addAlbOrigin(e,a){let{originId:r,domainName:n,pathPattern:i,customHeaders:o={},forwardHeaders:c=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:u={default:0,max:0,min:0}}=a,d=Object.entries(o).map(([p,g])=>({HeaderName:p,HeaderValue:g})),m={Id:r,DomainName:n,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:i,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,a,r,n){let i=e.Properties.DistributionConfig.Origins?.find((o)=>o.Id===a);if(i){if(!i.OriginCustomHeaders)i.OriginCustomHeaders=[];i.OriginCustomHeaders.push({HeaderName:r,HeaderValue:n})}return e}static EdgeFunctionTemplates={docsOriginRequest:`
|
|
140
140
|
'use strict';
|
|
141
141
|
exports.handler = async (event) => {
|
|
142
142
|
const request = event.Records[0].cf.request;
|
|
@@ -209,7 +209,7 @@ exports.handler = async (event) => {
|
|
|
209
209
|
|
|
210
210
|
return request;
|
|
211
211
|
};
|
|
212
|
-
`.trim()};static Config={ttl:(e)=>{let{min:a=0,max:r=86400,default:n=86400}=e;return{MinTTL:a,MaxTTL:r,DefaultTTL:n}},cookies:(e,a)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&a)r.WhitelistedNames=a;return r},allowedMethods:(e)=>{let a={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.GET_HEAD},cachedMethods:(e)=>{let a={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.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:a={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:n,allowedMethods:i="GET_HEAD",cachedMethods:o="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:a.min,MaxTTL:a.max,DefaultTTL:a.default,Compress:c,AllowedMethods:Xe.Config.allowedMethods(i),CachedMethods:Xe.Config.cachedMethods(o),ForwardedValues:{QueryString:u,Headers:d,Cookies:Xe.Config.cookies(r,n)}}}};static applyConfig(e,a){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(a.ttl)r.MinTTL=a.ttl.min,r.MaxTTL=a.ttl.max,r.DefaultTTL=a.ttl.default;if(a.compress!==void 0)r.Compress=a.compress;if(a.allowedMethods)r.AllowedMethods=Xe.Config.allowedMethods(a.allowedMethods);if(a.cachedMethods)r.CachedMethods=Xe.Config.cachedMethods(a.cachedMethods);if(a.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=Xe.Config.cookies(a.cookies,a.allowedCookies)}return e}}class Se{static createHostedZone(e){let{domain:a,slug:r,environment:n,comment:i}=e,o=l({slug:r,environment:n,resourceType:"hostedzone"}),c=s(`${o}-${a.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:a,HostedZoneConfig:{Comment:i||`Hosted zone for ${a}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:a,hostedZoneName:r,name:n,type:i,ttl:o,values:c,aliasTarget:u}=e,d=s(`record-${n.replace(/\./g,"")}-${i}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:n,Type:i}};if(a)m.Properties.HostedZoneId=a;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=o||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,a,r){return Se.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,a,r,n){return Se.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,a,r,n=300){return Se.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:n,values:[a]})}static createWwwRedirect(e,a){return Se.createRecord({hostedZoneId:a,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,a,r,n=300){return Se.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:n,values:a.map((i)=>`${i.priority} ${i.server}`)})}static createTxtRecord(e,a,r,n=300){return Se.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:n,values:[`"${a}"`]})}static createSpfRecord(e,a,r){return Se.createTxtRecord(e,a,r)}static createDmarcRecord(e,a,r,n){let i=`v=DMARC1; p=${a}; rua=mailto:${r}`;return Se.createTxtRecord(`_dmarc.${e}`,i,n)}static createS3WebsiteAlias(e,a,r,n){return Se.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,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,a){return`${e}.s3-website-${a}.amazonaws.com`}static createStoreRecord(e,a,r){return Se.createCname(`store.${e}`,a,r)}static createApiRecord(e,a,r){return Se.createCname(`api.${e}`,a,r)}static createDocsRecord(e,a,r){return Se.createCname(`docs.${e}`,a,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class B{static createCertificate(e){let{domain:a,subdomains:r=[],slug:n,environment:i,validationMethod:o="DNS",hostedZoneId:c}=e,u=l({slug:n,environment:i,resourceType:"acm"}),d=s(`${u}-${a.replace(/\./g,"")}`),m=[a];for(let g of r)if(g==="*")m.push(`*.${a}`);else m.push(`${g}.${a}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a,SubjectAlternativeNames:m,ValidationMethod:o}};if(o==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:a,slug:r,environment:n,enableRotation:i=!0,multiRegion:o=!1}=e,c=l({slug:r,environment:n,resourceType:"kms"}),u=s(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:w.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:a,Enabled:!0,EnableKeyRotation:i,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:o}},p=s(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${n}`,TargetKeyId:w.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",defaultAction:i="allow"}=e,o=l({slug:a,environment:r,resourceType:"waf"}),c=s(o);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:o,Scope:n,DefaultAction:i==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${a} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${o}-metric`}}},logicalId:c}}static setRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockCountries(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{GeoMatchStatement:{CountryCodes:a.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockIpAddresses(e,a,r,n){let i=l({slug:r,environment:n,resourceType:"ipset"}),o=s(`${i}-${a.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${i}-${a.name}`,Scope:e.Properties.Scope,IPAddressVersion:a.ipVersion||"IPV4",Addresses:a.ipAddresses,Description:`Blocked IPs for ${a.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{IPSetReferenceStatement:{Arn:w.GetAtt(o,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:o}}static addManagedRules(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:a.vendorName,Name:a.ruleName}};if(a.excludedRules&&a.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=a.excludedRules.map((n)=>({Name:n}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.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,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r=a.paths.map((n)=>({SearchString:n,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((n)=>({ByteMatchStatement:n}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static setHeaderRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:a.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(a.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:a.headerValue,FieldToMatch:{SingleHeader:{Name:a.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static protectLoginEndpoint(e,a){let{loginPaths:r,priority:n,requestsPerMinute:i=10}=a;return B.setPathRateLimit(e,{name:"LoginRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static protectApiEndpoints(e,a){let{apiPaths:r,priority:n,requestsPerMinute:i=100}=a;return B.setPathRateLimit(e,{name:"ApiRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static createProtectedFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",enableBotControl:i=!1,enableRateLimiting:o=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=B.createFirewall({slug:a,environment:r,scope:n,defaultAction:"allow"}),m=0;if(u=B.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...B.ManagedRuleGroups.AmazonIpReputation}),u=B.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...B.ManagedRuleGroups.AnonymousIpList}),u=B.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...B.ManagedRuleGroups.CoreRuleSet}),u=B.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...B.ManagedRuleGroups.KnownBadInputs}),u=B.addManagedRules(u,{name:"AWSSQLi",priority:m++,...B.ManagedRuleGroups.SqlDatabase}),i)u=B.addManagedRules(u,{name:"AWSBotControl",priority:m++,...B.ManagedRuleGroups.BotControl});if(o)u=B.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}}class S{static createServer(e){let{slug:a,environment:r,instanceType:n="t3.micro",imageId:i="ami-0f3caa1cf4417e51b",keyName:o,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,h=l({slug:a,environment:r,resourceType:"ec2"}),y=s(h),f={Type:"AWS::EC2::Instance",Properties:{ImageId:i,InstanceType:n,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(o)f.Properties.KeyName=o;if(c)f.Properties.SecurityGroupIds=c;if(u)f.Properties.SubnetId=u;if(d)f.Properties.UserData=w.Base64(d);return f.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:f,logicalId:y}}static createSecurityGroup(e){let{slug:a,environment:r,vpcId:n,description:i,ingress:o=[],egress:c=[]}=e,u=l({slug:a,environment:r,resourceType:"sg"}),d=s(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:i||`Security group for ${a} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(n)m.Properties.VpcId=n;if(o.length>0)m.Properties.SecurityGroupIngress=o.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,a,r){return S.createSecurityGroup({slug:e,environment:a,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:a,environment:r,scheme:n="internet-facing",subnets:i,securityGroups:o,type:c="application"}=e,u=l({slug:a,environment:r,resourceType:"alb"}),d=s(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:n,Type:c,Subnets:i,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o)m.Properties.SecurityGroups=o;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:a,environment:r,port:n,protocol:i="HTTP",vpcId:o,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,h=l({slug:a,environment:r,resourceType:"tg"}),y=s(h);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:h,Port:n,Protocol:i,VpcId:o,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:i,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}},logicalId:y}}static createListener(e,a){let{port:r,protocol:n="HTTP",certificateArn:i,defaultTargetGroupArn:o}=a,c=s(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:w.Ref(e),Port:r,Protocol:n,DefaultActions:[{Type:"forward",TargetGroupArn:o}]}};if(n==="HTTPS"&&i)u.Properties.Certificates=[{CertificateArn:i}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,a){let r=l({slug:e,environment:a,resourceType:"ecs-cluster"}),n=s(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static createFargateService(e){let{slug:a,environment:r,image:n,cpu:i="256",memory:o="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:h,securityGroups:y,targetGroupArn:f}=e,{cluster:b,logicalId:v}=S.createEcsCluster(a,r),P=l({slug:a,environment:r,resourceType:"fargate"}),R=s(`${P}-execution-role`),T={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"]}},N=s(`${P}-task-role`),I={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},k=s(`${P}-task`),x={Type:"AWS::ECS::TaskDefinition",Properties:{Family:P,TaskRoleArn:w.GetAtt(N,"Arn"),ExecutionRoleArn:w.GetAtt(R,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:i,Memory:o,ContainerDefinitions:[{Name:a,Image:n,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([W,K])=>({Name:W,Value:K})),Secrets:m.map((W)=>({Name:W.name,ValueFrom:W.valueFrom}))}],Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(p)x.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)x.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":w.Ref("AWS::Region"),"awslogs-stream-prefix":a}};let L=s(`${P}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:P,Cluster:w.Ref(v),TaskDefinition:w.Ref(k),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:h,SecurityGroups:y,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(f)O.Properties.LoadBalancers=[{TargetGroupArn:f,ContainerName:a,ContainerPort:u}];return{cluster:b,taskDefinition:x,service:O,taskRole:I,executionRole:T,clusterLogicalId:v,taskDefinitionLogicalId:k,serviceLogicalId:L,taskRoleLogicalId:N,executionRoleLogicalId:R}}static createLambdaFunction(e){let{slug:a,environment:r,runtime:n,handler:i,code:o,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:a,environment:r,resourceType:"lambda"}),g=s(p),h=s(`${p}-role`),y={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)y.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let f={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:n,Role:w.GetAtt(h,"Arn"),Handler:i,Code:{...o.s3Bucket&&{S3Bucket:o.s3Bucket},...o.s3Key&&{S3Key:o.s3Key},...o.zipFile&&{ZipFile:o.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)f.Properties.Environment={Variables:d};if(m)f.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:f,role:y,logicalId:g,roleLogicalId:h}}static generateNodeServerUserData(e={}){let{nodeVersion:a="20",appRepo:r,environment:n={}}=e,i=Object.entries(n).map(([o,c])=>`echo "export ${o}='${c}'" >> /etc/environment`).join(`
|
|
212
|
+
`.trim()};static Config={ttl:(e)=>{let{min:a=0,max:r=86400,default:n=86400}=e;return{MinTTL:a,MaxTTL:r,DefaultTTL:n}},cookies:(e,a)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&a)r.WhitelistedNames=a;return r},allowedMethods:(e)=>{let a={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.GET_HEAD},cachedMethods:(e)=>{let a={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.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:a={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:n,allowedMethods:i="GET_HEAD",cachedMethods:o="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:a.min,MaxTTL:a.max,DefaultTTL:a.default,Compress:c,AllowedMethods:Ye.Config.allowedMethods(i),CachedMethods:Ye.Config.cachedMethods(o),ForwardedValues:{QueryString:u,Headers:d,Cookies:Ye.Config.cookies(r,n)}}}};static applyConfig(e,a){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(a.ttl)r.MinTTL=a.ttl.min,r.MaxTTL=a.ttl.max,r.DefaultTTL=a.ttl.default;if(a.compress!==void 0)r.Compress=a.compress;if(a.allowedMethods)r.AllowedMethods=Ye.Config.allowedMethods(a.allowedMethods);if(a.cachedMethods)r.CachedMethods=Ye.Config.cachedMethods(a.cachedMethods);if(a.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=Ye.Config.cookies(a.cookies,a.allowedCookies)}return e}}class Se{static createHostedZone(e){let{domain:a,slug:r,environment:n,comment:i}=e,o=l({slug:r,environment:n,resourceType:"hostedzone"}),c=s(`${o}-${a.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:a,HostedZoneConfig:{Comment:i||`Hosted zone for ${a}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:a,hostedZoneName:r,name:n,type:i,ttl:o,values:c,aliasTarget:u}=e,d=s(`record-${n.replace(/\./g,"")}-${i}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:n,Type:i}};if(a)m.Properties.HostedZoneId=a;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=o||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,a,r){return Se.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,a,r,n){return Se.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,a,r,n=300){return Se.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:n,values:[a]})}static createWwwRedirect(e,a){return Se.createRecord({hostedZoneId:a,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,a,r,n=300){return Se.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:n,values:a.map((i)=>`${i.priority} ${i.server}`)})}static createTxtRecord(e,a,r,n=300){return Se.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:n,values:[`"${a}"`]})}static createSpfRecord(e,a,r){return Se.createTxtRecord(e,a,r)}static createDmarcRecord(e,a,r,n){let i=`v=DMARC1; p=${a}; rua=mailto:${r}`;return Se.createTxtRecord(`_dmarc.${e}`,i,n)}static createS3WebsiteAlias(e,a,r,n){return Se.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,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,a){return`${e}.s3-website-${a}.amazonaws.com`}static createStoreRecord(e,a,r){return Se.createCname(`store.${e}`,a,r)}static createApiRecord(e,a,r){return Se.createCname(`api.${e}`,a,r)}static createDocsRecord(e,a,r){return Se.createCname(`docs.${e}`,a,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class B{static createCertificate(e){let{domain:a,subdomains:r=[],slug:n,environment:i,validationMethod:o="DNS",hostedZoneId:c}=e,u=l({slug:n,environment:i,resourceType:"acm"}),d=s(`${u}-${a.replace(/\./g,"")}`),m=[a];for(let g of r)if(g==="*")m.push(`*.${a}`);else m.push(`${g}.${a}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a,SubjectAlternativeNames:m,ValidationMethod:o}};if(o==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:a,slug:r,environment:n,enableRotation:i=!0,multiRegion:o=!1}=e,c=l({slug:r,environment:n,resourceType:"kms"}),u=s(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:w.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:a,Enabled:!0,EnableKeyRotation:i,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:o}},p=s(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${n}`,TargetKeyId:w.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",defaultAction:i="allow"}=e,o=l({slug:a,environment:r,resourceType:"waf"}),c=s(o);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:o,Scope:n,DefaultAction:i==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${a} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${o}-metric`}}},logicalId:c}}static setRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockCountries(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{GeoMatchStatement:{CountryCodes:a.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockIpAddresses(e,a,r,n){let i=l({slug:r,environment:n,resourceType:"ipset"}),o=s(`${i}-${a.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${i}-${a.name}`,Scope:e.Properties.Scope,IPAddressVersion:a.ipVersion||"IPV4",Addresses:a.ipAddresses,Description:`Blocked IPs for ${a.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{IPSetReferenceStatement:{Arn:w.GetAtt(o,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:o}}static addManagedRules(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:a.vendorName,Name:a.ruleName}};if(a.excludedRules&&a.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=a.excludedRules.map((n)=>({Name:n}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.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,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r=a.paths.map((n)=>({SearchString:n,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((n)=>({ByteMatchStatement:n}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static setHeaderRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:a.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(a.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:a.headerValue,FieldToMatch:{SingleHeader:{Name:a.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static protectLoginEndpoint(e,a){let{loginPaths:r,priority:n,requestsPerMinute:i=10}=a;return B.setPathRateLimit(e,{name:"LoginRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static protectApiEndpoints(e,a){let{apiPaths:r,priority:n,requestsPerMinute:i=100}=a;return B.setPathRateLimit(e,{name:"ApiRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static createProtectedFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",enableBotControl:i=!1,enableRateLimiting:o=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=B.createFirewall({slug:a,environment:r,scope:n,defaultAction:"allow"}),m=0;if(u=B.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...B.ManagedRuleGroups.AmazonIpReputation}),u=B.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...B.ManagedRuleGroups.AnonymousIpList}),u=B.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...B.ManagedRuleGroups.CoreRuleSet}),u=B.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...B.ManagedRuleGroups.KnownBadInputs}),u=B.addManagedRules(u,{name:"AWSSQLi",priority:m++,...B.ManagedRuleGroups.SqlDatabase}),i)u=B.addManagedRules(u,{name:"AWSBotControl",priority:m++,...B.ManagedRuleGroups.BotControl});if(o)u=B.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}}class S{static createServer(e){let{slug:a,environment:r,instanceType:n="t3.micro",imageId:i="ami-0f3caa1cf4417e51b",keyName:o,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,h=l({slug:a,environment:r,resourceType:"ec2"}),y=s(h),f={Type:"AWS::EC2::Instance",Properties:{ImageId:i,InstanceType:n,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(o)f.Properties.KeyName=o;if(c)f.Properties.SecurityGroupIds=c;if(u)f.Properties.SubnetId=u;if(d)f.Properties.UserData=w.Base64(d);return f.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:f,logicalId:y}}static createSecurityGroup(e){let{slug:a,environment:r,vpcId:n,description:i,ingress:o=[],egress:c=[]}=e,u=l({slug:a,environment:r,resourceType:"sg"}),d=s(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:i||`Security group for ${a} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(n)m.Properties.VpcId=n;if(o.length>0)m.Properties.SecurityGroupIngress=o.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,a,r){return S.createSecurityGroup({slug:e,environment:a,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:a,environment:r,scheme:n="internet-facing",subnets:i,securityGroups:o,type:c="application"}=e,u=l({slug:a,environment:r,resourceType:"alb"}),d=s(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:n,Type:c,Subnets:i,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o)m.Properties.SecurityGroups=o;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:a,environment:r,port:n,protocol:i="HTTP",vpcId:o,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,h=l({slug:a,environment:r,resourceType:"tg"}),y=s(h);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:h,Port:n,Protocol:i,VpcId:o,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:i,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}},logicalId:y}}static createListener(e,a){let{port:r,protocol:n="HTTP",certificateArn:i,defaultTargetGroupArn:o}=a,c=s(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:w.Ref(e),Port:r,Protocol:n,DefaultActions:[{Type:"forward",TargetGroupArn:o}]}};if(n==="HTTPS"&&i)u.Properties.Certificates=[{CertificateArn:i}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,a){let r=l({slug:e,environment:a,resourceType:"ecs-cluster"}),n=s(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static createFargateService(e){let{slug:a,environment:r,image:n,cpu:i="256",memory:o="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:h,securityGroups:y,targetGroupArn:f}=e,{cluster:b,logicalId:v}=S.createEcsCluster(a,r),P=l({slug:a,environment:r,resourceType:"fargate"}),R=s(`${P}-execution-role`),T={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"]}},N=s(`${P}-task-role`),I={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},k=s(`${P}-task`),x={Type:"AWS::ECS::TaskDefinition",Properties:{Family:P,TaskRoleArn:w.GetAtt(N,"Arn"),ExecutionRoleArn:w.GetAtt(R,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:i,Memory:o,ContainerDefinitions:[{Name:a,Image:n,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([W,K])=>({Name:W,Value:K})),Secrets:m.map((W)=>({Name:W.name,ValueFrom:W.valueFrom}))}],Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(p)x.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)x.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":w.Ref("AWS::Region"),"awslogs-stream-prefix":a}};let L=s(`${P}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:P,Cluster:w.Ref(v),TaskDefinition:w.Ref(k),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:h,SecurityGroups:y,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(f)O.Properties.LoadBalancers=[{TargetGroupArn:f,ContainerName:a,ContainerPort:u}];return{cluster:b,taskDefinition:x,service:O,taskRole:I,executionRole:T,clusterLogicalId:v,taskDefinitionLogicalId:k,serviceLogicalId:L,taskRoleLogicalId:N,executionRoleLogicalId:R}}static createLambdaFunction(e){let{slug:a,environment:r,runtime:n,handler:i,code:o,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:a,environment:r,resourceType:"lambda"}),g=s(p),h=s(`${p}-role`),y={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)y.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let f={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:n,Role:w.GetAtt(h,"Arn"),Handler:i,Code:{...o.s3Bucket&&{S3Bucket:o.s3Bucket},...o.s3Key&&{S3Key:o.s3Key},...o.zipFile&&{ZipFile:o.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)f.Properties.Environment={Variables:d};if(m)f.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:f,role:y,logicalId:g,roleLogicalId:h}}static generateNodeServerUserData(e={}){let{nodeVersion:a="20",appRepo:r,environment:n={}}=e,i=Object.entries(n).map(([o,c])=>`echo "export ${o}='${c}'" >> /etc/environment`).join(`
|
|
213
213
|
`);return`#!/bin/bash
|
|
214
214
|
# Update system
|
|
215
215
|
yum update -y
|
|
@@ -620,7 +620,7 @@ echo "Redis server setup complete!"
|
|
|
620
620
|
- Using a single NAT Gateway (singleNatGateway: true)
|
|
621
621
|
- Using NAT Instances instead (cheaper but requires management)
|
|
622
622
|
- Disabling NAT entirely for isolated private subnets
|
|
623
|
-
`}class Qe{static createFileSystem(e){let{slug:a,environment:r,encrypted:n=!0,kmsKeyId:i,performanceMode:o="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:a,environment:r,resourceType:"efs"}),p=s(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:n,PerformanceMode:o,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(i)g.Properties.KmsKeyId=i;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,a){let{slug:r,environment:n,subnetId:i,securityGroups:o,ipAddress:c}=a,u=l({slug:r,environment:n,resourceType:"efs-mt"}),d=s(`${u}-${i}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:w.Ref(e),SubnetId:i,SecurityGroups:o}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,a){let{slug:r,environment:n,path:i="/",uid:o="1000",gid:c="1000",permissions:u="755"}=a,d=l({slug:r,environment:n,resourceType:"efs-ap"}),m=s(`${d}-${i.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:w.Ref(e),PosixUser:{Uid:o,Gid:c},RootDirectory:{Path:i,CreationInfo:{OwnerUid:o,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${i}`},{Key:"Environment",Value:n}]}},logicalId:m}}static setLifecyclePolicy(e,a){let{transitionToIA:r,transitionToPrimary:n=!1}=a;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let i=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:i})}if(n)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,a){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=a,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:a,environment:r,vpcId:n,sourceSecurityGroupIds:i=[],sourceCidrBlocks:o=[],description:c}=e,u=l({slug:a,environment:r,resourceType:"efs-sg"}),d=s(u),m=[];for(let p of i)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:p,Description:"NFS from security group"});for(let p of o)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:p,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${a} ${r}`,VpcId:n,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,a){let{slug:r,environment:n,subnetIds:i,securityGroupId:o}=a,c=[],u=[];for(let d=0;d<i.length;d++){let m=i[d],p=l({slug:r,environment:n,resourceType:"efs-mt"}),g=s(`${p}-az${d+1}`),h={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:w.Ref(e),SubnetId:m,SecurityGroups:[o]}};c.push(h),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:a,environment:r,vpcId:n,subnetIds:i,sourceSecurityGroupIds:o=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:h,logicalId:y}=Qe.createFileSystem({slug:a,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)Qe.setLifecyclePolicy(h,{transitionToIA:p,transitionToPrimary:!0});g[y]=h;let{securityGroup:f,logicalId:b}=Qe.createEfsSecurityGroup({slug:a,environment:r,vpcId:n,sourceSecurityGroupIds:o});g[b]=f;let{mountTargets:v,logicalIds:P}=Qe.createMultiAzMountTargets(y,{slug:a,environment:r,subnetIds:i,securityGroupId:w.Ref(b)});for(let R=0;R<v.length;R++)g[P[R]]=v[R];return{resources:g,outputs:{fileSystemId:y,securityGroupId:b,mountTargetIds:P}}}}class D{static verifyDomain(e){let{domain:a,slug:r,environment:n,enableDkim:i=!0,dkimKeyLength:o="RSA_2048_BIT"}=e,c=l({slug:r,environment:n,resourceType:"ses-identity"}),u=s(`${c}-${a.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:a,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(i)d.Properties.DkimSigningAttributes={NextSigningKeyLength:o};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,a,r){let n=[];for(let i=0;i<a.length;i++){let o=a[i],c=s(`dkim-${e.replace(/\./g,"")}-${i+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${o}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${o}.dkim.amazonses.com`]}};n.push({record:u,logicalId:c})}return n}static createConfigurationSet(e){let{slug:a,environment:r,name:n,reputationMetrics:i=!0,sendingEnabled:o=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=n||l({slug:a,environment:r,resourceType:"ses-config"}),m=s(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:i},SendingOptions:{SendingEnabled:o},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:a,environment:r,name:n}=e,i=n||l({slug:a,environment:r,resourceType:"ses-ruleset"}),o=s(i);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:i}},logicalId:o}}static createReceiptRule(e,a){let{slug:r,environment:n,ruleSetName:i,recipients:o,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=a,h=l({slug:r,environment:n,resourceType:"ses-rule"}),y=s(h),f=[];if(m)f.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)f.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)f.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:i,Rule:{Name:h,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:o,Actions:f.length>0?f:void 0}}},logicalId:y}}static createMxRecord(e,a,r){let n=s(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:n}}static createVerificationRecord(e,a,r){let n=s(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${a}"`]}},logicalId:n}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,a,r){let{includeDomains:n=[],softFail:i=!1}=r||{},o=s(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let u of n)c+=` include:${u}`;return c+=i?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:o}}static createDmarcRecord(e,a,r){let{policy:n="none",subdomainPolicy:i,percentage:o=100,reportingEmail:c,forensicEmail:u}=r||{},d=s(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${n}; pct=${o}`;if(i)m+=`; sp=${i}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3KeyPrefix:o="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:h}=D.createReceiptRuleSet({slug:a,environment:r});p[h]=g;let{receiptRule:y,logicalId:f}=D.createReceiptRule(h,{slug:a,environment:r,ruleSetName:g.Properties.RuleSetName||`${a}-${r}-receipt-rule-set`,recipients:[n],s3Action:{bucketName:i,prefix:o},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[f]=y;let{record:b,logicalId:v}=D.createMxRecord(n,u,c);return p[v]=b,{resources:p,outputs:{ruleSetLogicalId:h,ruleLogicalId:f,mxRecordLogicalId:v}}}static createCompleteDomainSetup(e){let{slug:a,environment:r,domain:n,hostedZoneId:i,region:o,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=D.verifyDomain({domain:n,slug:a,environment:r});m[g]=p;let{configurationSet:h,logicalId:y}=D.createConfigurationSet({slug:a,environment:r});m[y]=h;let{record:f,logicalId:b}=D.createSpfRecord(n,i);m[b]=f;let{record:v,logicalId:P}=D.createDmarcRecord(n,i,{policy:"none",reportingEmail:d||`dmarc-reports@${n}`});if(m[P]=v,c&&u){let R=D.createInboundEmailSetup({slug:a,environment:r,domain:n,s3BucketName:u,region:o,hostedZoneId:i});Object.assign(m,R.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:y}}}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 D.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:a,environment:r,s3BucketArn:n,sesIdentityArn:i}=e,o=l({slug:a,environment:r,resourceType:"email-lambda-role"}),c=s(o),u=s(`${o}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:o,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:o},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[n,`${n}/*`]}];if(i)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:i});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[w.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,domain:i,configurationSetName:o,timeout:c=30,memorySize:u=256}=e,d=l({slug:a,environment:r,resourceType:"outbound-email"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:i,CONFIGURATION_SET:o||""}},Code:{ZipFile:D.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,organizedPrefix:o="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"inbound-email"}),m=s(d),p=s(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,ORGANIZED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},h={Type:"AWS::Lambda::Permission",Properties:{FunctionName:w.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:w.Ref("AWS::AccountId")}};return{function:g,permission:h,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,convertedPrefix:o="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"email-conversion"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,CONVERTED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:a,prefix:r="inbound/",suffix:n,events:i}=e,o=i??["s3:ObjectCreated:*"],c={};if(r||n){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(n)c.S3Key.Rules.push({Name:"suffix",Value:n})}return{notificationConfiguration:{LambdaConfigurations:[{Event:o[0],Function:a,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:a,environment:r,lambdaLogicalId:n,s3BucketArn:i}=e,o=l({slug:a,environment:r,resourceType:"s3-lambda-permission"}),c=s(o);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:w.Ref(n),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:i}},logicalId:c}}static createEmailProcessingStack(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3BucketArn:o,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:h,policyLogicalId:y}=D.createEmailLambdaRole({slug:a,environment:r,s3BucketArn:o,sesIdentityArn:`arn:aws:ses:*:*:identity/${n}`});m[h]=p,m[y]=g;let{function:f,logicalId:b}=D.createOutboundEmailLambda({slug:a,environment:r,roleArn:w.GetAtt(h,"Arn"),domain:n,configurationSetName:c});m[b]=f;let v={roleLogicalId:h,outboundLambdaLogicalId:b};if(u){let{function:P,permission:R,logicalId:T,permissionLogicalId:N}=D.createInboundEmailLambda({slug:a,environment:r,roleArn:w.GetAtt(h,"Arn"),s3BucketName:i});m[T]=P,m[N]=R;let{permission:I,logicalId:k}=D.createS3LambdaPermission({slug:a,environment:r,lambdaLogicalId:T,s3BucketArn:o});m[k]=I,v.inboundLambdaLogicalId=T}if(d){let{function:P,logicalId:R}=D.createEmailConversionLambda({slug:a,environment:r,roleArn:w.GetAtt(h,"Arn"),s3BucketName:i});m[R]=P,v.conversionLambdaLogicalId=R}return{resources:m,outputs:v}}static LambdaCode={outboundEmail:`
|
|
623
|
+
`}class Ze{static createFileSystem(e){let{slug:a,environment:r,encrypted:n=!0,kmsKeyId:i,performanceMode:o="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:a,environment:r,resourceType:"efs"}),p=s(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:n,PerformanceMode:o,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(i)g.Properties.KmsKeyId=i;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,a){let{slug:r,environment:n,subnetId:i,securityGroups:o,ipAddress:c}=a,u=l({slug:r,environment:n,resourceType:"efs-mt"}),d=s(`${u}-${i}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:w.Ref(e),SubnetId:i,SecurityGroups:o}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,a){let{slug:r,environment:n,path:i="/",uid:o="1000",gid:c="1000",permissions:u="755"}=a,d=l({slug:r,environment:n,resourceType:"efs-ap"}),m=s(`${d}-${i.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:w.Ref(e),PosixUser:{Uid:o,Gid:c},RootDirectory:{Path:i,CreationInfo:{OwnerUid:o,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${i}`},{Key:"Environment",Value:n}]}},logicalId:m}}static setLifecyclePolicy(e,a){let{transitionToIA:r,transitionToPrimary:n=!1}=a;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let i=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:i})}if(n)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,a){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=a,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:a,environment:r,vpcId:n,sourceSecurityGroupIds:i=[],sourceCidrBlocks:o=[],description:c}=e,u=l({slug:a,environment:r,resourceType:"efs-sg"}),d=s(u),m=[];for(let p of i)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:p,Description:"NFS from security group"});for(let p of o)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:p,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${a} ${r}`,VpcId:n,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,a){let{slug:r,environment:n,subnetIds:i,securityGroupId:o}=a,c=[],u=[];for(let d=0;d<i.length;d++){let m=i[d],p=l({slug:r,environment:n,resourceType:"efs-mt"}),g=s(`${p}-az${d+1}`),h={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:w.Ref(e),SubnetId:m,SecurityGroups:[o]}};c.push(h),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:a,environment:r,vpcId:n,subnetIds:i,sourceSecurityGroupIds:o=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:h,logicalId:y}=Ze.createFileSystem({slug:a,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)Ze.setLifecyclePolicy(h,{transitionToIA:p,transitionToPrimary:!0});g[y]=h;let{securityGroup:f,logicalId:b}=Ze.createEfsSecurityGroup({slug:a,environment:r,vpcId:n,sourceSecurityGroupIds:o});g[b]=f;let{mountTargets:v,logicalIds:P}=Ze.createMultiAzMountTargets(y,{slug:a,environment:r,subnetIds:i,securityGroupId:w.Ref(b)});for(let R=0;R<v.length;R++)g[P[R]]=v[R];return{resources:g,outputs:{fileSystemId:y,securityGroupId:b,mountTargetIds:P}}}}class D{static verifyDomain(e){let{domain:a,slug:r,environment:n,enableDkim:i=!0,dkimKeyLength:o="RSA_2048_BIT"}=e,c=l({slug:r,environment:n,resourceType:"ses-identity"}),u=s(`${c}-${a.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:a,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(i)d.Properties.DkimSigningAttributes={NextSigningKeyLength:o};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,a,r){let n=[];for(let i=0;i<a.length;i++){let o=a[i],c=s(`dkim-${e.replace(/\./g,"")}-${i+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${o}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${o}.dkim.amazonses.com`]}};n.push({record:u,logicalId:c})}return n}static createConfigurationSet(e){let{slug:a,environment:r,name:n,reputationMetrics:i=!0,sendingEnabled:o=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=n||l({slug:a,environment:r,resourceType:"ses-config"}),m=s(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:i},SendingOptions:{SendingEnabled:o},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:a,environment:r,name:n}=e,i=n||l({slug:a,environment:r,resourceType:"ses-ruleset"}),o=s(i);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:i}},logicalId:o}}static createReceiptRule(e,a){let{slug:r,environment:n,ruleSetName:i,recipients:o,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=a,h=l({slug:r,environment:n,resourceType:"ses-rule"}),y=s(h),f=[];if(m)f.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)f.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)f.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:i,Rule:{Name:h,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:o,Actions:f.length>0?f:void 0}}},logicalId:y}}static createMxRecord(e,a,r){let n=s(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:n}}static createVerificationRecord(e,a,r){let n=s(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${a}"`]}},logicalId:n}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,a,r){let{includeDomains:n=[],softFail:i=!1}=r||{},o=s(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let u of n)c+=` include:${u}`;return c+=i?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:o}}static createDmarcRecord(e,a,r){let{policy:n="none",subdomainPolicy:i,percentage:o=100,reportingEmail:c,forensicEmail:u}=r||{},d=s(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${n}; pct=${o}`;if(i)m+=`; sp=${i}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3KeyPrefix:o="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:h}=D.createReceiptRuleSet({slug:a,environment:r});p[h]=g;let{receiptRule:y,logicalId:f}=D.createReceiptRule(h,{slug:a,environment:r,ruleSetName:g.Properties.RuleSetName||`${a}-${r}-receipt-rule-set`,recipients:[n],s3Action:{bucketName:i,prefix:o},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[f]=y;let{record:b,logicalId:v}=D.createMxRecord(n,u,c);return p[v]=b,{resources:p,outputs:{ruleSetLogicalId:h,ruleLogicalId:f,mxRecordLogicalId:v}}}static createCompleteDomainSetup(e){let{slug:a,environment:r,domain:n,hostedZoneId:i,region:o,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=D.verifyDomain({domain:n,slug:a,environment:r});m[g]=p;let{configurationSet:h,logicalId:y}=D.createConfigurationSet({slug:a,environment:r});m[y]=h;let{record:f,logicalId:b}=D.createSpfRecord(n,i);m[b]=f;let{record:v,logicalId:P}=D.createDmarcRecord(n,i,{policy:"none",reportingEmail:d||`dmarc-reports@${n}`});if(m[P]=v,c&&u){let R=D.createInboundEmailSetup({slug:a,environment:r,domain:n,s3BucketName:u,region:o,hostedZoneId:i});Object.assign(m,R.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:y}}}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 D.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:a,environment:r,s3BucketArn:n,sesIdentityArn:i}=e,o=l({slug:a,environment:r,resourceType:"email-lambda-role"}),c=s(o),u=s(`${o}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:o,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:o},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[n,`${n}/*`]}];if(i)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:i});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[w.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,domain:i,configurationSetName:o,timeout:c=30,memorySize:u=256}=e,d=l({slug:a,environment:r,resourceType:"outbound-email"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:i,CONFIGURATION_SET:o||""}},Code:{ZipFile:D.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,organizedPrefix:o="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"inbound-email"}),m=s(d),p=s(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,ORGANIZED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},h={Type:"AWS::Lambda::Permission",Properties:{FunctionName:w.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:w.Ref("AWS::AccountId")}};return{function:g,permission:h,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,convertedPrefix:o="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"email-conversion"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,CONVERTED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:a,prefix:r="inbound/",suffix:n,events:i}=e,o=i??["s3:ObjectCreated:*"],c={};if(r||n){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(n)c.S3Key.Rules.push({Name:"suffix",Value:n})}return{notificationConfiguration:{LambdaConfigurations:[{Event:o[0],Function:a,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:a,environment:r,lambdaLogicalId:n,s3BucketArn:i}=e,o=l({slug:a,environment:r,resourceType:"s3-lambda-permission"}),c=s(o);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:w.Ref(n),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:i}},logicalId:c}}static createEmailProcessingStack(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3BucketArn:o,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:h,policyLogicalId:y}=D.createEmailLambdaRole({slug:a,environment:r,s3BucketArn:o,sesIdentityArn:`arn:aws:ses:*:*:identity/${n}`});m[h]=p,m[y]=g;let{function:f,logicalId:b}=D.createOutboundEmailLambda({slug:a,environment:r,roleArn:w.GetAtt(h,"Arn"),domain:n,configurationSetName:c});m[b]=f;let v={roleLogicalId:h,outboundLambdaLogicalId:b};if(u){let{function:P,permission:R,logicalId:T,permissionLogicalId:N}=D.createInboundEmailLambda({slug:a,environment:r,roleArn:w.GetAtt(h,"Arn"),s3BucketName:i});m[T]=P,m[N]=R;let{permission:I,logicalId:k}=D.createS3LambdaPermission({slug:a,environment:r,lambdaLogicalId:T,s3BucketArn:o});m[k]=I,v.inboundLambdaLogicalId=T}if(d){let{function:P,logicalId:R}=D.createEmailConversionLambda({slug:a,environment:r,roleArn:w.GetAtt(h,"Arn"),s3BucketName:i});m[R]=P,v.conversionLambdaLogicalId=R}return{resources:m,outputs:v}}static LambdaCode={outboundEmail:`
|
|
624
624
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
625
625
|
const ses = new SESClient({});
|
|
626
626
|
|
|
@@ -1658,7 +1658,7 @@ catch (error) {
|
|
|
1658
1658
|
|
|
1659
1659
|
return { statusCode: 200, body: 'OK' };
|
|
1660
1660
|
};
|
|
1661
|
-
`;class Tt{static LambdaCode={incomingCall:Ea,voicemail:kr,missedCall:Dr};static createConnectInstance(e){let{slug:a,environment:r,instanceAlias:n,inboundCallsEnabled:i=!0,outboundCallsEnabled:o=!0}=e;return{[`${a}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:n,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:i,OutboundCalls:o,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((a)=>({Day:a.day,StartTime:{Hours:a.startHour,Minutes:a.startMinute},EndTime:{Hours:a.endHour,Minutes:a.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 a={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(a)}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:Tt.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:Tt.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:Tt.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 a={},r={};Object.assign(a,Tt.createPhoneLambdaRole({slug:e.slug})),Object.assign(a,Tt.createCallLogTable({slug:e.slug})),a[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},a[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let n={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},i={Ref:`${e.slug}PhoneNotificationTopic`},o={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(a,Tt.createIncomingCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(a,Tt.createVoicemailLambda({slug:e.slug,roleArn:n,voicemailBucket:c,notificationTopicArn:i,callLogTable:o,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(a,Tt.createMissedCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,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:a,outputs:r}}}class pe{static createQueue(e){let{slug:a,environment:r,name:n,delaySeconds:i=0,visibilityTimeout:o=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:h}=e,y=n||l({slug:a,environment:r,resourceType:"queue"}),f=m?`${y}.fifo`:y,b=s(y),v={Type:"AWS::SQS::Queue",Properties:{QueueName:f,DelaySeconds:i,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:o,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r}]}};if(m)v.Properties.FifoQueue=!0,v.Properties.ContentBasedDeduplication=p;if(g)if(h)v.Properties.KmsMasterKeyId=h;else v.Properties.SqsManagedSseEnabled=!0;return{queue:v,logicalId:b}}static createDeadLetterQueue(e,a){let{slug:r,environment:n,maxReceiveCount:i=3}=a,o=l({slug:r,environment:n,resourceType:"dlq"}),c=s(o),u={Type:"AWS::SQS::Queue",Properties:{QueueName:o,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:w.GetAtt(c,"Arn"),maxReceiveCount:i}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"schedule"}),d=s(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:o,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,a,r){let{slug:n,environment:i,name:o,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:h=!1,taskCount:y=1,containerOverrides:f}=r,b=o||l({slug:n,environment:i,resourceType:"ecs-schedule"}),v=s(b),P={Id:"1",Arn:m,RoleArn:a,EcsParameters:{TaskDefinitionArn:d,TaskCount:y,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:h?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(f&&f.length>0)P.Input=JSON.stringify({containerOverrides:f});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:b,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[P]}},logicalId:v}}static scheduleLambda(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,functionArn:u,input:d}=a,m=i||l({slug:r,environment:n,resourceType:"lambda-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,queueArn:u,messageGroupId:d}=a,m=i||l({slug:r,environment:n,resourceType:"sqs-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,a){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:a.id,Arn:a.arn};if(a.roleArn)r.RoleArn=a.roleArn;if(a.input)r.Input=JSON.stringify(a.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,a){return`rate(${e} ${a})`}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 a=e.toLowerCase().trim(),r=a.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,h=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:h})`}let n=a.match(/^every\s+(minute|hour|day)$/i);if(n)return`rate(1 ${n[1]})`;let i={"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(i[a])return i[a];let o=a.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(o){let m=parseInt(o[1],10),p=o[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=a.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=a.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return pe.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:a,handler:r,retries:n=3,backoff:i="exponential",backoffDelay:o=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:a,handler:r,retries:n,backoff:i,backoffDelay:o,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,a)=>{let{backoff:r,backoffDelay:n,maxDelay:i,jitter:o}=a,c;switch(r){case"linear":c=n*e;break;case"exponential":c=n*2**(e-1);break;case"fixed":default:c=n}if(c=Math.min(c,i||Number.MAX_SAFE_INTEGER),o){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:a,jobClass:r,jobData:n,environment:i={}}=e,o=[{name:"JOB_CLASS",value:r}];if(n)o.push({name:"JOB_DATA",value:JSON.stringify(n)});for(let[c,u]of Object.entries(i))o.push({name:c,value:u});return{name:a,command:["bun","run","app/Jobs/runner.ts"],environment:o}}static createScheduledJob(e){let{slug:a,environment:r,schedule:n,jobClass:i,jobData:o,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,h=pe.rateStringToExpression(n),y=pe.createJobContainerOverride({containerName:g,jobClass:i,jobData:o});return pe.scheduleEcsTask(h,p,{slug:a,environment:r,name:`${a}-${i.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${i}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[y]})}static QueuePresets={highThroughput:(e,a)=>pe.createQueue({slug:e,environment:a,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,a)=>pe.createQueue({slug:e,environment:a,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,a)=>pe.createQueue({slug:e,environment:a,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,a,r=60)=>pe.createQueue({slug:e,environment:a,delaySeconds:r})}}class Mt{static async discoverJobs(e){let{projectRoot:a,jobsPath:r="app/Jobs"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Mt.parseJobMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseJobMetadata(e,a,r){let n=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),i=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),o=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:a,path:r,schedule:n?.[1],handler:`${a}.handle`,enabled:i?.[1]!=="false",retries:o?parseInt(o[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:a,actionsPath:r="app/Actions"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Mt.parseActionMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseActionMetadata(e,a,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let n=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:a,path:r,handler:`${a}.handle`,description:n?.[1]}}static generateScheduledJobResources(e){let{slug:a,environment:r,jobs:n,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let h of n){if(!h.schedule||!h.enabled)continue;let{rule:y,logicalId:f}=pe.createScheduledJob({slug:a,environment:r,schedule:h.schedule,jobClass:h.name,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[f]=y,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1661
|
+
`;class Tt{static LambdaCode={incomingCall:Ea,voicemail:kr,missedCall:Dr};static createConnectInstance(e){let{slug:a,environment:r,instanceAlias:n,inboundCallsEnabled:i=!0,outboundCallsEnabled:o=!0}=e;return{[`${a}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:n,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:i,OutboundCalls:o,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((a)=>({Day:a.day,StartTime:{Hours:a.startHour,Minutes:a.startMinute},EndTime:{Hours:a.endHour,Minutes:a.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 a={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(a)}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:Tt.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:Tt.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:Tt.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 a={},r={};Object.assign(a,Tt.createPhoneLambdaRole({slug:e.slug})),Object.assign(a,Tt.createCallLogTable({slug:e.slug})),a[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},a[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let n={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},i={Ref:`${e.slug}PhoneNotificationTopic`},o={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(a,Tt.createIncomingCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(a,Tt.createVoicemailLambda({slug:e.slug,roleArn:n,voicemailBucket:c,notificationTopicArn:i,callLogTable:o,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(a,Tt.createMissedCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,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:a,outputs:r}}}class pe{static createQueue(e){let{slug:a,environment:r,name:n,delaySeconds:i=0,visibilityTimeout:o=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:h}=e,y=n||l({slug:a,environment:r,resourceType:"queue"}),f=m?`${y}.fifo`:y,b=s(y),v={Type:"AWS::SQS::Queue",Properties:{QueueName:f,DelaySeconds:i,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:o,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r}]}};if(m)v.Properties.FifoQueue=!0,v.Properties.ContentBasedDeduplication=p;if(g)if(h)v.Properties.KmsMasterKeyId=h;else v.Properties.SqsManagedSseEnabled=!0;return{queue:v,logicalId:b}}static createDeadLetterQueue(e,a){let{slug:r,environment:n,maxReceiveCount:i=3}=a,o=l({slug:r,environment:n,resourceType:"dlq"}),c=s(o),u={Type:"AWS::SQS::Queue",Properties:{QueueName:o,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:w.GetAtt(c,"Arn"),maxReceiveCount:i}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"schedule"}),d=s(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:o,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,a,r){let{slug:n,environment:i,name:o,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:h=!1,taskCount:y=1,containerOverrides:f}=r,b=o||l({slug:n,environment:i,resourceType:"ecs-schedule"}),v=s(b),P={Id:"1",Arn:m,RoleArn:a,EcsParameters:{TaskDefinitionArn:d,TaskCount:y,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:h?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(f&&f.length>0)P.Input=JSON.stringify({containerOverrides:f});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:b,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[P]}},logicalId:v}}static scheduleLambda(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,functionArn:u,input:d}=a,m=i||l({slug:r,environment:n,resourceType:"lambda-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,queueArn:u,messageGroupId:d}=a,m=i||l({slug:r,environment:n,resourceType:"sqs-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,a){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:a.id,Arn:a.arn};if(a.roleArn)r.RoleArn=a.roleArn;if(a.input)r.Input=JSON.stringify(a.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,a){return`rate(${e} ${a})`}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 a=e.toLowerCase().trim(),r=a.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,h=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:h})`}let n=a.match(/^every\s+(minute|hour|day)$/i);if(n)return`rate(1 ${n[1]})`;let i={"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(i[a])return i[a];let o=a.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(o){let m=parseInt(o[1],10),p=o[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=a.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=a.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return pe.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:a,handler:r,retries:n=3,backoff:i="exponential",backoffDelay:o=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:a,handler:r,retries:n,backoff:i,backoffDelay:o,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,a)=>{let{backoff:r,backoffDelay:n,maxDelay:i,jitter:o}=a,c;switch(r){case"linear":c=n*e;break;case"exponential":c=n*2**(e-1);break;case"fixed":default:c=n}if(c=Math.min(c,i||Number.MAX_SAFE_INTEGER),o){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:a,jobClass:r,jobData:n,environment:i={}}=e,o=[{name:"JOB_CLASS",value:r}];if(n)o.push({name:"JOB_DATA",value:JSON.stringify(n)});for(let[c,u]of Object.entries(i))o.push({name:c,value:u});return{name:a,command:["bun","run","app/Jobs/runner.ts"],environment:o}}static createScheduledJob(e){let{slug:a,environment:r,schedule:n,jobClass:i,jobData:o,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,h=pe.rateStringToExpression(n),y=pe.createJobContainerOverride({containerName:g,jobClass:i,jobData:o});return pe.scheduleEcsTask(h,p,{slug:a,environment:r,name:`${a}-${i.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${i}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[y]})}static QueuePresets={highThroughput:(e,a)=>pe.createQueue({slug:e,environment:a,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,a)=>pe.createQueue({slug:e,environment:a,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,a)=>pe.createQueue({slug:e,environment:a,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,a,r=60)=>pe.createQueue({slug:e,environment:a,delaySeconds:r})}}class Ut{static async discoverJobs(e){let{projectRoot:a,jobsPath:r="app/Jobs"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Ut.parseJobMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseJobMetadata(e,a,r){let n=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),i=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),o=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:a,path:r,schedule:n?.[1],handler:`${a}.handle`,enabled:i?.[1]!=="false",retries:o?parseInt(o[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:a,actionsPath:r="app/Actions"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Ut.parseActionMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseActionMetadata(e,a,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let n=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:a,path:r,handler:`${a}.handle`,description:n?.[1]}}static generateScheduledJobResources(e){let{slug:a,environment:r,jobs:n,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let h of n){if(!h.schedule||!h.enabled)continue;let{rule:y,logicalId:f}=pe.createScheduledJob({slug:a,environment:r,schedule:h.schedule,jobClass:h.name,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[f]=y,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1662
1662
|
/**
|
|
1663
1663
|
* Job Runner Script
|
|
1664
1664
|
* This script is invoked by ECS scheduled tasks to run jobs
|
|
@@ -1703,7 +1703,7 @@ catch (error) {
|
|
|
1703
1703
|
}
|
|
1704
1704
|
|
|
1705
1705
|
run()
|
|
1706
|
-
`}static async generateJobManifest(e){let a=await
|
|
1706
|
+
`}static async generateJobManifest(e){let a=await Ut.discoverJobs(e),r=a.filter((n)=>n.schedule&&n.enabled);return{jobs:a,scheduledCount:r.length,totalCount:a.length}}}var np={loadJobs:Ut.discoverJobs,loadActions:Ut.discoverActions,generateScheduledJobs:Ut.generateScheduledJobResources,generateRunner:Ut.generateJobRunnerScript,paths:{jobs:"app/Jobs",actions:"app/Actions",runner:"app/Jobs/runner.ts"}},$r=`
|
|
1707
1707
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1708
1708
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1709
1709
|
|
|
@@ -2306,14 +2306,14 @@ function resolveTemplate(template, data) {
|
|
|
2306
2306
|
}
|
|
2307
2307
|
return result;
|
|
2308
2308
|
}
|
|
2309
|
-
`;class be{static LambdaCode={send:Pa,receive:Lr,deliveryStatus:$r};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let a={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)a.SenderId=e.senderId;if(e.shortCode)a.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:a}}}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:be.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:be.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:be.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 a={},r={};Object.assign(a,be.createPinpointApp({slug:e.slug})),Object.assign(a,be.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(a,be.createSmsLambdaRole({slug:e.slug})),Object.assign(a,be.createMessageLogTable({slug:e.slug})),Object.assign(a,be.createOptOutTable({slug:e.slug})),Object.assign(a,be.createNotificationTopic({slug:e.slug}));let n={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},i={Ref:`${e.slug}PinpointApp`},o={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(a,be.createSendLambda({slug:e.slug,roleArn:n,pinpointAppId:i,messageLogTable:o,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(a,be.createReceiveLambda({slug:e.slug,roleArn:n,optOutTable:c,messageLogTable:o,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(a,be.createDeliveryStatusLambda({slug:e.slug,roleArn:n,messageLogTable:o,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:a,outputs:r}}}function At(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((a)=>a.charAt(0).toUpperCase()+a.slice(1)).join("")||"User"}function xr(e,a){let r=(e||a).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${a}`);return r}function Or(e){let a=e.storage;if(a?.type==="efs"){let n="fileSystemId"in a?a.fileSystemId:void 0;if(!n||typeof n==="string"&&!n.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:n,posixProfile:a.posixProfile}}let r=(a?.type==="s3"?a.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 Br(e,a,r){let n=a.posixProfile??r;if(!n)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let i of[n.uid,n.gid,...n.secondaryGids??[]])if(!Number.isInteger(i)||i<0||i>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${i}`);return{Uid:n.uid,Gid:n.gid,...n.secondaryGids?.length?{SecondaryGids:n.secondaryGids}:{}}}function _r(e,a){return typeof e==="string"?`/${e}/${a}`:{"Fn::Sub":[`/\${FileSystemId}/${a}`,{FileSystemId:e}]}}function Wr(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 bo{static create(e){let a=Or(e),r=a.type==="efs"?"EFS":"S3",n=e.endpointType??"PUBLIC";if(n==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let i=`${At(e.slug)}${At(e.environment)}Sftp`,o=`${i}Server`,c={},u;if(e.logging!==!1){let d=`${i}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[o]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:n,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...n==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=At(d),g=xr(m.homeDirectory,d),h=`${i}${p}User`,y=m.roleArn;if(!y){let f=`${i}${p}Role`,b;if(a.type==="efs")b=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Wr(a.fileSystemId)}];else{let v=`arn:aws:s3:::${a.bucket}`;b=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:v,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${v}/${g}/*`}]}c[f]={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:b}}]}},y={"Fn::GetAtt":[f,"Arn"]}}c[h]={Type:"AWS::Transfer::User",DependsOn:[o],Properties:{ServerId:{Ref:o},UserName:d,Role:y,HomeDirectoryType:"PATH",HomeDirectory:a.type==="efs"?_r(a.fileSystemId,g):`/${a.bucket}/${g}`,...a.type==="efs"?{PosixProfile:Br(d,m,a.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:o,domain:r}}}class Me{static createBedrockRole(e,a){let{slug:r,environment:n,name:i,models:o=["*"],allowStreaming:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"bedrock-role"}),d=s(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=o.map((g)=>g==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${g}`);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:n}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:a,environment:r,name:n,models:i=["*"],allowInvoke:o=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=n||l({slug:a,environment:r,resourceType:"bedrock-policy"}),m=s(d),p=[];if(o)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=i.map((h)=>h==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${h}`);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 Me.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return Me.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return Me.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,a=["*"],r=!0){let n=["bedrock:InvokeModel"];if(r)n.push("bedrock:InvokeModelWithResponseStream");let i=a.map((o)=>o==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${o}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n,Resource:i}]}}),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 Ut{static createPostgres(e){return Ut.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Ut.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,a,r){let{slug:n,environment:i,instanceClass:o="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:h,encrypted:y=!0,kmsKeyId:f,multiAz:b=!1,backupRetentionDays:v=7,publiclyAccessible:P=!1,enableCloudwatchLogs:R=!0,deletionProtection:T=!0}=r,N=l({slug:n,environment:i,resourceType:`${e}-db`}),I=s(N),k,x;if(g&&g.length>0){let O=l({slug:n,environment:i,resourceType:"db-subnet-group"});x=s(O),k={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${N}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:i}]}}}let L={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:N,DBInstanceClass:o,Engine:e,EngineVersion:a,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:y,MultiAZ:b,BackupRetentionPeriod:v,PubliclyAccessible:P,DeletionProtection:T,Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:i}]}};if(p)L.Properties.DBName=p;if(f)L.Properties.KmsKeyId=f;if(x)L.Properties.DBSubnetGroupName=w.Ref(x);if(h&&h.length>0)L.Properties.VPCSecurityGroups=h;if(R)L.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:L,subnetGroup:k,logicalId:I,subnetGroupId:x}}static createReadReplica(e,a){let{slug:r,environment:n,instanceClass:i="db.t3.micro",securityGroupIds:o,publiclyAccessible:c=!1}=a,u=l({slug:r,environment:n,resourceType:"db-replica"}),d=s(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:i,SourceDBInstanceIdentifier:w.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Type",Value:"ReadReplica"}]}};if(o&&o.length>0)m.Properties.VPCSecurityGroups=o;return{replica:m,logicalId:d}}static createParameterGroup(e,a,r){let{slug:n,environment:i,parameters:o={}}=r,c=l({slug:n,environment:i,resourceType:"db-params"}),u=s(c),d=e==="postgres"?`postgres${a.split(".")[0]}`:`mysql${a.split(".")[0]}.${a.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:o,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i}]}},logicalId:u}}static enableBackup(e,a=7){return e.Properties.BackupRetentionPeriod=a,e}static createTable(e){let{slug:a,environment:r,tableName:n,partitionKey:i,sortKey:o,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:h,pointInTimeRecovery:y=!0,ttlAttribute:f}=e,b=n||l({slug:a,environment:r,resourceType:"table"}),v=s(b),P=[{AttributeName:i.name,AttributeType:i.type}];if(o)P.push({AttributeName:o.name,AttributeType:o.type});let R=[{AttributeName:i.name,KeyType:"HASH"}];if(o)R.push({AttributeName:o.name,KeyType:"RANGE"});let T={Type:"AWS::DynamoDB::Table",Properties:{TableName:b,BillingMode:c,AttributeDefinitions:P,KeySchema:R,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")T.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)T.Properties.StreamSpecification={StreamViewType:p};if(g)T.Properties.SSESpecification={SSEEnabled:!0,SSEType:h?"KMS":"AES256",KMSMasterKeyId:h};if(y)T.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(f)T.Properties.TimeToLiveSpecification={AttributeName:f,Enabled:!0};return{table:T,logicalId:v}}static addGlobalSecondaryIndex(e,a){let{indexName:r,partitionKey:n,sortKey:i,projectionType:o="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=a;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===n.name))e.Properties.AttributeDefinitions.push({AttributeName:n.name,AttributeType:n.type});if(i&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});let m=[{AttributeName:n.name,KeyType:"HASH"}];if(i)m.push({AttributeName:i.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:o,NonKeyAttributes:o==="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,a="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:a},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 mi{static createRedis(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="7.1",port:o=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:h=1,replicasPerNodeGroup:y=1,atRestEncryption:f=!0,transitEncryption:b=!0,authToken:v,kmsKeyId:P,snapshotRetentionDays:R=7,snapshotWindow:T,maintenanceWindow:N}=e,I=l({slug:a,environment:r,resourceType:"redis"}),k=s(I),x,L;if(c&&c.length>0){let W=l({slug:a,environment:r,resourceType:"cache-subnet-group"});L=s(W),x={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:W,Description:`Subnet group for ${I}`,SubnetIds:c,Tags:[{Key:"Name",Value:W},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:I,ReplicationGroupDescription:`Redis cluster for ${a} ${r}`,Engine:"redis",EngineVersion:i,CacheNodeType:n,Port:o,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:f,TransitEncryptionEnabled:b,SnapshotRetentionLimit:R,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:r}]}};if(g)O.Properties.NumNodeGroups=h,O.Properties.ReplicasPerNodeGroup=y;else O.Properties.NumCacheClusters=d;if(v)O.Properties.AuthToken=v;if(P)O.Properties.KmsKeyId=P;if(L)O.Properties.CacheSubnetGroupName=w.Ref(L);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(T)O.Properties.SnapshotWindow=T;if(N)O.Properties.PreferredMaintenanceWindow=N;return{replicationGroup:O,subnetGroup:x,logicalId:k,subnetGroupId:L}}static createMemcached(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="1.6.22",port:o=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,h=l({slug:a,environment:r,resourceType:"memcached"}),y=s(h),f,b;if(u&&u.length>0){let P=l({slug:a,environment:r,resourceType:"cache-subnet-group"});b=s(P),f={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:P,Description:`Subnet group for ${h}`,SubnetIds:u,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}}}let v={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:h,CacheNodeType:n,Engine:"memcached",EngineVersion:i,NumCacheNodes:c,Port:o,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(b)v.Properties.CacheSubnetGroupName=w.Ref(b);if(d&&d.length>0)v.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)v.Properties.PreferredAvailabilityZones=p;if(g)v.Properties.PreferredMaintenanceWindow=g;return{cluster:v,subnetGroup:f,logicalId:y,subnetGroupId:b}}static enableClusterMode(e,a=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=a,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"redis-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static createMemcachedParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"memcached-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},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 ve{static createUser(e){let{slug:a,environment:r,userName:n,groups:i,managedPolicyArns:o}=e,c=n||l({slug:a,environment:r,resourceType:"user"}),u=s(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(i&&i.length>0)d.Properties.Groups=i;if(o&&o.length>0)d.Properties.ManagedPolicyArns=o;return{user:d,logicalId:u}}static createRole(e){let{slug:a,environment:r,roleName:n,servicePrincipal:i,awsPrincipal:o,managedPolicyArns:c}=e,u=n||l({slug:a,environment:r,resourceType:"role"}),d=s(u),m={};if(i)m.Service=i;if(o)m.AWS=o;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:a,environment:r,groupName:n,managedPolicyArns:i}=e,o=n||l({slug:a,environment:r,resourceType:"group"}),c=s(o),u={Type:"AWS::IAM::Group",Properties:{GroupName:o}};if(i&&i.length>0)u.Properties.ManagedPolicyArns=i;return{group:u,logicalId:c}}static createPolicy(e){let{slug:a,environment:r,policyName:n,description:i,statements:o}=e,c=n||l({slug:a,environment:r,resourceType:"policy"}),u=s(c),d=o.map((m)=>({Sid:m.sid,Effect:m.effect||"Allow",Action:m.actions,Resource:m.resources,Condition:m.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:i||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToUser(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToGroup(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static addInlinePolicyToRole(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static addInlinePolicyToUser(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static createAccessKey(e,a){let{slug:r,environment:n,status:i="Active"}=a,o=l({slug:r,environment:n,resourceType:"access-key"}),c=s(o);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:w.Ref(e),Status:i}},logicalId:c}}static createInstanceProfile(e,a){let{slug:r,environment:n,profileName:i}=a,o=i||l({slug:r,environment:n,resourceType:"instance-profile"}),c=s(o);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:o,Roles:[w.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:a,environment:r,permissions:n,createAccessKey:i=!0}=e,o={},c=[];if(n.s3Buckets&&n.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...n.s3Buckets,...n.s3Buckets.map((y)=>`${y}/*`)]});if(n.cloudFrontDistributions&&n.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:n.cloudFrontDistributions});if(n.ecrRepositories&&n.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:n.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(n.ecsServices&&n.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:n.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(n.cloudFormationStacks&&n.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:n.cloudFormationStacks});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:n.lambdaFunctions});if(n.secretsManagerSecrets&&n.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:n.secretsManagerSecrets});let{policy:u,logicalId:d}=ve.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${a} (${r})`,statements:c});o[d]=u;let{user:m,logicalId:p}=ve.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[w.Ref(d)]});o[p]=m;let g,h;if(i){let y=ve.createAccessKey(p,{slug:a,environment:r});g=y.accessKey,h=y.logicalId,o[h]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,resources:o}}static createCrossAccountRole(e){let{slug:a,environment:r,trustedAccountIds:n,externalId:i,permissions:o,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=ve.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${a} (${r})`,statements:o});u[m]=d;let p=l({slug:a,environment:r,resourceType:"cross-account-role"}),g=s(p),h={};if(i)h.StringEquals={"sts:ExternalId":i};let y={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:n.map((f)=>`arn:aws:iam::${f}:root`)},Action:"sts:AssumeRole",...Object.keys(h).length>0?{Condition:h}:{}}]},ManagedPolicyArns:[w.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=y,{role:y,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:a,environment:r,permissions:n="readonly"}=e,i={},o=[],c=[];switch(n){case"readonly":c=[ve.ManagedPolicies.ReadOnlyAccess];break;case"deploy":o=[{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=[ve.ManagedPolicies.AdministratorAccess];break}let u,d;if(o.length>0){let y=ve.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${a} (${r})`,statements:o});u=y.policy,d=y.logicalId,i[d]=u,c=[w.Ref(d)]}let{user:m,logicalId:p}=ve.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});i[p]=m;let{accessKey:g,logicalId:h}=ve.createAccessKey(p,{slug:a,environment:r});return i[h]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,resources:i}}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((a)=>`${a}/*`)}],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 vo{static createRestApi(e){let{slug:a,environment:r,name:n,description:i,endpointType:o="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=n||l({slug:a,environment:r,resourceType:"rest-api"}),m=s(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:i||`REST API for ${a} ${r}`,EndpointConfiguration:{Types:[o]},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:a,environment:r,name:n,description:i,corsEnabled:o=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=n||l({slug:a,environment:r,resourceType:"http-api"}),h=s(g),y={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:i||`HTTP API for ${a} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(o)y.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:y,logicalId:h}}static createWebSocketApi(e){let{slug:a,environment:r,name:n,description:i}=e,o=n||l({slug:a,environment:r,resourceType:"ws-api"}),c=s(o);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:o,Description:i||`WebSocket API for ${a} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:o,Environment:r}}},logicalId:c}}static createDeployment(e,a){let{slug:r,environment:n,description:i}=a,o=l({slug:r,environment:n,resourceType:"api-deployment"}),c=s(o);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:w.Ref(e),Description:i||`Deployment for ${o}`}},logicalId:c}}static createStage(e,a,r){let{slug:n,environment:i,stageName:o,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:n,environment:i,resourceType:"api-stage"}),h=s(g),y={Type:"AWS::ApiGateway::Stage",Properties:{StageName:o||i,RestApiId:w.Ref(e),DeploymentId:w.Ref(a),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:i}]}};if(u)y.Properties.CacheClusterSize=d;if(m)y.Properties.Variables=m;if(p)y.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:y,logicalId:h}}static createAuthorizer(e,a){let{slug:r,environment:n,name:i,type:o,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=a,p=i||l({slug:r,environment:n,resourceType:"api-authorizer"}),g=s(p),h={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:o,RestApiId:w.Ref(e),AuthorizerResultTtlInSeconds:m}};if(o==="TOKEN"||o==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");h.Properties.AuthorizerUri=c,h.Properties.IdentitySource=u||"method.request.header.Authorization"}if(o==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");h.Properties.ProviderARNs=d,h.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:h,logicalId:g}}static setCors(e,a={}){let{origins:r=["*"],methods:n=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:i=["*"],maxAge:o=86400,allowCredentials:c=!1}=a;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:n,AllowHeaders:i,MaxAge:o,AllowCredentials:c},e}static addThrottling(e,a=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:a,ThrottlingRateLimit:r}),e}static enableCaching(e,a="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=a,!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 Ne{static createTopic(e){let{slug:a,environment:r,topicName:n,displayName:i,encrypted:o=!1,kmsKeyId:c}=e,u=n||l({slug:a,environment:r,resourceType:"topic"}),d=s(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:i||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,a){let{slug:r,environment:n,protocol:i,endpoint:o,filterPolicy:c,rawMessageDelivery:u=!1}=a,d=l({slug:r,environment:n,resourceType:"subscription"}),m=o.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=s(`${d}-${i}-${p}`),h={Type:"AWS::SNS::Subscription",Properties:{TopicArn:w.Ref(e),Protocol:i,Endpoint:o,RawMessageDelivery:u}};if(c)h.Properties.FilterPolicy=c;return{subscription:h,logicalId:g}}static subscribeEmail(e,a,r){return Ne.subscribe(e,{...r,protocol:"email",endpoint:a})}static subscribeLambda(e,a,r){return Ne.subscribe(e,{...r,protocol:"lambda",endpoint:a,rawMessageDelivery:!0})}static subscribeSqs(e,a,r){return Ne.subscribe(e,{...r,protocol:"sqs",endpoint:a})}static subscribeHttp(e,a,r){let n=a.startsWith("https://")?"https":"http";return Ne.subscribe(e,{...r,protocol:n,endpoint:a})}static subscribeSms(e,a,r){return Ne.subscribe(e,{...r,protocol:"sms",endpoint:a})}static setTopicPolicy(e,a){let{slug:r,environment:n,allowedPrincipals:i,allowedServices:o,actions:c="SNS:Publish"}=a,u=l({slug:r,environment:n,resourceType:"topic-policy"}),d=s(u),m={};if(i)m.AWS=i;if(o)m.Service=o;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[w.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:w.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,a){return Ne.setTopicPolicy(e,{...a,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,a){return Ne.setTopicPolicy(e,{...a,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,a){return Ne.setTopicPolicy(e,{...a,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,a){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=a,e}static addInlineSubscription(e,a,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:a,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,a,r)=>({[e]:[{numeric:[">=",a,"<=",r]}]}),prefix:(e,a)=>({[e]:[{prefix:a}]}),and:(...e)=>Object.assign({},...e),exists:(e,a)=>({[e]:[{exists:a}]})};static UseCases={createAlertTopic:(e)=>Ne.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>Ne.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>Ne.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class nd{static createStateMachine(e){let{slug:a,environment:r,stateMachineName:n,type:i="STANDARD",definition:o,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=n||l({slug:a,environment:r,resourceType:"state-machine"}),p=s(m),g,h,y;if(c)y=c;else{let b=l({slug:a,environment:r,resourceType:"state-machine-role"});h=s(b),g={Type:"AWS::IAM::Role",Properties:{RoleName:b,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:b},{Key:"Environment",Value:r}]}},y=w.GetAtt(h,"Arn")}let f={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:i,DefinitionString:JSON.stringify(o),RoleArn:y,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)f.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((b)=>({CloudWatchLogsLogGroup:{LogGroupArn:b}}))};if(d)f.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:f,logicalId:p,role:g,roleLogicalId:h}}static createLambdaTask(e,a){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:a?.parameters||{"Input.$":"$"}},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createDynamoDBTask(e,a,r,n){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:a,...r},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSNSPublishTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:a},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,a){return{Type:"Choice",Choices:e,Default:a}}static createParallelState(e,a){return{Type:"Parallel",Branches:e,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createMapState(e,a){return{Type:"Map",ItemsPath:a?.itemsPath||"$.items",Iterator:e,MaxConcurrency:a?.maxConcurrency,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,a){return{Type:"Fail",Error:e,Cause:a}}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,a,r,n)=>({ErrorEquals:e,IntervalSeconds:a,MaxAttempts:r,BackoffRate:n})};static CatchPolicies={all:(e,a)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:a||"$.error"}),specific:(e,a,r)=>({ErrorEquals:e,Next:a,ResultPath:r||"$.error"})};static Patterns={sequential:(e,a,r)=>{let n={};return r.forEach((i,o)=>{let c=o===r.length-1;n[i.name]={...i.state,Next:c?void 0:r[o+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:n}},fanout:(e,a,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((n)=>n.definition),End:!0}}}),map:(e,a,r,n)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:n,End:!0}}}),withErrorHandling:(e,a,r,n)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:n,Success:{Type:"Succeed"}}})}}class gi{static createAlarm(e){let{slug:a,environment:r,alarmName:n,metricName:i,namespace:o,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:h=!0,alarmActions:y,okActions:f,insufficientDataActions:b,dimensions:v,unit:P,datapointsToAlarm:R}=e,T=n||l({slug:a,environment:r,resourceType:"alarm"}),N=s(T),I={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:T,MetricName:i,Namespace:o,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:h}};if(y&&y.length>0)I.Properties.AlarmActions=y;if(f&&f.length>0)I.Properties.OKActions=f;if(b&&b.length>0)I.Properties.InsufficientDataActions=b;if(v)I.Properties.Dimensions=Object.entries(v).map(([k,x])=>({Name:k,Value:x}));if(P)I.Properties.Unit=P;if(R!==void 0)I.Properties.DatapointsToAlarm=R;return{alarm:I,logicalId:N}}static createCompositeAlarm(e){let{slug:a,environment:r,alarmName:n,alarmRule:i,actionsEnabled:o=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=n||l({slug:a,environment:r,resourceType:"composite-alarm"}),p=s(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:i,ActionsEnabled:o}};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:a,environment:r,dashboardName:n,widgets:i}=e,o=n||l({slug:a,environment:r,resourceType:"dashboard"}),c=s(o),u={widgets:i.map((d)=>({type:d.type,x:d.x,y:d.y,width:d.width,height:d.height,properties:d.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:o,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:a,environment:r,logGroupName:n,retentionInDays:i,kmsKeyId:o}=e,c=n||l({slug:a,environment:r,resourceType:"log-group"}),u=s(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(i!==void 0)d.Properties.RetentionInDays=i;if(o)d.Properties.KmsKeyId=o;return{logGroup:d,logicalId:u}}static createLogStream(e,a){let{slug:r,environment:n,logStreamName:i}=a,o=i||l({slug:r,environment:n,resourceType:"log-stream"}),c=s(o);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:w.Ref(e),LogStreamName:o}},logicalId:c}}static createMetricFilter(e,a){let{slug:r,environment:n,filterName:i,filterPattern:o,metricTransformations:c}=a,u=i||l({slug:r,environment:n,resourceType:"metric-filter"}),d=s(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:w.Ref(e),FilterPattern:o,MetricTransformations:c.map((m)=>({MetricName:m.metricName,MetricNamespace:m.metricNamespace,MetricValue:m.metricValue,DefaultValue:m.defaultValue,Unit:m.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highMemory:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highDisk:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:i?[i]:void 0}),lambdaErrors:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),lambdaThrottles:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),apiGateway5xxErrors:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),apiGateway4xxErrors:(e,a,r,n=50,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),dynamoDBThrottles:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:i?[i]:void 0}),rdsCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0}),rdsFreeStorage:(e,a,r,n=5368709120,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,a,r,n=100,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:i?[i]:void 0}),albUnhealthyTargets:(e,a,r,n,i=1,o)=>({slug:e,environment:a,alarmName:`${e}-${a}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:n},alarmActions:o?[o]:void 0}),sesBounceRate:(e,a,r=5,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),sesComplaintRate:(e,a,r=0.1,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),smsDeliveryFailure:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:i?[i]:void 0}),smsSpendLimit:(e,a,r=100,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),connectMissedCalls:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0})};static DashboardWidgets={metric:(e,a,r,n,i,o)=>({type:"metric",x:e,y:a,width:r,height:n,properties:{metrics:i,title:o||"Metrics",region:"us-east-1",period:300}}),text:(e,a,r,n,i)=>({type:"text",x:e,y:a,width:r,height:n,properties:{markdown:i}}),log:(e,a,r,n,i,o)=>({type:"log",x:e,y:a,width:r,height:n,properties:{query:`SOURCE '${i.join("' | SOURCE '")}'
|
|
2309
|
+
`;class be{static LambdaCode={send:Pa,receive:Lr,deliveryStatus:$r};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let a={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)a.SenderId=e.senderId;if(e.shortCode)a.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:a}}}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:be.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:be.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:be.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 a={},r={};Object.assign(a,be.createPinpointApp({slug:e.slug})),Object.assign(a,be.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(a,be.createSmsLambdaRole({slug:e.slug})),Object.assign(a,be.createMessageLogTable({slug:e.slug})),Object.assign(a,be.createOptOutTable({slug:e.slug})),Object.assign(a,be.createNotificationTopic({slug:e.slug}));let n={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},i={Ref:`${e.slug}PinpointApp`},o={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(a,be.createSendLambda({slug:e.slug,roleArn:n,pinpointAppId:i,messageLogTable:o,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(a,be.createReceiveLambda({slug:e.slug,roleArn:n,optOutTable:c,messageLogTable:o,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(a,be.createDeliveryStatusLambda({slug:e.slug,roleArn:n,messageLogTable:o,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:a,outputs:r}}}function At(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((a)=>a.charAt(0).toUpperCase()+a.slice(1)).join("")||"User"}function xr(e,a){let r=(e||a).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${a}`);return r}function Or(e){let a=e.storage;if(a?.type==="efs"){let n="fileSystemId"in a?a.fileSystemId:void 0;if(!n||typeof n==="string"&&!n.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:n,posixProfile:a.posixProfile}}let r=(a?.type==="s3"?a.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 Br(e,a,r){let n=a.posixProfile??r;if(!n)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let i of[n.uid,n.gid,...n.secondaryGids??[]])if(!Number.isInteger(i)||i<0||i>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${i}`);return{Uid:n.uid,Gid:n.gid,...n.secondaryGids?.length?{SecondaryGids:n.secondaryGids}:{}}}function _r(e,a){return typeof e==="string"?`/${e}/${a}`:{"Fn::Sub":[`/\${FileSystemId}/${a}`,{FileSystemId:e}]}}function Wr(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 bo{static create(e){let a=Or(e),r=a.type==="efs"?"EFS":"S3",n=e.endpointType??"PUBLIC";if(n==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let i=`${At(e.slug)}${At(e.environment)}Sftp`,o=`${i}Server`,c={},u;if(e.logging!==!1){let d=`${i}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[o]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:n,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...n==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=At(d),g=xr(m.homeDirectory,d),h=`${i}${p}User`,y=m.roleArn;if(!y){let f=`${i}${p}Role`,b;if(a.type==="efs")b=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Wr(a.fileSystemId)}];else{let v=`arn:aws:s3:::${a.bucket}`;b=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:v,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${v}/${g}/*`}]}c[f]={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:b}}]}},y={"Fn::GetAtt":[f,"Arn"]}}c[h]={Type:"AWS::Transfer::User",DependsOn:[o],Properties:{ServerId:{Ref:o},UserName:d,Role:y,HomeDirectoryType:"PATH",HomeDirectory:a.type==="efs"?_r(a.fileSystemId,g):`/${a.bucket}/${g}`,...a.type==="efs"?{PosixProfile:Br(d,m,a.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:o,domain:r}}}class Me{static createBedrockRole(e,a){let{slug:r,environment:n,name:i,models:o=["*"],allowStreaming:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"bedrock-role"}),d=s(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=o.map((g)=>g==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${g}`);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:n}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:a,environment:r,name:n,models:i=["*"],allowInvoke:o=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=n||l({slug:a,environment:r,resourceType:"bedrock-policy"}),m=s(d),p=[];if(o)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=i.map((h)=>h==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${h}`);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 Me.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return Me.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return Me.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,a=["*"],r=!0){let n=["bedrock:InvokeModel"];if(r)n.push("bedrock:InvokeModelWithResponseStream");let i=a.map((o)=>o==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${o}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n,Resource:i}]}}),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 Bt{static createPostgres(e){return Bt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Bt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,a,r){let{slug:n,environment:i,instanceClass:o="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:h,encrypted:y=!0,kmsKeyId:f,multiAz:b=!1,backupRetentionDays:v=7,publiclyAccessible:P=!1,enableCloudwatchLogs:R=!0,deletionProtection:T=!0}=r,N=l({slug:n,environment:i,resourceType:`${e}-db`}),I=s(N),k,x;if(g&&g.length>0){let O=l({slug:n,environment:i,resourceType:"db-subnet-group"});x=s(O),k={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${N}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:i}]}}}let L={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:N,DBInstanceClass:o,Engine:e,EngineVersion:a,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:y,MultiAZ:b,BackupRetentionPeriod:v,PubliclyAccessible:P,DeletionProtection:T,Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:i}]}};if(p)L.Properties.DBName=p;if(f)L.Properties.KmsKeyId=f;if(x)L.Properties.DBSubnetGroupName=w.Ref(x);if(h&&h.length>0)L.Properties.VPCSecurityGroups=h;if(R)L.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:L,subnetGroup:k,logicalId:I,subnetGroupId:x}}static createReadReplica(e,a){let{slug:r,environment:n,instanceClass:i="db.t3.micro",securityGroupIds:o,publiclyAccessible:c=!1}=a,u=l({slug:r,environment:n,resourceType:"db-replica"}),d=s(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:i,SourceDBInstanceIdentifier:w.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Type",Value:"ReadReplica"}]}};if(o&&o.length>0)m.Properties.VPCSecurityGroups=o;return{replica:m,logicalId:d}}static createParameterGroup(e,a,r){let{slug:n,environment:i,parameters:o={}}=r,c=l({slug:n,environment:i,resourceType:"db-params"}),u=s(c),d=e==="postgres"?`postgres${a.split(".")[0]}`:`mysql${a.split(".")[0]}.${a.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:o,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i}]}},logicalId:u}}static enableBackup(e,a=7){return e.Properties.BackupRetentionPeriod=a,e}static createTable(e){let{slug:a,environment:r,tableName:n,partitionKey:i,sortKey:o,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:h,pointInTimeRecovery:y=!0,ttlAttribute:f}=e,b=n||l({slug:a,environment:r,resourceType:"table"}),v=s(b),P=[{AttributeName:i.name,AttributeType:i.type}];if(o)P.push({AttributeName:o.name,AttributeType:o.type});let R=[{AttributeName:i.name,KeyType:"HASH"}];if(o)R.push({AttributeName:o.name,KeyType:"RANGE"});let T={Type:"AWS::DynamoDB::Table",Properties:{TableName:b,BillingMode:c,AttributeDefinitions:P,KeySchema:R,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")T.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)T.Properties.StreamSpecification={StreamViewType:p};if(g)T.Properties.SSESpecification={SSEEnabled:!0,SSEType:h?"KMS":"AES256",KMSMasterKeyId:h};if(y)T.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(f)T.Properties.TimeToLiveSpecification={AttributeName:f,Enabled:!0};return{table:T,logicalId:v}}static addGlobalSecondaryIndex(e,a){let{indexName:r,partitionKey:n,sortKey:i,projectionType:o="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=a;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===n.name))e.Properties.AttributeDefinitions.push({AttributeName:n.name,AttributeType:n.type});if(i&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});let m=[{AttributeName:n.name,KeyType:"HASH"}];if(i)m.push({AttributeName:i.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:o,NonKeyAttributes:o==="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,a="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:a},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 mi{static createRedis(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="7.1",port:o=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:h=1,replicasPerNodeGroup:y=1,atRestEncryption:f=!0,transitEncryption:b=!0,authToken:v,kmsKeyId:P,snapshotRetentionDays:R=7,snapshotWindow:T,maintenanceWindow:N}=e,I=l({slug:a,environment:r,resourceType:"redis"}),k=s(I),x,L;if(c&&c.length>0){let W=l({slug:a,environment:r,resourceType:"cache-subnet-group"});L=s(W),x={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:W,Description:`Subnet group for ${I}`,SubnetIds:c,Tags:[{Key:"Name",Value:W},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:I,ReplicationGroupDescription:`Redis cluster for ${a} ${r}`,Engine:"redis",EngineVersion:i,CacheNodeType:n,Port:o,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:f,TransitEncryptionEnabled:b,SnapshotRetentionLimit:R,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:r}]}};if(g)O.Properties.NumNodeGroups=h,O.Properties.ReplicasPerNodeGroup=y;else O.Properties.NumCacheClusters=d;if(v)O.Properties.AuthToken=v;if(P)O.Properties.KmsKeyId=P;if(L)O.Properties.CacheSubnetGroupName=w.Ref(L);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(T)O.Properties.SnapshotWindow=T;if(N)O.Properties.PreferredMaintenanceWindow=N;return{replicationGroup:O,subnetGroup:x,logicalId:k,subnetGroupId:L}}static createMemcached(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="1.6.22",port:o=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,h=l({slug:a,environment:r,resourceType:"memcached"}),y=s(h),f,b;if(u&&u.length>0){let P=l({slug:a,environment:r,resourceType:"cache-subnet-group"});b=s(P),f={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:P,Description:`Subnet group for ${h}`,SubnetIds:u,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}}}let v={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:h,CacheNodeType:n,Engine:"memcached",EngineVersion:i,NumCacheNodes:c,Port:o,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(b)v.Properties.CacheSubnetGroupName=w.Ref(b);if(d&&d.length>0)v.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)v.Properties.PreferredAvailabilityZones=p;if(g)v.Properties.PreferredMaintenanceWindow=g;return{cluster:v,subnetGroup:f,logicalId:y,subnetGroupId:b}}static enableClusterMode(e,a=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=a,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"redis-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static createMemcachedParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"memcached-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},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 ve{static createUser(e){let{slug:a,environment:r,userName:n,groups:i,managedPolicyArns:o}=e,c=n||l({slug:a,environment:r,resourceType:"user"}),u=s(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(i&&i.length>0)d.Properties.Groups=i;if(o&&o.length>0)d.Properties.ManagedPolicyArns=o;return{user:d,logicalId:u}}static createRole(e){let{slug:a,environment:r,roleName:n,servicePrincipal:i,awsPrincipal:o,managedPolicyArns:c}=e,u=n||l({slug:a,environment:r,resourceType:"role"}),d=s(u),m={};if(i)m.Service=i;if(o)m.AWS=o;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:a,environment:r,groupName:n,managedPolicyArns:i}=e,o=n||l({slug:a,environment:r,resourceType:"group"}),c=s(o),u={Type:"AWS::IAM::Group",Properties:{GroupName:o}};if(i&&i.length>0)u.Properties.ManagedPolicyArns=i;return{group:u,logicalId:c}}static createPolicy(e){let{slug:a,environment:r,policyName:n,description:i,statements:o}=e,c=n||l({slug:a,environment:r,resourceType:"policy"}),u=s(c),d=o.map((m)=>({Sid:m.sid,Effect:m.effect||"Allow",Action:m.actions,Resource:m.resources,Condition:m.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:i||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToUser(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToGroup(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static addInlinePolicyToRole(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static addInlinePolicyToUser(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static createAccessKey(e,a){let{slug:r,environment:n,status:i="Active"}=a,o=l({slug:r,environment:n,resourceType:"access-key"}),c=s(o);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:w.Ref(e),Status:i}},logicalId:c}}static createInstanceProfile(e,a){let{slug:r,environment:n,profileName:i}=a,o=i||l({slug:r,environment:n,resourceType:"instance-profile"}),c=s(o);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:o,Roles:[w.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:a,environment:r,permissions:n,createAccessKey:i=!0}=e,o={},c=[];if(n.s3Buckets&&n.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...n.s3Buckets,...n.s3Buckets.map((y)=>`${y}/*`)]});if(n.cloudFrontDistributions&&n.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:n.cloudFrontDistributions});if(n.ecrRepositories&&n.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:n.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(n.ecsServices&&n.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:n.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(n.cloudFormationStacks&&n.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:n.cloudFormationStacks});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:n.lambdaFunctions});if(n.secretsManagerSecrets&&n.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:n.secretsManagerSecrets});let{policy:u,logicalId:d}=ve.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${a} (${r})`,statements:c});o[d]=u;let{user:m,logicalId:p}=ve.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[w.Ref(d)]});o[p]=m;let g,h;if(i){let y=ve.createAccessKey(p,{slug:a,environment:r});g=y.accessKey,h=y.logicalId,o[h]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,resources:o}}static createCrossAccountRole(e){let{slug:a,environment:r,trustedAccountIds:n,externalId:i,permissions:o,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=ve.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${a} (${r})`,statements:o});u[m]=d;let p=l({slug:a,environment:r,resourceType:"cross-account-role"}),g=s(p),h={};if(i)h.StringEquals={"sts:ExternalId":i};let y={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:n.map((f)=>`arn:aws:iam::${f}:root`)},Action:"sts:AssumeRole",...Object.keys(h).length>0?{Condition:h}:{}}]},ManagedPolicyArns:[w.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=y,{role:y,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:a,environment:r,permissions:n="readonly"}=e,i={},o=[],c=[];switch(n){case"readonly":c=[ve.ManagedPolicies.ReadOnlyAccess];break;case"deploy":o=[{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=[ve.ManagedPolicies.AdministratorAccess];break}let u,d;if(o.length>0){let y=ve.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${a} (${r})`,statements:o});u=y.policy,d=y.logicalId,i[d]=u,c=[w.Ref(d)]}let{user:m,logicalId:p}=ve.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});i[p]=m;let{accessKey:g,logicalId:h}=ve.createAccessKey(p,{slug:a,environment:r});return i[h]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,resources:i}}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((a)=>`${a}/*`)}],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 vo{static createRestApi(e){let{slug:a,environment:r,name:n,description:i,endpointType:o="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=n||l({slug:a,environment:r,resourceType:"rest-api"}),m=s(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:i||`REST API for ${a} ${r}`,EndpointConfiguration:{Types:[o]},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:a,environment:r,name:n,description:i,corsEnabled:o=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=n||l({slug:a,environment:r,resourceType:"http-api"}),h=s(g),y={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:i||`HTTP API for ${a} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(o)y.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:y,logicalId:h}}static createWebSocketApi(e){let{slug:a,environment:r,name:n,description:i}=e,o=n||l({slug:a,environment:r,resourceType:"ws-api"}),c=s(o);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:o,Description:i||`WebSocket API for ${a} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:o,Environment:r}}},logicalId:c}}static createDeployment(e,a){let{slug:r,environment:n,description:i}=a,o=l({slug:r,environment:n,resourceType:"api-deployment"}),c=s(o);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:w.Ref(e),Description:i||`Deployment for ${o}`}},logicalId:c}}static createStage(e,a,r){let{slug:n,environment:i,stageName:o,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:n,environment:i,resourceType:"api-stage"}),h=s(g),y={Type:"AWS::ApiGateway::Stage",Properties:{StageName:o||i,RestApiId:w.Ref(e),DeploymentId:w.Ref(a),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:i}]}};if(u)y.Properties.CacheClusterSize=d;if(m)y.Properties.Variables=m;if(p)y.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:y,logicalId:h}}static createAuthorizer(e,a){let{slug:r,environment:n,name:i,type:o,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=a,p=i||l({slug:r,environment:n,resourceType:"api-authorizer"}),g=s(p),h={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:o,RestApiId:w.Ref(e),AuthorizerResultTtlInSeconds:m}};if(o==="TOKEN"||o==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");h.Properties.AuthorizerUri=c,h.Properties.IdentitySource=u||"method.request.header.Authorization"}if(o==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");h.Properties.ProviderARNs=d,h.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:h,logicalId:g}}static setCors(e,a={}){let{origins:r=["*"],methods:n=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:i=["*"],maxAge:o=86400,allowCredentials:c=!1}=a;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:n,AllowHeaders:i,MaxAge:o,AllowCredentials:c},e}static addThrottling(e,a=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:a,ThrottlingRateLimit:r}),e}static enableCaching(e,a="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=a,!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 Ne{static createTopic(e){let{slug:a,environment:r,topicName:n,displayName:i,encrypted:o=!1,kmsKeyId:c}=e,u=n||l({slug:a,environment:r,resourceType:"topic"}),d=s(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:i||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,a){let{slug:r,environment:n,protocol:i,endpoint:o,filterPolicy:c,rawMessageDelivery:u=!1}=a,d=l({slug:r,environment:n,resourceType:"subscription"}),m=o.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=s(`${d}-${i}-${p}`),h={Type:"AWS::SNS::Subscription",Properties:{TopicArn:w.Ref(e),Protocol:i,Endpoint:o,RawMessageDelivery:u}};if(c)h.Properties.FilterPolicy=c;return{subscription:h,logicalId:g}}static subscribeEmail(e,a,r){return Ne.subscribe(e,{...r,protocol:"email",endpoint:a})}static subscribeLambda(e,a,r){return Ne.subscribe(e,{...r,protocol:"lambda",endpoint:a,rawMessageDelivery:!0})}static subscribeSqs(e,a,r){return Ne.subscribe(e,{...r,protocol:"sqs",endpoint:a})}static subscribeHttp(e,a,r){let n=a.startsWith("https://")?"https":"http";return Ne.subscribe(e,{...r,protocol:n,endpoint:a})}static subscribeSms(e,a,r){return Ne.subscribe(e,{...r,protocol:"sms",endpoint:a})}static setTopicPolicy(e,a){let{slug:r,environment:n,allowedPrincipals:i,allowedServices:o,actions:c="SNS:Publish"}=a,u=l({slug:r,environment:n,resourceType:"topic-policy"}),d=s(u),m={};if(i)m.AWS=i;if(o)m.Service=o;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[w.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:w.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,a){return Ne.setTopicPolicy(e,{...a,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,a){return Ne.setTopicPolicy(e,{...a,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,a){return Ne.setTopicPolicy(e,{...a,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,a){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=a,e}static addInlineSubscription(e,a,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:a,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,a,r)=>({[e]:[{numeric:[">=",a,"<=",r]}]}),prefix:(e,a)=>({[e]:[{prefix:a}]}),and:(...e)=>Object.assign({},...e),exists:(e,a)=>({[e]:[{exists:a}]})};static UseCases={createAlertTopic:(e)=>Ne.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>Ne.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>Ne.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class nd{static createStateMachine(e){let{slug:a,environment:r,stateMachineName:n,type:i="STANDARD",definition:o,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=n||l({slug:a,environment:r,resourceType:"state-machine"}),p=s(m),g,h,y;if(c)y=c;else{let b=l({slug:a,environment:r,resourceType:"state-machine-role"});h=s(b),g={Type:"AWS::IAM::Role",Properties:{RoleName:b,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:b},{Key:"Environment",Value:r}]}},y=w.GetAtt(h,"Arn")}let f={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:i,DefinitionString:JSON.stringify(o),RoleArn:y,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)f.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((b)=>({CloudWatchLogsLogGroup:{LogGroupArn:b}}))};if(d)f.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:f,logicalId:p,role:g,roleLogicalId:h}}static createLambdaTask(e,a){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:a?.parameters||{"Input.$":"$"}},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createDynamoDBTask(e,a,r,n){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:a,...r},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSNSPublishTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:a},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,a){return{Type:"Choice",Choices:e,Default:a}}static createParallelState(e,a){return{Type:"Parallel",Branches:e,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createMapState(e,a){return{Type:"Map",ItemsPath:a?.itemsPath||"$.items",Iterator:e,MaxConcurrency:a?.maxConcurrency,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,a){return{Type:"Fail",Error:e,Cause:a}}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,a,r,n)=>({ErrorEquals:e,IntervalSeconds:a,MaxAttempts:r,BackoffRate:n})};static CatchPolicies={all:(e,a)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:a||"$.error"}),specific:(e,a,r)=>({ErrorEquals:e,Next:a,ResultPath:r||"$.error"})};static Patterns={sequential:(e,a,r)=>{let n={};return r.forEach((i,o)=>{let c=o===r.length-1;n[i.name]={...i.state,Next:c?void 0:r[o+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:n}},fanout:(e,a,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((n)=>n.definition),End:!0}}}),map:(e,a,r,n)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:n,End:!0}}}),withErrorHandling:(e,a,r,n)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:n,Success:{Type:"Succeed"}}})}}class gi{static createAlarm(e){let{slug:a,environment:r,alarmName:n,metricName:i,namespace:o,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:h=!0,alarmActions:y,okActions:f,insufficientDataActions:b,dimensions:v,unit:P,datapointsToAlarm:R}=e,T=n||l({slug:a,environment:r,resourceType:"alarm"}),N=s(T),I={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:T,MetricName:i,Namespace:o,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:h}};if(y&&y.length>0)I.Properties.AlarmActions=y;if(f&&f.length>0)I.Properties.OKActions=f;if(b&&b.length>0)I.Properties.InsufficientDataActions=b;if(v)I.Properties.Dimensions=Object.entries(v).map(([k,x])=>({Name:k,Value:x}));if(P)I.Properties.Unit=P;if(R!==void 0)I.Properties.DatapointsToAlarm=R;return{alarm:I,logicalId:N}}static createCompositeAlarm(e){let{slug:a,environment:r,alarmName:n,alarmRule:i,actionsEnabled:o=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=n||l({slug:a,environment:r,resourceType:"composite-alarm"}),p=s(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:i,ActionsEnabled:o}};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:a,environment:r,dashboardName:n,widgets:i}=e,o=n||l({slug:a,environment:r,resourceType:"dashboard"}),c=s(o),u={widgets:i.map((d)=>({type:d.type,x:d.x,y:d.y,width:d.width,height:d.height,properties:d.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:o,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:a,environment:r,logGroupName:n,retentionInDays:i,kmsKeyId:o}=e,c=n||l({slug:a,environment:r,resourceType:"log-group"}),u=s(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(i!==void 0)d.Properties.RetentionInDays=i;if(o)d.Properties.KmsKeyId=o;return{logGroup:d,logicalId:u}}static createLogStream(e,a){let{slug:r,environment:n,logStreamName:i}=a,o=i||l({slug:r,environment:n,resourceType:"log-stream"}),c=s(o);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:w.Ref(e),LogStreamName:o}},logicalId:c}}static createMetricFilter(e,a){let{slug:r,environment:n,filterName:i,filterPattern:o,metricTransformations:c}=a,u=i||l({slug:r,environment:n,resourceType:"metric-filter"}),d=s(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:w.Ref(e),FilterPattern:o,MetricTransformations:c.map((m)=>({MetricName:m.metricName,MetricNamespace:m.metricNamespace,MetricValue:m.metricValue,DefaultValue:m.defaultValue,Unit:m.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highMemory:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highDisk:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:i?[i]:void 0}),lambdaErrors:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),lambdaThrottles:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),apiGateway5xxErrors:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),apiGateway4xxErrors:(e,a,r,n=50,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),dynamoDBThrottles:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:i?[i]:void 0}),rdsCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0}),rdsFreeStorage:(e,a,r,n=5368709120,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,a,r,n=100,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:i?[i]:void 0}),albUnhealthyTargets:(e,a,r,n,i=1,o)=>({slug:e,environment:a,alarmName:`${e}-${a}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:n},alarmActions:o?[o]:void 0}),sesBounceRate:(e,a,r=5,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),sesComplaintRate:(e,a,r=0.1,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),smsDeliveryFailure:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:i?[i]:void 0}),smsSpendLimit:(e,a,r=100,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),connectMissedCalls:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0})};static DashboardWidgets={metric:(e,a,r,n,i,o)=>({type:"metric",x:e,y:a,width:r,height:n,properties:{metrics:i,title:o||"Metrics",region:"us-east-1",period:300}}),text:(e,a,r,n,i)=>({type:"text",x:e,y:a,width:r,height:n,properties:{markdown:i}}),log:(e,a,r,n,i,o)=>({type:"log",x:e,y:a,width:r,height:n,properties:{query:`SOURCE '${i.join("' | SOURCE '")}'
|
|
2310
2310
|
| fields @timestamp, @message
|
|
2311
2311
|
| sort @timestamp desc
|
|
2312
2312
|
| limit 20`,region:"us-east-1",title:o||"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,a)=>`{ $.${e} = "${a}" }`,httpStatus:(e)=>`[..., status_code = ${e}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(e){let{slug:a,environment:r,region:n="us-east-1",components:i={}}=e,o=[],c=0;if(o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:`# ${a.toUpperCase()} Dashboard (${r})`}}),c+=1,i.ec2InstanceIds&&i.ec2InstanceIds.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:n,metrics:i.ec2InstanceIds.map((u)=>["AWS/EC2","CPUUtilization","InstanceId",u]),period:300,stat:"Average"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Network Traffic",region:n,metrics:[...i.ec2InstanceIds.flatMap((u)=>[["AWS/EC2","NetworkIn","InstanceId",u,{label:`${u} In`}],["AWS/EC2","NetworkOut","InstanceId",u,{label:`${u} Out`}]])],period:300,stat:"Sum"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Status Checks",region:n,metrics:i.ec2InstanceIds.map((u)=>["AWS/EC2","StatusCheckFailed","InstanceId",u]),period:60,stat:"Maximum"}}),c+=6;if(i.lambdaFunctionNames&&i.lambdaFunctionNames.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Invocations",region:n,metrics:i.lambdaFunctionNames.map((u)=>["AWS/Lambda","Invocations","FunctionName",u]),period:300,stat:"Sum"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Duration",region:n,metrics:i.lambdaFunctionNames.map((u)=>["AWS/Lambda","Duration","FunctionName",u]),period:300,stat:"Average"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Errors",region:n,metrics:i.lambdaFunctionNames.map((u)=>["AWS/Lambda","Errors","FunctionName",u]),period:300,stat:"Sum"}}),c+=6;if(i.ecsClusterName&&i.ecsServiceName)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## ECS Service"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:n,metrics:[["AWS/ECS","CPUUtilization","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:300,stat:"Average"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Memory Utilization",region:n,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:300,stat:"Average"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Running Tasks",region:n,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:60,stat:"Average"}}),c+=6;if(i.albName)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Request Count",region:n,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",i.albName]],period:60,stat:"Sum"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Response Time",region:n,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",i.albName]],period:60,stat:"Average"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"HTTP Errors",region:n,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",i.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",i.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),c+=6;if(i.rdsInstanceId)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## RDS Database"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:n,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",i.rdsInstanceId]],period:300,stat:"Average"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Database Connections",region:n,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",i.rdsInstanceId]],period:60,stat:"Sum"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Free Storage Space",region:n,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",i.rdsInstanceId]],period:300,stat:"Average"}}),c+=6;if(i.sqsQueueNames&&i.sqsQueueNames.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## SQS Queues"}}),c+=1,o.push({type:"metric",x:0,y:c,width:12,height:6,properties:{title:"Messages Visible",region:n,metrics:i.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",u]),period:60,stat:"Sum"}}),o.push({type:"metric",x:12,y:c,width:12,height:6,properties:{title:"Message Age",region:n,metrics:i.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",u]),period:60,stat:"Maximum"}}),c+=6;if(i.logGroupNames&&i.logGroupNames.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Logs"}}),c+=1,o.push({type:"log",x:0,y:c,width:24,height:6,properties:{query:`SOURCE '${i.logGroupNames.join("' | SOURCE '")}'
|
|
2313
2313
|
| fields @timestamp, @message
|
|
2314
2314
|
| filter @message like /ERROR|WARN|Exception/
|
|
2315
2315
|
| sort @timestamp desc
|
|
2316
|
-
| limit 50`,region:n,title:"Recent Errors and Warnings"}}),c+=6;return gi.createDashboard({slug:a,environment:r,widgets:o})}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((a,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${a} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",a],["AWS/Lambda","Duration","FunctionName",a],["AWS/Lambda","Errors","FunctionName",a]],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:a,namespace:r,threshold:n,comparisonOperator:i="GreaterThanThreshold",evaluationPeriods:o=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:a,Namespace:r,Threshold:n,ComparisonOperator:i,EvaluationPeriods:o,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 Te{static createUserPool(e){let{slug:a,environment:r,userPoolName:n,aliasAttributes:i,autoVerifiedAttributes:o,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:h}=e,y=n||l({slug:a,environment:r,resourceType:"user-pool"}),f=s(y),b={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:y,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(i&&i.length>0)b.Properties.UsernameAttributes=i;if(o&&o.length>0)b.Properties.AutoVerifiedAttributes=o;if(d)b.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)b.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)b.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)b.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(h)b.Properties.AccountRecoverySetting={RecoveryMechanisms:h.recoveryMechanisms};return{userPool:b,logicalId:f}}static createUserPoolClient(e,a){let{slug:r,environment:n,clientName:i,generateSecret:o=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:h,preventUserExistenceErrors:y,enableTokenRevocation:f,callbackURLs:b,logoutURLs:v,allowedOAuthFlows:P,allowedOAuthScopes:R,allowedOAuthFlowsUserPoolClient:T,supportedIdentityProviders:N}=a,I=i||l({slug:r,environment:n,resourceType:"user-pool-client"}),k=s(I);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:I,UserPoolId:w.Ref(e),GenerateSecret:o,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:h,PreventUserExistenceErrors:y,EnableTokenRevocation:f,CallbackURLs:b,LogoutURLs:v,AllowedOAuthFlows:P,AllowedOAuthScopes:R,AllowedOAuthFlowsUserPoolClient:T,SupportedIdentityProviders:N}},logicalId:k}}static createUserPoolDomain(e,a){let{slug:r,environment:n,domain:i,customDomainConfig:o}=a,c=l({slug:r,environment:n,resourceType:"user-pool-domain"}),u=s(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:i,UserPoolId:w.Ref(e),CustomDomainConfig:o}},logicalId:u}}static createIdentityPool(e){let{slug:a,environment:r,identityPoolName:n,allowUnauthenticatedIdentities:i=!1,cognitoIdentityProviders:o,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=n||l({slug:a,environment:r,resourceType:"identity-pool"}),p=s(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:i,CognitoIdentityProviders:o,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,a){let{slug:r,environment:n,authenticatedRole:i,unauthenticatedRole:o,roleMappings:c}=a,u=l({slug:r,environment:n,resourceType:"identity-pool-role-attachment"}),d=s(u),m={authenticated:i};if(o)m.unauthenticated=o;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:w.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-authenticated-role"}),o=s(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":w.Ref(n)},"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:i},{Key:"Environment",Value:r}]}},logicalId:o}}static createUnauthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-unauthenticated-role"}),o=s(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":w.Ref(n)},"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:i},{Key:"Environment",Value:r}]}},logicalId:o}}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,a,r)=>{let{userPool:n,logicalId:i}=Te.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Te.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:o,logicalId:c}=Te.createUserPoolClient(i,{slug:e,environment:a,explicitAuthFlows:[...Te.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Te.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:n,poolId:i,client:o,clientId:c}},mobileApp:(e,a)=>{let{userPool:r,logicalId:n}=Te.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Te.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:o}=Te.createUserPoolClient(n,{slug:e,environment:a,explicitAuthFlows:[...Te.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Te.createIdentityPool({slug:e,environment:a,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:w.Ref(o),ProviderName:w.GetAtt(n,"ProviderName")}]}),{role:d,logicalId:m}=Te.createAuthenticatedRole({slug:e,environment:a,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=Te.createIdentityPoolRoleAttachment(u,{slug:e,environment:a,authenticatedRole:w.GetAtt(m,"Arn")});return{userPool:r,poolId:n,client:i,clientId:o,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}class Ee{static createApplication(e){let{slug:a,environment:r,applicationName:n,computePlatform:i}=e,o=n||l({slug:a,environment:r,resourceType:"deploy-app"}),c=s(o);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:o,ComputePlatform:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,a){let{slug:r,environment:n,deploymentGroupName:i,serviceRoleArn:o,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:h}=a,y=i||l({slug:r,environment:n,resourceType:"deploy-group"}),f=s(y);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:w.Ref(e),DeploymentGroupName:y,ServiceRoleArn:o,AutoScalingGroups:c,Ec2TagFilters:u?.map((b)=>({Key:b.key,Value:b.value,Type:b.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((b)=>({Name:b.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((b)=>({Name:b.name})),ElbInfoList:g.elbInfoList?.map((b)=>({Name:b.name}))}:void 0,BlueGreenDeploymentConfiguration:h?{TerminateBlueInstancesOnDeploymentSuccess:h.terminateBlueInstancesOnDeploymentSuccess?{Action:h.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:h.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:h.deploymentReadyOption?{ActionOnTimeout:h.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:h.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:h.greenFleetProvisioningOption?{Action:h.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}},logicalId:f}}static createDeploymentConfig(e){let{slug:a,environment:r,deploymentConfigName:n,minimumHealthyHosts:i,trafficRoutingConfig:o}=e,c=n||l({slug:a,environment:r,resourceType:"deploy-config"}),u=s(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:i?{Type:i.type,Value:i.value}:void 0,TrafficRoutingConfig:o?{Type:o.type,TimeBasedCanary:o.timeBasedCanary?{CanaryPercentage:o.timeBasedCanary.canaryPercentage,CanaryInterval:o.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:o.timeBasedLinear?{LinearPercentage:o.timeBasedLinear.linearPercentage,LinearInterval:o.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,a)=>({type:e,value:a})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,a)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:a}}),linear:(e,a)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:a}})};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,a,r,n)=>{let{application:i,logicalId:o}=Ee.createApplication({slug:e,environment:a,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=Ee.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,autoScalingGroups:n,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Ee.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,a,r,n=10,i=5)=>{let{application:o,logicalId:c}=Ee.createApplication({slug:e,environment:a,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=Ee.createDeploymentConfig({slug:e,environment:a,trafficRoutingConfig:Ee.TrafficRouting.canary(n,i)}),{deploymentGroup:m,logicalId:p}=Ee.createDeploymentGroup(c,{slug:e,environment:a,serviceRoleArn:r,deploymentConfigName:w.Ref(d),autoRollbackConfiguration:Ee.RollbackConfigs.onAlarmOrFailure()});return{application:o,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,a,r,n)=>{let{application:i,logicalId:o}=Ee.createApplication({slug:e,environment:a,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=Ee.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:n}]},blueGreenDeploymentConfiguration:Ee.BlueGreenConfigs.standard(),autoRollbackConfiguration:Ee.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,a=5)=>({type:"canary",canaryPercentage:e,canaryInterval:a}),allAtOnce:()=>({type:"all-at-once"})}}class ee{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,a="md5"){let r=tt(e);return Gr(a).update(r).digest("hex")}static computeShortHash(e){return ee.computeFileHash(e).slice(0,8)}static getContentType(e){let a=oa(e).toLowerCase();return ee.ContentTypes[a]||"application/octet-stream"}static shouldHashFile(e,a){return![...ee.NoHashPatterns,...a||[]].some((r)=>r.test(e))}static generateHashedFilename(e,a){let r=oa(e),n=jr(e,r),i=sa(e);if(i===".")return`${n}.${a}${r}`;return Ue(i,`${n}.${a}${r}`)}static collectFiles(e,a){let r=[],n=a||e;if(!Ct(e))return r;let i=Fr(e,{withFileTypes:!0});for(let o of i){let c=Ue(e,o.name);if(o.isDirectory())r.push(...ee.collectFiles(c,n));else if(o.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:a,outputDir:r,excludePatterns:n=[],hashAlgorithm:i="md5",copyUnhashed:o=!0}=e,c=ee.collectFiles(a),u=[],d={};for(let p of c){let g=p.replace(a,"").replace(/^[/\\]/,""),h=ee.shouldHashFile(g,n),y=Vr(p),f=h?ee.computeFileHash(p,i).slice(0,8):"",b=h?ee.generateHashedFilename(g,f):g,v={originalPath:g,hashedPath:b,hash:f,size:y.size,contentType:ee.getContentType(p)};if(u.push(v),d[g]=b,r){let P=Ue(r,b),R=sa(P);if(!Ct(R)){let{mkdirSync:T}=or("node:fs");T(R,{recursive:!0})}if(h||o)Ur(p,P)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=Ue(r,"asset-manifest.json");at(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,a){let r=[];if(!e)return["/*"];let n=e.hashMap,i=a.hashMap;for(let[o,c]of Object.entries(i)){let u=n[o];if(!u||u!==c){if(r.push(`/${o}`),u&&u!==c)r.push(`/${u}`)}}for(let[o,c]of Object.entries(n))if(!i[o])r.push(`/${o}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:a,manifest:r,basePath:n=""}=e,i=ee.collectFiles(a).filter((o)=>o.endsWith(".html")||o.endsWith(".htm"));for(let o of i){let c=tt(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${n}/?${ee.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${n}/?${ee.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}at(o,c)}}static updateCssReferences(e){let{cssDir:a,manifest:r,basePath:n=""}=e,i=ee.collectFiles(a).filter((o)=>o.endsWith(".css"));for(let o of i){let c=tt(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${n}/?${ee.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${n}/${d})`)}at(o,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:a,keyPrefix:r="",excludePatterns:n=[],cacheControl:i={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ee.hashDirectory({sourceDir:a,excludePatterns:n}).assets.map((o)=>{let c=o.hash!=="",u=o.contentType==="text/html",d=i.unhashed||"public, max-age=3600";if(u)d=i.html||"public, max-age=0, must-revalidate";else if(c)d=i.hashed||"public, max-age=31536000, immutable";return{localPath:Ue(a,o.originalPath),s3Key:r?`${r}/${o.hashedPath}`:o.hashedPath,contentType:o.contentType,cacheControl:d,hash:o.hash}})}static compareManifests(e,a){let r={added:[],removed:[],changed:[],unchanged:[]},n=new Set(Object.keys(e.hashMap)),i=new Set(Object.keys(a.hashMap));for(let o of i)if(!n.has(o))r.added.push(o);for(let o of n)if(!i.has(o))r.removed.push(o);for(let o of i)if(n.has(o))if(e.hashMap[o]!==a.hashMap[o])r.changed.push(o);else r.unchanged.push(o);return r}static loadManifest(e){if(!Ct(e))return null;try{let a=tt(e,"utf-8");return JSON.parse(a)}catch{return null}}static saveManifest(e,a){at(a,JSON.stringify(e,null,2))}}class fi{static createSecret(e){let{slug:a,environment:r,secretName:n,description:i,secretString:o,kmsKeyId:c,tags:u}=e,d=n||l({slug:a,environment:r,resourceType:"secret"}),m=s(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:i,SecretString:o,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,h])=>({Key:g,Value:h})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:a,environment:r,secretName:n,description:i,excludeCharacters:o,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:h,tags:y}=e,f=n||l({slug:a,environment:r,resourceType:"secret"}),b=s(f),v={Type:"AWS::SecretsManager::Secret",Properties:{Name:f,Description:i,GenerateSecretString:{ExcludeCharacters:o,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r},...y?Object.entries(y).map(([P,R])=>({Key:P,Value:R})):[]]}};if(h)v.Properties.KmsKeyId=h;return{secret:v,logicalId:b}}static createDatabaseSecret(e){let{slug:a,environment:r,secretName:n,username:i,dbname:o,engine:c,host:u,port:d,kmsKeyId:m}=e,p=n||l({slug:a,environment:r,resourceType:"db-secret"}),g=s(p),h={username:i};if(o)h.dbname=o;if(c)h.engine=c;if(u)h.host=u;if(d)h.port=d;let y={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${i}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(h),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)y.Properties.KmsKeyId=m;return{secret:y,logicalId:g}}static attachToDatabase(e){let{slug:a,environment:r,secretId:n,targetId:i,targetType:o}=e,c=l({slug:a,environment:r,resourceType:"secret-attachment"}),u=s(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:n,TargetId:i,TargetType:o}},logicalId:u}}static enableRotation(e){let{slug:a,environment:r,secretId:n,rotationLambdaArn:i,automaticallyAfterDays:o,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:a,environment:r,resourceType:"secret-rotation"}),g=s(p),h={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:n,RotationRules:{AutomaticallyAfterDays:o||30}}};if(i)h.Properties.RotationLambdaARN=i;else if(c)h.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:h,logicalId:g}}static SecretTypes={apiKey:(e,a,r)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,a,r)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,a)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,a)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-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 G{static createParameter(e){let{slug:a,environment:r,parameterName:n,value:i,type:o="String",description:c,tier:u="Standard",tags:d}=e,m=n||l({slug:a,environment:r,resourceType:"parameter"}),p=s(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${a}/${r}/${m}`,Type:o,Value:i,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,a,r,n,i){return G.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"String",description:i})}static createSecureString(e,a,r,n,i){return G.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"SecureString",description:i})}static createStringList(e,a,r,n,i){return G.createParameter({slug:e,environment:a,parameterName:r,value:n.join(","),type:"StringList",description:i})}static Parameters={databaseUrl:(e,a,r)=>G.createSecureString(e,a,"database-url",r,"Database connection URL"),apiEndpoint:(e,a,r)=>G.createString(e,a,"api-endpoint",r,"API endpoint URL"),appVersion:(e,a,r)=>G.createString(e,a,"app-version",r,"Application version"),featureFlags:(e,a,r)=>G.createStringList(e,a,"feature-flags",r,"Enabled feature flags"),apiKey:(e,a,r,n)=>G.createSecureString(e,a,`${r}-api-key`,n,`API key for ${r}`),oauthCredentials:(e,a,r,n)=>{let i=G.createString(e,a,"oauth-client-id",r,"OAuth client ID"),o=G.createSecureString(e,a,"oauth-client-secret",n,"OAuth client secret");return{clientId:i,clientSecret:o}},smtpCredentials:(e,a,r,n,i,o)=>{let c=G.createString(e,a,"smtp-username",r,"SMTP username"),u=G.createSecureString(e,a,"smtp-password",n,"SMTP password"),d=G.createString(e,a,"smtp-host",i,"SMTP host"),m=G.createString(e,a,"smtp-port",o.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,a,r)=>G.createSecureString(e,a,"redis-url",r,"Redis connection URL"),s3Bucket:(e,a,r)=>G.createString(e,a,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,a,r)=>G.createString(e,a,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Bt{static createDomain(e){let{slug:a,environment:r,domainName:n,engineVersion:i="OpenSearch_2.11",instanceType:o="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:h=!1,availabilityZoneCount:y=2,vpc:f,encryption:b,enforceHttps:v=!0,tlsSecurityPolicy:P="Policy-Min-TLS-1-2-2019-07",advancedSecurity:R,autoSnapshotHour:T=0,autoTune:N=!0,tags:I={}}=e,k=n||l({slug:a,environment:r,resourceType:"search"}),x=s(k);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:k,EngineVersion:i,ClusterConfig:{InstanceType:o,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||o,DedicatedMasterCount:g},ZoneAwarenessEnabled:h,...h&&{ZoneAwarenessConfig:{AvailabilityZoneCount:y}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:v,TLSSecurityPolicy:P},SnapshotOptions:{AutomatedSnapshotStartHour:T},...f&&{VPCOptions:{SubnetIds:f.subnetIds,SecurityGroupIds:f.securityGroupIds}},...b&&{EncryptionAtRestOptions:{Enabled:b.atRest??!0,...b.kmsKeyId&&{KmsKeyId:b.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:b.nodeToNode??!0}},...R&&{AdvancedSecurityOptions:{Enabled:R.enabled,InternalUserDatabaseEnabled:R.internalUserDatabase??!0,...R.masterUserName&&R.masterUserPassword&&{MasterUserOptions:{MasterUserName:R.masterUserName,MasterUserPassword:R.masterUserPassword}},...R.masterUserArn&&{MasterUserOptions:{MasterUserARN:R.masterUserArn}}}},...N&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:r},...Object.entries(I).map(([L,O])=>({Key:L,Value:O}))]}},logicalId:x}}static createAccessPolicy(e,a){let{ipAddresses:r,iamPrincipalArns:n,allowAll:i,vpcEndpoint:o}=a;if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(n&&n.length>0)c.push({Effect:"Allow",Principal:{AWS:n},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(o)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,a)=>Bt.createDomain({slug:e,environment:a,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,a,r)=>Bt.createDomain({slug:e,environment:a,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,a)=>Bt.createDomain({slug:e,environment:a,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,a,r)=>Bt.createDomain({slug:e,environment:a,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 Et{static createDomainRedirectBucket(e){let{slug:a,environment:r,sourceDomain:n,targetDomain:i,protocol:o="https"}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"redirect"}),u=s(c),d=s(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:n,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:o}},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:w.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[w.Join("",[w.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:a,environment:r,rules:n}=e,i=l({slug:a,environment:r,resourceType:"cf-redirect"}),o=s(i),c=Et.generateRedirectFunctionCode(n);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:i,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${a} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:o,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2316
|
+
| limit 50`,region:n,title:"Recent Errors and Warnings"}}),c+=6;return gi.createDashboard({slug:a,environment:r,widgets:o})}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((a,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${a} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",a],["AWS/Lambda","Duration","FunctionName",a],["AWS/Lambda","Errors","FunctionName",a]],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:a,namespace:r,threshold:n,comparisonOperator:i="GreaterThanThreshold",evaluationPeriods:o=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:a,Namespace:r,Threshold:n,ComparisonOperator:i,EvaluationPeriods:o,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 Te{static createUserPool(e){let{slug:a,environment:r,userPoolName:n,aliasAttributes:i,autoVerifiedAttributes:o,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:h}=e,y=n||l({slug:a,environment:r,resourceType:"user-pool"}),f=s(y),b={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:y,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(i&&i.length>0)b.Properties.UsernameAttributes=i;if(o&&o.length>0)b.Properties.AutoVerifiedAttributes=o;if(d)b.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)b.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)b.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)b.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(h)b.Properties.AccountRecoverySetting={RecoveryMechanisms:h.recoveryMechanisms};return{userPool:b,logicalId:f}}static createUserPoolClient(e,a){let{slug:r,environment:n,clientName:i,generateSecret:o=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:h,preventUserExistenceErrors:y,enableTokenRevocation:f,callbackURLs:b,logoutURLs:v,allowedOAuthFlows:P,allowedOAuthScopes:R,allowedOAuthFlowsUserPoolClient:T,supportedIdentityProviders:N}=a,I=i||l({slug:r,environment:n,resourceType:"user-pool-client"}),k=s(I);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:I,UserPoolId:w.Ref(e),GenerateSecret:o,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:h,PreventUserExistenceErrors:y,EnableTokenRevocation:f,CallbackURLs:b,LogoutURLs:v,AllowedOAuthFlows:P,AllowedOAuthScopes:R,AllowedOAuthFlowsUserPoolClient:T,SupportedIdentityProviders:N}},logicalId:k}}static createUserPoolDomain(e,a){let{slug:r,environment:n,domain:i,customDomainConfig:o}=a,c=l({slug:r,environment:n,resourceType:"user-pool-domain"}),u=s(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:i,UserPoolId:w.Ref(e),CustomDomainConfig:o}},logicalId:u}}static createIdentityPool(e){let{slug:a,environment:r,identityPoolName:n,allowUnauthenticatedIdentities:i=!1,cognitoIdentityProviders:o,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=n||l({slug:a,environment:r,resourceType:"identity-pool"}),p=s(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:i,CognitoIdentityProviders:o,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,a){let{slug:r,environment:n,authenticatedRole:i,unauthenticatedRole:o,roleMappings:c}=a,u=l({slug:r,environment:n,resourceType:"identity-pool-role-attachment"}),d=s(u),m={authenticated:i};if(o)m.unauthenticated=o;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:w.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-authenticated-role"}),o=s(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":w.Ref(n)},"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:i},{Key:"Environment",Value:r}]}},logicalId:o}}static createUnauthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-unauthenticated-role"}),o=s(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":w.Ref(n)},"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:i},{Key:"Environment",Value:r}]}},logicalId:o}}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,a,r)=>{let{userPool:n,logicalId:i}=Te.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Te.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:o,logicalId:c}=Te.createUserPoolClient(i,{slug:e,environment:a,explicitAuthFlows:[...Te.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Te.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:n,poolId:i,client:o,clientId:c}},mobileApp:(e,a)=>{let{userPool:r,logicalId:n}=Te.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Te.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:o}=Te.createUserPoolClient(n,{slug:e,environment:a,explicitAuthFlows:[...Te.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Te.createIdentityPool({slug:e,environment:a,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:w.Ref(o),ProviderName:w.GetAtt(n,"ProviderName")}]}),{role:d,logicalId:m}=Te.createAuthenticatedRole({slug:e,environment:a,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=Te.createIdentityPoolRoleAttachment(u,{slug:e,environment:a,authenticatedRole:w.GetAtt(m,"Arn")});return{userPool:r,poolId:n,client:i,clientId:o,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}class Ee{static createApplication(e){let{slug:a,environment:r,applicationName:n,computePlatform:i}=e,o=n||l({slug:a,environment:r,resourceType:"deploy-app"}),c=s(o);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:o,ComputePlatform:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,a){let{slug:r,environment:n,deploymentGroupName:i,serviceRoleArn:o,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:h}=a,y=i||l({slug:r,environment:n,resourceType:"deploy-group"}),f=s(y);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:w.Ref(e),DeploymentGroupName:y,ServiceRoleArn:o,AutoScalingGroups:c,Ec2TagFilters:u?.map((b)=>({Key:b.key,Value:b.value,Type:b.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((b)=>({Name:b.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((b)=>({Name:b.name})),ElbInfoList:g.elbInfoList?.map((b)=>({Name:b.name}))}:void 0,BlueGreenDeploymentConfiguration:h?{TerminateBlueInstancesOnDeploymentSuccess:h.terminateBlueInstancesOnDeploymentSuccess?{Action:h.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:h.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:h.deploymentReadyOption?{ActionOnTimeout:h.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:h.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:h.greenFleetProvisioningOption?{Action:h.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}},logicalId:f}}static createDeploymentConfig(e){let{slug:a,environment:r,deploymentConfigName:n,minimumHealthyHosts:i,trafficRoutingConfig:o}=e,c=n||l({slug:a,environment:r,resourceType:"deploy-config"}),u=s(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:i?{Type:i.type,Value:i.value}:void 0,TrafficRoutingConfig:o?{Type:o.type,TimeBasedCanary:o.timeBasedCanary?{CanaryPercentage:o.timeBasedCanary.canaryPercentage,CanaryInterval:o.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:o.timeBasedLinear?{LinearPercentage:o.timeBasedLinear.linearPercentage,LinearInterval:o.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,a)=>({type:e,value:a})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,a)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:a}}),linear:(e,a)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:a}})};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,a,r,n)=>{let{application:i,logicalId:o}=Ee.createApplication({slug:e,environment:a,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=Ee.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,autoScalingGroups:n,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Ee.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,a,r,n=10,i=5)=>{let{application:o,logicalId:c}=Ee.createApplication({slug:e,environment:a,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=Ee.createDeploymentConfig({slug:e,environment:a,trafficRoutingConfig:Ee.TrafficRouting.canary(n,i)}),{deploymentGroup:m,logicalId:p}=Ee.createDeploymentGroup(c,{slug:e,environment:a,serviceRoleArn:r,deploymentConfigName:w.Ref(d),autoRollbackConfiguration:Ee.RollbackConfigs.onAlarmOrFailure()});return{application:o,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,a,r,n)=>{let{application:i,logicalId:o}=Ee.createApplication({slug:e,environment:a,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=Ee.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:n}]},blueGreenDeploymentConfiguration:Ee.BlueGreenConfigs.standard(),autoRollbackConfiguration:Ee.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,a=5)=>({type:"canary",canaryPercentage:e,canaryInterval:a}),allAtOnce:()=>({type:"all-at-once"})}}class ee{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,a="md5"){let r=tt(e);return Gr(a).update(r).digest("hex")}static computeShortHash(e){return ee.computeFileHash(e).slice(0,8)}static getContentType(e){let a=oa(e).toLowerCase();return ee.ContentTypes[a]||"application/octet-stream"}static shouldHashFile(e,a){return![...ee.NoHashPatterns,...a||[]].some((r)=>r.test(e))}static generateHashedFilename(e,a){let r=oa(e),n=jr(e,r),i=sa(e);if(i===".")return`${n}.${a}${r}`;return Ue(i,`${n}.${a}${r}`)}static collectFiles(e,a){let r=[],n=a||e;if(!Ct(e))return r;let i=Fr(e,{withFileTypes:!0});for(let o of i){let c=Ue(e,o.name);if(o.isDirectory())r.push(...ee.collectFiles(c,n));else if(o.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:a,outputDir:r,excludePatterns:n=[],hashAlgorithm:i="md5",copyUnhashed:o=!0}=e,c=ee.collectFiles(a),u=[],d={};for(let p of c){let g=p.replace(a,"").replace(/^[/\\]/,""),h=ee.shouldHashFile(g,n),y=Vr(p),f=h?ee.computeFileHash(p,i).slice(0,8):"",b=h?ee.generateHashedFilename(g,f):g,v={originalPath:g,hashedPath:b,hash:f,size:y.size,contentType:ee.getContentType(p)};if(u.push(v),d[g]=b,r){let P=Ue(r,b),R=sa(P);if(!Ct(R)){let{mkdirSync:T}=or("node:fs");T(R,{recursive:!0})}if(h||o)Ur(p,P)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=Ue(r,"asset-manifest.json");at(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,a){let r=[];if(!e)return["/*"];let n=e.hashMap,i=a.hashMap;for(let[o,c]of Object.entries(i)){let u=n[o];if(!u||u!==c){if(r.push(`/${o}`),u&&u!==c)r.push(`/${u}`)}}for(let[o,c]of Object.entries(n))if(!i[o])r.push(`/${o}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:a,manifest:r,basePath:n=""}=e,i=ee.collectFiles(a).filter((o)=>o.endsWith(".html")||o.endsWith(".htm"));for(let o of i){let c=tt(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${n}/?${ee.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${n}/?${ee.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}at(o,c)}}static updateCssReferences(e){let{cssDir:a,manifest:r,basePath:n=""}=e,i=ee.collectFiles(a).filter((o)=>o.endsWith(".css"));for(let o of i){let c=tt(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${n}/?${ee.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${n}/${d})`)}at(o,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:a,keyPrefix:r="",excludePatterns:n=[],cacheControl:i={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ee.hashDirectory({sourceDir:a,excludePatterns:n}).assets.map((o)=>{let c=o.hash!=="",u=o.contentType==="text/html",d=i.unhashed||"public, max-age=3600";if(u)d=i.html||"public, max-age=0, must-revalidate";else if(c)d=i.hashed||"public, max-age=31536000, immutable";return{localPath:Ue(a,o.originalPath),s3Key:r?`${r}/${o.hashedPath}`:o.hashedPath,contentType:o.contentType,cacheControl:d,hash:o.hash}})}static compareManifests(e,a){let r={added:[],removed:[],changed:[],unchanged:[]},n=new Set(Object.keys(e.hashMap)),i=new Set(Object.keys(a.hashMap));for(let o of i)if(!n.has(o))r.added.push(o);for(let o of n)if(!i.has(o))r.removed.push(o);for(let o of i)if(n.has(o))if(e.hashMap[o]!==a.hashMap[o])r.changed.push(o);else r.unchanged.push(o);return r}static loadManifest(e){if(!Ct(e))return null;try{let a=tt(e,"utf-8");return JSON.parse(a)}catch{return null}}static saveManifest(e,a){at(a,JSON.stringify(e,null,2))}}class fi{static createSecret(e){let{slug:a,environment:r,secretName:n,description:i,secretString:o,kmsKeyId:c,tags:u}=e,d=n||l({slug:a,environment:r,resourceType:"secret"}),m=s(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:i,SecretString:o,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,h])=>({Key:g,Value:h})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:a,environment:r,secretName:n,description:i,excludeCharacters:o,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:h,tags:y}=e,f=n||l({slug:a,environment:r,resourceType:"secret"}),b=s(f),v={Type:"AWS::SecretsManager::Secret",Properties:{Name:f,Description:i,GenerateSecretString:{ExcludeCharacters:o,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r},...y?Object.entries(y).map(([P,R])=>({Key:P,Value:R})):[]]}};if(h)v.Properties.KmsKeyId=h;return{secret:v,logicalId:b}}static createDatabaseSecret(e){let{slug:a,environment:r,secretName:n,username:i,dbname:o,engine:c,host:u,port:d,kmsKeyId:m}=e,p=n||l({slug:a,environment:r,resourceType:"db-secret"}),g=s(p),h={username:i};if(o)h.dbname=o;if(c)h.engine=c;if(u)h.host=u;if(d)h.port=d;let y={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${i}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(h),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)y.Properties.KmsKeyId=m;return{secret:y,logicalId:g}}static attachToDatabase(e){let{slug:a,environment:r,secretId:n,targetId:i,targetType:o}=e,c=l({slug:a,environment:r,resourceType:"secret-attachment"}),u=s(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:n,TargetId:i,TargetType:o}},logicalId:u}}static enableRotation(e){let{slug:a,environment:r,secretId:n,rotationLambdaArn:i,automaticallyAfterDays:o,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:a,environment:r,resourceType:"secret-rotation"}),g=s(p),h={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:n,RotationRules:{AutomaticallyAfterDays:o||30}}};if(i)h.Properties.RotationLambdaARN=i;else if(c)h.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:h,logicalId:g}}static SecretTypes={apiKey:(e,a,r)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,a,r)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,a)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,a)=>fi.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-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 G{static createParameter(e){let{slug:a,environment:r,parameterName:n,value:i,type:o="String",description:c,tier:u="Standard",tags:d}=e,m=n||l({slug:a,environment:r,resourceType:"parameter"}),p=s(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${a}/${r}/${m}`,Type:o,Value:i,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,a,r,n,i){return G.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"String",description:i})}static createSecureString(e,a,r,n,i){return G.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"SecureString",description:i})}static createStringList(e,a,r,n,i){return G.createParameter({slug:e,environment:a,parameterName:r,value:n.join(","),type:"StringList",description:i})}static Parameters={databaseUrl:(e,a,r)=>G.createSecureString(e,a,"database-url",r,"Database connection URL"),apiEndpoint:(e,a,r)=>G.createString(e,a,"api-endpoint",r,"API endpoint URL"),appVersion:(e,a,r)=>G.createString(e,a,"app-version",r,"Application version"),featureFlags:(e,a,r)=>G.createStringList(e,a,"feature-flags",r,"Enabled feature flags"),apiKey:(e,a,r,n)=>G.createSecureString(e,a,`${r}-api-key`,n,`API key for ${r}`),oauthCredentials:(e,a,r,n)=>{let i=G.createString(e,a,"oauth-client-id",r,"OAuth client ID"),o=G.createSecureString(e,a,"oauth-client-secret",n,"OAuth client secret");return{clientId:i,clientSecret:o}},smtpCredentials:(e,a,r,n,i,o)=>{let c=G.createString(e,a,"smtp-username",r,"SMTP username"),u=G.createSecureString(e,a,"smtp-password",n,"SMTP password"),d=G.createString(e,a,"smtp-host",i,"SMTP host"),m=G.createString(e,a,"smtp-port",o.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,a,r)=>G.createSecureString(e,a,"redis-url",r,"Redis connection URL"),s3Bucket:(e,a,r)=>G.createString(e,a,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,a,r)=>G.createString(e,a,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Ft{static createDomain(e){let{slug:a,environment:r,domainName:n,engineVersion:i="OpenSearch_2.11",instanceType:o="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:h=!1,availabilityZoneCount:y=2,vpc:f,encryption:b,enforceHttps:v=!0,tlsSecurityPolicy:P="Policy-Min-TLS-1-2-2019-07",advancedSecurity:R,autoSnapshotHour:T=0,autoTune:N=!0,tags:I={}}=e,k=n||l({slug:a,environment:r,resourceType:"search"}),x=s(k);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:k,EngineVersion:i,ClusterConfig:{InstanceType:o,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||o,DedicatedMasterCount:g},ZoneAwarenessEnabled:h,...h&&{ZoneAwarenessConfig:{AvailabilityZoneCount:y}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:v,TLSSecurityPolicy:P},SnapshotOptions:{AutomatedSnapshotStartHour:T},...f&&{VPCOptions:{SubnetIds:f.subnetIds,SecurityGroupIds:f.securityGroupIds}},...b&&{EncryptionAtRestOptions:{Enabled:b.atRest??!0,...b.kmsKeyId&&{KmsKeyId:b.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:b.nodeToNode??!0}},...R&&{AdvancedSecurityOptions:{Enabled:R.enabled,InternalUserDatabaseEnabled:R.internalUserDatabase??!0,...R.masterUserName&&R.masterUserPassword&&{MasterUserOptions:{MasterUserName:R.masterUserName,MasterUserPassword:R.masterUserPassword}},...R.masterUserArn&&{MasterUserOptions:{MasterUserARN:R.masterUserArn}}}},...N&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:r},...Object.entries(I).map(([L,O])=>({Key:L,Value:O}))]}},logicalId:x}}static createAccessPolicy(e,a){let{ipAddresses:r,iamPrincipalArns:n,allowAll:i,vpcEndpoint:o}=a;if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(n&&n.length>0)c.push({Effect:"Allow",Principal:{AWS:n},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(o)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,a)=>Ft.createDomain({slug:e,environment:a,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,a,r)=>Ft.createDomain({slug:e,environment:a,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,a)=>Ft.createDomain({slug:e,environment:a,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,a,r)=>Ft.createDomain({slug:e,environment:a,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 Et{static createDomainRedirectBucket(e){let{slug:a,environment:r,sourceDomain:n,targetDomain:i,protocol:o="https"}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"redirect"}),u=s(c),d=s(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:n,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:o}},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:w.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[w.Join("",[w.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:a,environment:r,rules:n}=e,i=l({slug:a,environment:r,resourceType:"cf-redirect"}),o=s(i),c=Et.generateRedirectFunctionCode(n);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:i,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${a} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:o,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2317
2317
|
const request = event.request;
|
|
2318
2318
|
const uri = request.uri;
|
|
2319
2319
|
const querystring = request.querystring;
|
|
@@ -2465,7 +2465,7 @@ exports.handler = async (event) => {
|
|
|
2465
2465
|
console.log('Receive SMS:', JSON.stringify(event, null, 2));
|
|
2466
2466
|
// Process inbound SMS, handle opt-out keywords
|
|
2467
2467
|
return { statusCode: 200 };
|
|
2468
|
-
};`}var t={ref:(e)=>({Ref:e}),getAtt:(e,a)=>({"Fn::GetAtt":[e,a]}),join:(e,a)=>({"Fn::Join":[e,a]}),sub:(e,a)=>a?{"Fn::Sub":[e,a]}:{"Fn::Sub":e},select:(e,a)=>({"Fn::Select":[e,a]}),split:(e,a)=>({"Fn::Split":[e,a]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,a,r)=>({"Fn::FindInMap":[e,a,r]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,a,r)=>({"Fn::Cidr":[e,a,r]}),equals:(e,a)=>({"Fn::Equals":[e,a]}),if:(e,a,r)=>({"Fn::If":[e,a,r]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},To={s3Bucket:(e)=>t.sub(`arn:aws:s3:::${e}`),s3Object:(e,a="*")=>t.sub(`arn:aws:s3:::${e}/${a}`),lambda:(e,a,r)=>t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,a&&r?{"AWS::Region":a,"AWS::AccountId":r}:void 0),dynamodb:(e)=>t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>t.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>t.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,a)=>t.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${a}`),secretsManager:(e)=>t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>t.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},ip={ACCOUNT_ID:{Ref:"AWS::AccountId"},NOTIFICATION_ARNS:{Ref:"AWS::NotificationARNs"},NO_VALUE:{Ref:"AWS::NoValue"},PARTITION:{Ref:"AWS::Partition"},REGION:{Ref:"AWS::Region"},STACK_ID:{Ref:"AWS::StackId"},STACK_NAME:{Ref:"AWS::StackName"},URL_SUFFIX:{Ref:"AWS::URLSuffix"}};function Kr(e,a){if(a.type==="http")Hr(e,a);else if(a.type==="rest")qr(e,a);else if(a.type==="websocket")zr(e,a)}function Hr(e,a){let r={Name:t.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(a.cors)r.CorsConfiguration={AllowOrigins:a.cors.allowOrigins,AllowMethods:a.cors.allowMethods,AllowHeaders:a.cors.allowHeaders||["*"],MaxAge:a.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",r),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:a.throttling?{ThrottlingBurstLimit:a.throttling.burstLimit,ThrottlingRateLimit:a.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:t.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:t.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),a.authorizer)Qr(e,"HttpApi",a.authorizer);if(a.customDomain)Wt(e,"HttpApi",a.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:t.ref("HttpApi"),Export:{Name:t.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-http-api-endpoint")}}})}function qr(e,a){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:t.sub("${AWS::StackName}-rest-api"),Description:t.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:t.getAtt("ApiGatewayCloudWatchRole","Arn")},{dependsOn:"ApiGatewayCloudWatchRole"}),e.addResource("ApiGatewayCloudWatchRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"apigateway.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"]}),e.addResource("RestApiDeployment","AWS::ApiGateway::Deployment",{RestApiId:t.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let r={RestApiId:t.ref("RestApi"),DeploymentId:t.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(a.throttling)r.MethodSettings[0].ThrottlingBurstLimit=a.throttling.burstLimit,r.MethodSettings[0].ThrottlingRateLimit=a.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",r,{dependsOn:["RestApi","RestApiDeployment"]}),a.customDomain)Wt(e,"RestApi",a.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:t.ref("RestApi"),Export:{Name:t.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:t.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:t.sub("${AWS::StackName}-rest-api-endpoint")}}})}function zr(e,a){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:t.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),a.routes){if(a.routes.connect)rt(e,"$connect",a.routes.connect.functionName);if(a.routes.disconnect)rt(e,"$disconnect",a.routes.disconnect.functionName);if(a.routes.default)rt(e,"$default",a.routes.default.functionName);if(a.routes.custom)a.routes.custom.forEach((r)=>{rt(e,r.routeKey,r.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:a.throttling?{ThrottlingBurstLimit:a.throttling.burstLimit,ThrottlingRateLimit:a.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),a.customDomain)Wt(e,"WebSocketApi",a.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:t.ref("WebSocketApi"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:t.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function rt(e,a,r){let n=e.toLogicalId(`websocket-route-${a}`),i=e.toLogicalId(`websocket-integration-${a}`),o=e.toLogicalId(`${r}-function`);e.addResource(i,"AWS::ApiGatewayV2::Integration",{ApiId:t.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:t.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${o}.Arn}/invocations`)},{dependsOn:["WebSocketApi",o]}),e.addResource(n,"AWS::ApiGatewayV2::Route",{ApiId:t.ref("WebSocketApi"),RouteKey:a,Target:t.join("/",["integrations",t.ref(i)])},{dependsOn:["WebSocketApi",i]}),e.addResource(`${n}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(o),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[o,"WebSocketApi"]})}function Wt(e,a,r,n){let i={DomainName:r.domain};if(n==="REST")i.CertificateArn=r.certificateArn,i.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",i),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:t.ref("ApiCustomDomain"),RestApiId:t.ref(a),Stage:t.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",a,"RestApiStage"]});else i.DomainNameConfigurations=[{CertificateArn:r.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",i),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:t.ref(a),DomainName:t.ref("ApiCustomDomain"),Stage:n==="HTTP"?t.ref("HttpApiStage"):t.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",a]});if(r.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${Jr(r.domain)}.`),Name:r.domain,Type:"A",AliasTarget:{HostedZoneId:t.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:t.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:r.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:t.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:t.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function Qr(e,a,r){if(!r)return;if(r.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(a),AuthorizerType:"JWT",IdentitySource:[r.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:r.issuer,Audience:r.audience},Name:"JWTAuthorizer"},{dependsOn:a});else if(r.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(a),AuthorizerType:"REQUEST",AuthorizerUri:r.authorizerUri,IdentitySource:[r.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:a})}function Jr(e){let a=e.split(".");if(a.length>=2)return a.slice(-2).join(".");return e}function Yr(e,a){if(a.redis)Zr(e,a.redis);if(a.memcached)Xr(e,a.memcached);if(a.elasticache)en(e,a.elasticache)}function Zr(e,a){if(!a)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:a.port||6379,ToPort:a.port||6379,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),a.parameterGroup&&Object.keys(a.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${a.engineVersion.split(".")[0]}`,Properties:a.parameterGroup});if(a.numCacheNodes>1||a.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheClusters:a.numCacheNodes,AutomaticFailoverEnabled:a.automaticFailoverEnabled||!1,MultiAZEnabled:a.automaticFailoverEnabled||!1,Port:a.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:a.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:a.snapshotRetentionLimit||5,SnapshotWindow:a.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:a.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheNodes:1,Port:a.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:a.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:a.snapshotRetentionLimit||5,SnapshotWindow:a.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:a.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}})}function Xr(e,a){if(!a)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:a.port||11211,ToPort:a.port||11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheNodes:a.numCacheNodes,Port:a.port||11211,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-memcached-port")}}})}function en(e,a){if(!a)return;let r=a.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:r?6379:11211,ToPort:r?6379:11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub(`\${AWS::StackName}-${a.engine}`),Engine:a.engine,EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheNodes:a.numCacheNodes,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${a.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function tn(e,a){if(!a.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:t.sub("${AWS::StackName} CloudFront OAI")}});let r=[],n=[];if(!a.origins||a.origins.length===0)r.push({Id:"S3Origin",DomainName:t.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else a.origins.forEach((c,u)=>{let d={Id:c.id,DomainName:c.domainName};if(c.originPath)d.OriginPath=c.originPath;if(c.domainName.includes("s3"))d.S3OriginConfig={OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(r.push(d),u>0||c.pathPattern)n.push({PathPattern:c.pathPattern||`/${c.id}/*`,TargetOriginId:c.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:a.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:a.cachePolicy?.minTTL||0,DefaultTTL:a.cachePolicy?.defaultTTL||86400,MaxTTL:a.cachePolicy?.maxTTL||31536000})});let i={TargetOriginId:r[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:a.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:a.cachePolicy?.minTTL||0,DefaultTTL:a.cachePolicy?.defaultTTL||86400,MaxTTL:a.cachePolicy?.maxTTL||31536000};if(a.edgeFunctions&&a.edgeFunctions.length>0)i.LambdaFunctionAssociations=a.edgeFunctions.map((c)=>({EventType:c.eventType,LambdaFunctionARN:c.functionArn}));let o={Enabled:!0,HttpVersion:a.http3?"http3":"http2",IPV6Enabled:!0,Origins:r,DefaultCacheBehavior:i,PriceClass:a.priceClass||"PriceClass_100",ViewerCertificate:{}};if(n.length>0)o.CacheBehaviors=n;if(a.customDomain)o.Aliases=[a.customDomain.domain],o.ViewerCertificate={AcmCertificateArn:a.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else o.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(a.errorPages)o.CustomErrorResponses=Object.entries(a.errorPages).map(([c,u])=>({ErrorCode:Number.parseInt(c),ResponseCode:200,ResponsePagePath:u,ErrorCachingMinTTL:300}));if(o.DefaultRootObject="index.html",o.Comment=t.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:o},{dependsOn:"CloudFrontOriginAccessIdentity"}),!a.origins||a.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:t.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:t.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:t.join("",[t.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(a.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${an(a.customDomain.domain)}.`),Name:a.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:t.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:t.ref("CloudFrontDistribution"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:t.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-domain")}}}),a.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:t.sub(`https://${a.customDomain.domain}`)}})}function an(e){let a=e.split(".");if(a.length>=2)return a.slice(-2).join(".");return e}function cn(e,a){if(a.server)ln(e,a.server);if(a.fargate)ca(e,"app",a.fargate);if(a.services)a.services.forEach((r)=>{if(r.type==="fargate")ca(e,r.name,{taskDefinition:r.taskDefinition,service:r.service})})}function ln(e,a){if(!a)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:t.ref("ALBSecurityGroup")},{IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-app-sg")}]},{dependsOn:"VPC"}),e.addResource("EC2InstanceRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[t.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let r=a.userData||`#!/bin/bash
|
|
2468
|
+
};`}var t={ref:(e)=>({Ref:e}),getAtt:(e,a)=>({"Fn::GetAtt":[e,a]}),join:(e,a)=>({"Fn::Join":[e,a]}),sub:(e,a)=>a?{"Fn::Sub":[e,a]}:{"Fn::Sub":e},select:(e,a)=>({"Fn::Select":[e,a]}),split:(e,a)=>({"Fn::Split":[e,a]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,a,r)=>({"Fn::FindInMap":[e,a,r]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,a,r)=>({"Fn::Cidr":[e,a,r]}),equals:(e,a)=>({"Fn::Equals":[e,a]}),if:(e,a,r)=>({"Fn::If":[e,a,r]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},To={s3Bucket:(e)=>t.sub(`arn:aws:s3:::${e}`),s3Object:(e,a="*")=>t.sub(`arn:aws:s3:::${e}/${a}`),lambda:(e,a,r)=>t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,a&&r?{"AWS::Region":a,"AWS::AccountId":r}:void 0),dynamodb:(e)=>t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>t.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>t.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,a)=>t.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${a}`),secretsManager:(e)=>t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>t.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},ip={ACCOUNT_ID:{Ref:"AWS::AccountId"},NOTIFICATION_ARNS:{Ref:"AWS::NotificationARNs"},NO_VALUE:{Ref:"AWS::NoValue"},PARTITION:{Ref:"AWS::Partition"},REGION:{Ref:"AWS::Region"},STACK_ID:{Ref:"AWS::StackId"},STACK_NAME:{Ref:"AWS::StackName"},URL_SUFFIX:{Ref:"AWS::URLSuffix"}};function Kr(e,a){if(a.type==="http")Hr(e,a);else if(a.type==="rest")qr(e,a);else if(a.type==="websocket")zr(e,a)}function Hr(e,a){let r={Name:t.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(a.cors)r.CorsConfiguration={AllowOrigins:a.cors.allowOrigins,AllowMethods:a.cors.allowMethods,AllowHeaders:a.cors.allowHeaders||["*"],MaxAge:a.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",r),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:a.throttling?{ThrottlingBurstLimit:a.throttling.burstLimit,ThrottlingRateLimit:a.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:t.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:t.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),a.authorizer)Qr(e,"HttpApi",a.authorizer);if(a.customDomain)_t(e,"HttpApi",a.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:t.ref("HttpApi"),Export:{Name:t.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-http-api-endpoint")}}})}function qr(e,a){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:t.sub("${AWS::StackName}-rest-api"),Description:t.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:t.getAtt("ApiGatewayCloudWatchRole","Arn")},{dependsOn:"ApiGatewayCloudWatchRole"}),e.addResource("ApiGatewayCloudWatchRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"apigateway.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"]}),e.addResource("RestApiDeployment","AWS::ApiGateway::Deployment",{RestApiId:t.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let r={RestApiId:t.ref("RestApi"),DeploymentId:t.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(a.throttling)r.MethodSettings[0].ThrottlingBurstLimit=a.throttling.burstLimit,r.MethodSettings[0].ThrottlingRateLimit=a.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",r,{dependsOn:["RestApi","RestApiDeployment"]}),a.customDomain)_t(e,"RestApi",a.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:t.ref("RestApi"),Export:{Name:t.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:t.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:t.sub("${AWS::StackName}-rest-api-endpoint")}}})}function zr(e,a){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:t.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),a.routes){if(a.routes.connect)rt(e,"$connect",a.routes.connect.functionName);if(a.routes.disconnect)rt(e,"$disconnect",a.routes.disconnect.functionName);if(a.routes.default)rt(e,"$default",a.routes.default.functionName);if(a.routes.custom)a.routes.custom.forEach((r)=>{rt(e,r.routeKey,r.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:a.throttling?{ThrottlingBurstLimit:a.throttling.burstLimit,ThrottlingRateLimit:a.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),a.customDomain)_t(e,"WebSocketApi",a.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:t.ref("WebSocketApi"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:t.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function rt(e,a,r){let n=e.toLogicalId(`websocket-route-${a}`),i=e.toLogicalId(`websocket-integration-${a}`),o=e.toLogicalId(`${r}-function`);e.addResource(i,"AWS::ApiGatewayV2::Integration",{ApiId:t.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:t.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${o}.Arn}/invocations`)},{dependsOn:["WebSocketApi",o]}),e.addResource(n,"AWS::ApiGatewayV2::Route",{ApiId:t.ref("WebSocketApi"),RouteKey:a,Target:t.join("/",["integrations",t.ref(i)])},{dependsOn:["WebSocketApi",i]}),e.addResource(`${n}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(o),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[o,"WebSocketApi"]})}function _t(e,a,r,n){let i={DomainName:r.domain};if(n==="REST")i.CertificateArn=r.certificateArn,i.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",i),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:t.ref("ApiCustomDomain"),RestApiId:t.ref(a),Stage:t.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",a,"RestApiStage"]});else i.DomainNameConfigurations=[{CertificateArn:r.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",i),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:t.ref(a),DomainName:t.ref("ApiCustomDomain"),Stage:n==="HTTP"?t.ref("HttpApiStage"):t.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",a]});if(r.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${Jr(r.domain)}.`),Name:r.domain,Type:"A",AliasTarget:{HostedZoneId:t.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:t.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:r.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:t.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:t.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function Qr(e,a,r){if(!r)return;if(r.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(a),AuthorizerType:"JWT",IdentitySource:[r.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:r.issuer,Audience:r.audience},Name:"JWTAuthorizer"},{dependsOn:a});else if(r.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(a),AuthorizerType:"REQUEST",AuthorizerUri:r.authorizerUri,IdentitySource:[r.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:a})}function Jr(e){let a=e.split(".");if(a.length>=2)return a.slice(-2).join(".");return e}function Yr(e,a){if(a.redis)Zr(e,a.redis);if(a.memcached)Xr(e,a.memcached);if(a.elasticache)en(e,a.elasticache)}function Zr(e,a){if(!a)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:a.port||6379,ToPort:a.port||6379,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),a.parameterGroup&&Object.keys(a.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${a.engineVersion.split(".")[0]}`,Properties:a.parameterGroup});if(a.numCacheNodes>1||a.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheClusters:a.numCacheNodes,AutomaticFailoverEnabled:a.automaticFailoverEnabled||!1,MultiAZEnabled:a.automaticFailoverEnabled||!1,Port:a.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:a.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:a.snapshotRetentionLimit||5,SnapshotWindow:a.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:a.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheNodes:1,Port:a.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:a.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:a.snapshotRetentionLimit||5,SnapshotWindow:a.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:a.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}})}function Xr(e,a){if(!a)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:a.port||11211,ToPort:a.port||11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheNodes:a.numCacheNodes,Port:a.port||11211,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-memcached-port")}}})}function en(e,a){if(!a)return;let r=a.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:r?6379:11211,ToPort:r?6379:11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub(`\${AWS::StackName}-${a.engine}`),Engine:a.engine,EngineVersion:a.engineVersion,CacheNodeType:a.nodeType,NumCacheNodes:a.numCacheNodes,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${a.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function tn(e,a){if(!a.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:t.sub("${AWS::StackName} CloudFront OAI")}});let r=[],n=[];if(!a.origins||a.origins.length===0)r.push({Id:"S3Origin",DomainName:t.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else a.origins.forEach((c,u)=>{let d={Id:c.id,DomainName:c.domainName};if(c.originPath)d.OriginPath=c.originPath;if(c.domainName.includes("s3"))d.S3OriginConfig={OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(r.push(d),u>0||c.pathPattern)n.push({PathPattern:c.pathPattern||`/${c.id}/*`,TargetOriginId:c.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:a.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:a.cachePolicy?.minTTL||0,DefaultTTL:a.cachePolicy?.defaultTTL||86400,MaxTTL:a.cachePolicy?.maxTTL||31536000})});let i={TargetOriginId:r[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:a.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:a.cachePolicy?.minTTL||0,DefaultTTL:a.cachePolicy?.defaultTTL||86400,MaxTTL:a.cachePolicy?.maxTTL||31536000};if(a.edgeFunctions&&a.edgeFunctions.length>0)i.LambdaFunctionAssociations=a.edgeFunctions.map((c)=>({EventType:c.eventType,LambdaFunctionARN:c.functionArn}));let o={Enabled:!0,HttpVersion:a.http3?"http3":"http2",IPV6Enabled:!0,Origins:r,DefaultCacheBehavior:i,PriceClass:a.priceClass||"PriceClass_100",ViewerCertificate:{}};if(n.length>0)o.CacheBehaviors=n;if(a.customDomain)o.Aliases=[a.customDomain.domain],o.ViewerCertificate={AcmCertificateArn:a.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else o.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(a.errorPages)o.CustomErrorResponses=Object.entries(a.errorPages).map(([c,u])=>({ErrorCode:Number.parseInt(c),ResponseCode:200,ResponsePagePath:u,ErrorCachingMinTTL:300}));if(o.DefaultRootObject="index.html",o.Comment=t.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:o},{dependsOn:"CloudFrontOriginAccessIdentity"}),!a.origins||a.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:t.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:t.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:t.join("",[t.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(a.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${an(a.customDomain.domain)}.`),Name:a.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:t.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:t.ref("CloudFrontDistribution"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:t.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-domain")}}}),a.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:t.sub(`https://${a.customDomain.domain}`)}})}function an(e){let a=e.split(".");if(a.length>=2)return a.slice(-2).join(".");return e}function cn(e,a){if(a.server)ln(e,a.server);if(a.fargate)ca(e,"app",a.fargate);if(a.services)a.services.forEach((r)=>{if(r.type==="fargate")ca(e,r.name,{taskDefinition:r.taskDefinition,service:r.service})})}function ln(e,a){if(!a)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:t.ref("ALBSecurityGroup")},{IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-app-sg")}]},{dependsOn:"VPC"}),e.addResource("EC2InstanceRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[t.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let r=a.userData||`#!/bin/bash
|
|
2469
2469
|
set -e
|
|
2470
2470
|
# Update system
|
|
2471
2471
|
yum update -y || apt-get update -y
|
|
@@ -2490,10 +2490,10 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
|
|
|
2490
2490
|
# Install Node.js or PHP/Python based on app needs
|
|
2491
2491
|
# Configure application server (PM2, Nginx, Apache)
|
|
2492
2492
|
# Mount EFS for shared file storage
|
|
2493
|
-
`}},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:[n||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${r}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:n?{domain:n,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:n?{domain:n,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 Sp(e){let{name:a,slug:r,domain:n,repository:i,phpVersion:o="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:a,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:n}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[o],default:o},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:n,phpVersion:o,repository:{...i,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function bp(e){let{name:a,slug:r,domain:n,layers:i,phpVersion:o="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:h="us-east-1"}=e;return{project:{name:a,slug:r,region:h},mode:"serverless",environments:{production:{type:"production",domain:n,app:{kind:"php",runtime:"provided.al2023",phpVersion:o,architecture:c,layers:i,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:n}}}}}function vp(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 id=Ka,od="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function Mn(e){let a=e.split(".").filter(Boolean);return a.length<=2?e:a.slice(-2).join(".")}function xn(e){let a=2166136261;for(let r=0;r<e.length;r++)a^=e.charCodeAt(r),a=Math.imul(a,16777619);return a>>>0}var sd=20000,ad=12000;function cd(e){return sd+xn(e)%ad}function Ia(e,a){let r=Mn(e);if(r===e)return`dashboard.${r}`;for(let n of a)if(n===r)return`dashboard.${r}`;return`dashboard.${e}`}function Ra(e,a){let r=[],n=e.infrastructure?.dns?.domain;if(n&&!e.cloud?.attachTo)r.push(n);if(a&&e.environments?.[a]?.domain)r.push(e.environments[a].domain);for(let i of Object.values(e.sites??{})){let o=i;if(!o||o.redirect)continue;let c=o.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((i)=>i&&!i.startsWith("dashboard."))}function ld(e,a,r){if(r)return r;let n=Ra(e,a),i=n[0];if(!i)return null;return Ia(i,n)}function dd(e,a,r){if(r)return[r];let n=Ra(e,a),i=[];for(let o of n){let c=Ia(o,n);if(!i.includes(c))i.push(c)}return i}function
|
|
2494
|
-
`),n=null,i,o,c;for(let u of r){let d=u.trim();if(!d||d.startsWith("#")||d.startsWith(";"))continue;let m=d.match(/^\[([^\]]+)\]$/);if(m){if(n===a&&i&&o)return{accessKeyId:i,secretAccessKey:o,sessionToken:c};n=m[1],i=void 0,o=void 0,c=void 0;continue}if(n===a){let[p,...g]=d.split("="),h=g.join("=").trim();switch(p.trim().toLowerCase()){case"aws_access_key_id":i=h;break;case"aws_secret_access_key":o=h;break;case"aws_session_token":c=h;break}}}if(n===a&&i&&o)return{accessKeyId:i,secretAccessKey:o,sessionToken:c};return null}async function md(e){let a=e?.timeout??1000,r="http://169.254.169.254";try{let n=await Ke("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},a);if(!n.ok)return null;let i=await n.text(),o=await Ke("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":i}},a);if(!o.ok)return null;let c=(await o.text()).trim(),u=await Ke(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":i}},a);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 gd(e){let a=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,n=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,i=null;if(r)i=`http://169.254.170.2${r}`;else if(n)i=n;if(!i)return null;try{let o={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)o.Authorization=c;let u=await Ke(i,{headers:o},a);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 fd(e){let a=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,n=process.env.AWS_ROLE_ARN,i=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!n)return null;try{let o=
|
|
2495
|
-
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===o;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function yd(e){let a=e||await Eo(),r=hd();await ze();let n=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,i="Action=GetCallerIdentity&Version=2011-06-15",o=oe({method:"POST",url:n,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...a,service:"sts",region:r}),c=await fetch(o.url,{method:o.method,headers:o.headers,body:o.body});if(!c.ok)throw Error(`Failed to get account ID: ${await c.text()}`);let u=await c.text(),d=Ve(u,"Account");if(!d)throw Error("Failed to parse account ID from response");return d}await ze();class Sd{profile;credentials=null;region;constructor(e="us-east-1",a="default"){this.profile=a,this.region=e}async init(){if(this.credentials=await Vs(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,a){let r=await this.ensureCredentials(),n={Action:e,Version:"2010-05-15",...
|
|
2496
|
-
Reason: ${o.StackStatusReason||"Unknown"}`);await new Promise((c)=>setTimeout(c,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,a,r){let n={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[a];if(!n)throw Error(`Unknown waiter: ${a}`);return this.waitForStack(e,n,r)}async createChangeSet(e){let a={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;if(e.parameters)for(let[r,[n,i]]of Object.entries(e.parameters).entries())a[`Parameters.member.${r+1}.ParameterKey`]=n,a[`Parameters.member.${r+1}.ParameterValue`]=i;if(e.capabilities)for(let[r,n]of e.capabilities.entries())a[`Capabilities.member.${r+1}`]=n;return(await this.request("CreateChangeSet",a)).ChangeSetId}async executeChangeSet(e,a){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:a})}async describeStacks(e){let a=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(a)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let a=await this.request("DescribeStacks",{StackName:e}),r=(a?.DescribeStacksResult||a?.DescribeStacksResponse?.DescribeStacksResult||a)?.Stacks?.member,n=Array.isArray(r)?r[0]:r;if(!n)return{};let i={},o=n.Outputs?.member;if(o){let c=Array.isArray(o)?o:[o];for(let u of c)if(u.OutputKey&&u.OutputValue)i[u.OutputKey]=u.OutputValue}return i}}function xt(e,a=""){let r={};for(let[n,i]of Object.entries(e)){let o=a?`${a}.${n}`:n;if(Array.isArray(i))i.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,xt(c,`${o}.${u+1}`));else r[`${o}.${u+1}`]=String(c)});else if(typeof i==="object"&&i!==null)Object.assign(r,xt(i,o));else if(i!==void 0&&i!==null)r[o]=String(i)}return r}function Bn(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function a(n,i,o){let c=1,u=o,d=`<${i}`,m=`</${i}>`;while(u<n.length&&c>0){let p=n.indexOf(d,u),g=n.indexOf(m,u);if(g===-1)return-1;if(p!==-1&&p<g){let h=n[p+d.length];if(h===">"||h===" "||h==="/"){let y=n.indexOf(">",p);if(y!==-1&&n[y-1]==="/")u=y+1;else c++,u=y+1}else u=p+d.length}else{if(c--,c===0)return g;u=g+m.length}}return-1}function r(n,i){while(i<n.length&&/\s/.test(n[i]))i++;if(i>=n.length||n[i]!=="<"){let y=n.indexOf("<",i);if(y===-1)return{value:n.slice(i).trim(),end:n.length};return{value:n.slice(i,y).trim(),end:y}}if(n[i+1]==="/")return{value:void 0,end:i};let o=n.slice(i).match(/^<(\w+)([^>]*?)\/?>/);if(!o)return{value:void 0,end:i+1};let c=o[1];if(o[0].endsWith("/>"))return{value:"",end:i+o[0].length};let u=i+o[0].length,d=`</${c}>`,m=a(n,c,u);if(m===-1)return{value:void 0,end:i+o[0].length};let p=n.slice(u,m).trim();if(!p.includes("<"))return{value:p,end:m+d.length};let g={},h=u;while(h<m){while(h<m&&/\s/.test(n[h]))h++;if(h>=m)break;if(n[h]!=="<"||n[h+1]==="/")break;let y=n.slice(h).match(/^<(\w+)/);if(!y)break;let f=y[1],b=r(n,h);if(b.value===void 0){h++;continue}if(f==="member"||g[f]!==void 0){if(!Array.isArray(g[f]))g[f]=g[f]!==void 0?[g[f]]:[];g[f].push(b.value)}else g[f]=b.value;h=b.end}return{value:g,end:m+d.length}}return r(e,0).value||{}}function _n(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Wn(e){let a=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackName:r.StackName||"",StackId:r.StackId,StackStatus:r.StackStatus,CreationTime:r.CreationTime,LastUpdatedTime:r.LastUpdatedTime,StackStatusReason:r.StackStatusReason,Description:r.Description}))}function Gn(e){let a=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackId:r.StackId||"",EventId:r.EventId||"",StackName:r.StackName||"",LogicalResourceId:r.LogicalResourceId||"",PhysicalResourceId:r.PhysicalResourceId,ResourceType:r.ResourceType||"",Timestamp:r.Timestamp||"",ResourceStatus:r.ResourceStatus||"",ResourceStatusReason:r.ResourceStatusReason}))}await ze();var Un=5242880,Pt=5242880,Fn=5242880;class tc{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 Eo(this.credentialOptions)}buildUrl(e,a){let r=a?encodeURIComponent(a).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return a?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let n=new URL(this.endpoint);return n.hostname=`${e}.${n.hostname}`,a?`${n.origin}/${r}`:n.origin}async get(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a),o={};if(r.range)o.Range=r.range;if(r.ifModifiedSince)o["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)o["If-Match"]=r.ifMatch;if(r.ifNoneMatch)o["If-None-Match"]=r.ifNoneMatch;let c=new URL(i);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=oe({method:"GET",url:c.toString(),headers:o,...n,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 Ce(`Failed to get object: ${m}`,d.status,e,a)}return d}async getText(e,a,r={}){return(await this.get(e,a,r)).text()}async getJSON(e,a,r={}){return(await this.get(e,a,r)).json()}async getBuffer(e,a,r={}){return(await this.get(e,a,r)).arrayBuffer()}async put(e,a,r,n={}){let i,o;if(typeof r==="string")i=new TextEncoder().encode(r).length,o=r;else if(r instanceof ArrayBuffer)i=r.byteLength,o=r;else if(r instanceof Uint8Array)i=r.byteLength,o=r;else if(r instanceof Blob)i=r.size,o=r;else return this.uploadMultipart(e,a,r,{...n,partSize:Pt});if(i>Fn){let c=Kn(o).stream();return this.uploadMultipart(e,a,c,{...n,partSize:Pt})}return this.putSimple(e,a,o,i,n)}async putSimple(e,a,r,n,i){let o=await this.getCredentials(),c=this.buildUrl(e,a),u={"Content-Length":String(n),"Content-Type":i.contentType||ua(a)};if(i.contentEncoding)u["Content-Encoding"]=i.contentEncoding;if(i.cacheControl)u["Cache-Control"]=i.cacheControl;if(i.contentDisposition)u["Content-Disposition"]=i.contentDisposition;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.serverSideEncryption)u["x-amz-server-side-encryption"]=i.serverSideEncryption;if(i.acl)u["x-amz-acl"]=i.acl;if(i.tagging)u["x-amz-tagging"]=i.tagging;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;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=oe({method:"PUT",url:c,headers:u,body:d,...o,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let g=await p.text();throw new Ce(`Failed to put object: ${g}`,p.status,e,a)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=oe({method:"DELETE",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok&&o.status!==204){let c=await o.text();throw new Ce(`Failed to delete object: ${c}`,o.status,e,a)}}async deleteMany(e,a){let r=await this.getCredentials(),n=`${this.buildUrl(e)}?delete`,i=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${a.map((y)=>`<Object><Key>${jn(y)}</Key></Object>`).join("")}</Delete>`,o=oe({method:"POST",url:n,headers:{"Content-Type":"application/xml"},body:i,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers,body:i});if(!c.ok){let y=await c.text();throw new Ce(`Failed to delete objects: ${y}`,c.status,e)}let u=await c.text(),d=[],m=[],p=/<Deleted><Key>([^<]+)<\/Key>/g,g;while((g=p.exec(u))!==null)d.push(g[1]);let h=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((g=h.exec(u))!==null)m.push({key:g[1],error:`${g[2]}: ${g[3]}`});return{deleted:d,errors:m}}async list(e,a={}){let r=await this.getCredentials(),n=new URL(this.buildUrl(e));if(n.searchParams.set("list-type","2"),a.prefix)n.searchParams.set("prefix",a.prefix);if(a.delimiter)n.searchParams.set("delimiter",a.delimiter);if(a.maxKeys)n.searchParams.set("max-keys",String(a.maxKeys));if(a.continuationToken)n.searchParams.set("continuation-token",a.continuationToken);if(a.startAfter)n.searchParams.set("start-after",a.startAfter);let i=oe({method:"GET",url:n.toString(),...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok){let u=await o.text();throw new Ce(`Failed to list objects: ${u}`,o.status,e)}let c=await o.text();return Vn(c)}async*listAll(e,a={}){let r;do{let n=await this.list(e,{...a,continuationToken:r});for(let i of n.contents)yield i;r=n.nextContinuationToken}while(r)}async head(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=oe({method:"HEAD",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(o.status===404)return null;if(!o.ok){let u=await o.text();throw new Ce(`Failed to head object: ${u}`,o.status,e,a)}let c={};return o.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(o.headers.get("Content-Length")||0),contentType:o.headers.get("Content-Type")||"application/octet-stream",etag:(o.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(o.headers.get("Last-Modified")||0),metadata:c,storageClass:o.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:o.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,a){return await this.head(e,a)!==null}async copy(e,a,r,n,i={}){let o=await this.getCredentials(),c=this.buildUrl(r,n),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(a)}`};if(i.metadataDirective)u["x-amz-metadata-directive"]=i.metadataDirective;if(i.contentType)u["Content-Type"]=i.contentType;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.acl)u["x-amz-acl"]=i.acl;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;let d=oe({method:"PUT",url:c,headers:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let g=await m.text();throw new Ce(`Failed to copy object: ${g}`,m.status,r,n)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async getPresignedUrl(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a);return Yl({url:i,method:r.method||"GET",expiresIn:r.expiresIn||3600,...n,service:"s3",region:this.region})}async uploadMultipart(e,a,r,n={}){let i=await this.getCredentials(),o=Math.max(n.partSize||Pt,Un),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,a,n);try{let p=await this.uploadParts(e,a,m,d,c,o,i,u,n.concurrency||4,n.onProgress);return await this.completeMultipartUpload(e,a,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,a,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,a,r){let n=await this.getCredentials(),i=this.buildUrl(e,a),o=`${i}?uploads`,c={"Content-Type":r.contentType||ua(a)};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[g,h]of Object.entries(r.metadata))c[`x-amz-meta-${g.toLowerCase()}`]=h;let u=oe({method:"POST",url:o,headers:c,...n,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let g=await d.text();throw new Ce(`Failed to initiate multipart upload: ${g}`,d.status,e,a)}let m=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!m)throw new Ce("Failed to parse upload ID from response",0,e,a);let p=i;if(d.url)try{let g=new URL(d.url);g.search="",p=g.toString()}catch{}return{uploadId:m[1],baseUrl:p}}async uploadParts(e,a,r,n,i,o,c,u,d,m){let p=[],g=i.getReader(),h=1,y=new Uint8Array(0),f=0,b=u?Math.ceil(u/o):void 0,v=new Map,P=async(T,N)=>{let I=`${r}?partNumber=${N}&uploadId=${encodeURIComponent(n)}`,k={"Content-Length":String(T.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},x=oe({method:"PUT",url:I,headers:k,...c,service:"s3",region:this.region}),L=await fetch(x.url,{method:x.method,headers:x.headers,body:T,redirect:"error"});if(!L.ok){let W=await L.text();throw new Ce(`Failed to upload part ${N}: ${W}`,L.status,e,a)}let O=(L.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new Ce(`Missing ETag for part ${N}`,L.status,e,a);return{partNumber:N,etag:O}},R=async()=>{let T=await Promise.race(v.values());v.delete(T.partNumber),p.push(T)};while(!0){let{done:T,value:N}=await g.read();if(N){let I=new Uint8Array(y.length+N.length);I.set(y),I.set(N,y.length),y=I}while(y.length>=o||T&&y.length>0){let I=y.slice(0,o);y=y.slice(o);let k=h++;if(v.size>=d)await R();if(v.set(k,P(I,k)),f+=I.byteLength,m)m({loaded:f,total:u||f,part:k,totalParts:b||k})}if(T)break}while(v.size>0)await R();return p.sort((T,N)=>T.partNumber-N.partNumber),p}async completeMultipartUpload(e,a,r,n,i){let o=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(n)}`,u=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${i.map((g)=>`<Part><PartNumber>${g.partNumber}</PartNumber><ETag>"${g.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,d=oe({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers,body:u});if(!m.ok){let g=await m.text();throw new Ce(`Failed to complete multipart upload: ${g}`,m.status,e,a)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async abortMultipartUpload(e,a,r,n){let i=await this.getCredentials(),o=`${n??this.buildUrl(e,a)}?uploadId=${encodeURIComponent(r)}`,c=oe({method:"DELETE",url:o,...i,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let a=[];for await(let o of this.listAll(e,{}))if(a.push(o.key),a.length>=1000)await this.deleteMany(e,a),a=[];if(a.length>0)await this.deleteMany(e,a);let r=await this.getCredentials(),n=this.buildUrl(e),i=oe({method:"DELETE",url:n,...r,service:"s3",region:this.region});await fetch(i.url,{method:i.method,headers:i.headers})}}class Ce extends Error{statusCode;bucket;key;constructor(e,a,r,n){super(e);this.statusCode=a,this.bucket=r,this.key=n,this.name="S3Error"}}function Vn(e){let a=[],r=[],n=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=n.exec(e))!==null){let c=i[1];a.push({key:Q(c,"Key")||"",lastModified:new Date(Q(c,"LastModified")||0),etag:(Q(c,"ETag")||"").replace(/"/g,""),size:Number(Q(c,"Size")||0),storageClass:Q(c,"StorageClass")||"STANDARD"})}let o=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((i=o.exec(e))!==null)r.push(i[1]);return{contents:a,commonPrefixes:r,isTruncated:Q(e,"IsTruncated")==="true",continuationToken:Q(e,"ContinuationToken")||void 0,nextContinuationToken:Q(e,"NextContinuationToken")||void 0,keyCount:Number(Q(e,"KeyCount")||0),maxKeys:Number(Q(e,"MaxKeys")||1000),prefix:Q(e,"Prefix")||void 0,delimiter:Q(e,"Delimiter")||void 0}}function Q(e,a){let r=new RegExp(`<${a}>([^<]*)</${a}>`),n=e.match(r);return n?n[1]:null}function jn(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function ua(e){let a=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"}[a||""]||"application/octet-stream"}function Kn(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function kp(e){return new tc(e)}await ze();class bd{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Vs(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let a=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,n=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2493
|
+
`}},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:[n||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${r}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:n?{domain:n,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:n?{domain:n,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 Sp(e){let{name:a,slug:r,domain:n,repository:i,phpVersion:o="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:a,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:n}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[o],default:o},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:n,phpVersion:o,repository:{...i,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function bp(e){let{name:a,slug:r,domain:n,layers:i,phpVersion:o="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:h="us-east-1"}=e;return{project:{name:a,slug:r,region:h},mode:"serverless",environments:{production:{type:"production",domain:n,app:{kind:"php",runtime:"provided.al2023",phpVersion:o,architecture:c,layers:i,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:n}}}}}function vp(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 id=Ka,od="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function Mn(e){let a=e.split(".").filter(Boolean);return a.length<=2?e:a.slice(-2).join(".")}function xn(e){let a=2166136261;for(let r=0;r<e.length;r++)a^=e.charCodeAt(r),a=Math.imul(a,16777619);return a>>>0}var sd=20000,ad=12000;function cd(e){return sd+xn(e)%ad}function Ia(e,a){let r=Mn(e);if(r===e)return`dashboard.${r}`;for(let n of a)if(n===r)return`dashboard.${r}`;return`dashboard.${e}`}function Ra(e,a){let r=[],n=e.infrastructure?.dns?.domain;if(n&&!e.cloud?.attachTo)r.push(n);if(a&&e.environments?.[a]?.domain)r.push(e.environments[a].domain);for(let i of Object.values(e.sites??{})){let o=i;if(!o||o.redirect)continue;let c=o.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((i)=>i&&!i.startsWith("dashboard."))}function ld(e,a,r){if(r)return r;let n=Ra(e,a),i=n[0];if(!i)return null;return Ia(i,n)}function dd(e,a,r){if(r)return[r];let n=Ra(e,a),i=[];for(let o of n){let c=Ia(o,n);if(!i.includes(c))i.push(c)}return i}function jt(e){return Object.entries(e.sites??{}).some(([a,r])=>{if(!r)return!1;let n=r.root??"";return Cr(a)||n==="ui/dist"||n.endsWith("/ui/dist")||n.endsWith("/dist/ui")})}var Ya="dashboard-";function Za(e){return Ya+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Cr(e){return e==="dashboard"||e.startsWith(Ya)}function hi(e,a,r){if(jt(e))return[];if(e.cloud?.attachTo)return[];let n=r.password?{auth:{username:r.username||"admin",password:r.password,realm:r.realm}}:{},i=r.build===!1||r.build===void 0?{}:{build:r.build};if(r.live!==!1){let o=ld(e,a,r.domain);if(!o)return[];let c=r.port??cd(o),u=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,d={root:r.uiRoot,deploy:"server",domain:o,preStart:["bun install --production --no-save"],start:`bun ${od} --box --host 127.0.0.1 --port ${c}`,port:c,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...u?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:u.password}:{}},zeroDowntime:!1,sharedPaths:[id],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Za(o),site:d}]}return dd(e,a,r.domain).map((o)=>({name:Za(o),site:{root:r.uiRoot,deploy:"server",type:"static",domain:o,ssl:{provider:"letsencrypt"},...i,...n}}))}function Tp(e,a,r){return hi(e,a,r)[0]??null}function Wt(e,a){let r={...e};for(let n in a){let i=a[n],o=r[n];if(i===void 0)continue;if(Array.isArray(i)&&Array.isArray(o))r[n]=[...o,...i];else if(typeof i==="object"&&i!==null&&!Array.isArray(i)&&typeof o==="object"&&o!==null&&!Array.isArray(o))r[n]=Wt(o,i);else r[n]=i}return r}function ec(e,a){return Wt(e,a)}function Ep(...e){return e.reduce((a,r)=>Wt(a,r),{})}function wp(e,a){return(r)=>{let n=e(r);if(typeof a==="function")return ec(n,a(n,r));return ec(n,a)}}function rn(e){return{infrastructure:e}}function Cp(e){return rn({monitoring:e})}function Ap(e){return rn({security:e})}function Ip(e){return rn({databases:e})}function Rp(e){return rn({cache:e})}function Pp(e){return rn({cdn:e})}function Np(e){return rn({queues:e})}ze();function ud(){let e=process.env.AWS_ACCESS_KEY_ID,a=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!a)return null;return{accessKeyId:e,secretAccessKey:a,sessionToken:process.env.AWS_SESSION_TOKEN}}function pd(e){let a=e?.profile||process.env.AWS_PROFILE||"default",r=e?.credentialsFile||ka(Da(),".aws","credentials");if(!Na(r))return null;try{let n=Gt(r,"utf-8");return On(n,a)}catch{return null}}function On(e,a){let r=e.split(`
|
|
2494
|
+
`),n=null,i,o,c;for(let u of r){let d=u.trim();if(!d||d.startsWith("#")||d.startsWith(";"))continue;let m=d.match(/^\[([^\]]+)\]$/);if(m){if(n===a&&i&&o)return{accessKeyId:i,secretAccessKey:o,sessionToken:c};n=m[1],i=void 0,o=void 0,c=void 0;continue}if(n===a){let[p,...g]=d.split("="),h=g.join("=").trim();switch(p.trim().toLowerCase()){case"aws_access_key_id":i=h;break;case"aws_secret_access_key":o=h;break;case"aws_session_token":c=h;break}}}if(n===a&&i&&o)return{accessKeyId:i,secretAccessKey:o,sessionToken:c};return null}async function md(e){let a=e?.timeout??1000,r="http://169.254.169.254";try{let n=await Ke("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},a);if(!n.ok)return null;let i=await n.text(),o=await Ke("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":i}},a);if(!o.ok)return null;let c=(await o.text()).trim(),u=await Ke(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":i}},a);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 gd(e){let a=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,n=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,i=null;if(r)i=`http://169.254.170.2${r}`;else if(n)i=n;if(!i)return null;try{let o={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)o.Authorization=c;let u=await Ke(i,{headers:o},a);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 fd(e){let a=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,n=process.env.AWS_ROLE_ARN,i=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!n)return null;try{let o=Gt(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:n,RoleSessionName:i,WebIdentityToken:o}),m=await Ke(`${u}/?${d.toString()}`,{method:"POST"},a);if(!m.ok)return null;let p=await m.text(),g=Ve(p,"AccessKeyId"),h=Ve(p,"SecretAccessKey"),y=Ve(p,"SessionToken"),f=Ve(p,"Expiration");if(!g||!h)return null;return{accessKeyId:g,secretAccessKey:h,sessionToken:y??void 0,expiration:f?new Date(f):void 0}}catch{return null}}async function Eo(e){let a=ud();if(a)return a;let r=pd(e);if(r)return r;let n=await fd(e);if(n)return n;let i=await gd(e);if(i)return i;let o=await md(e);if(o)return o;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 Dp(e){let a=null,r=null;return async()=>{if(a){if(!a.expiration)return a;let n=300000;if(a.expiration.getTime()-Date.now()>n)return a}if(r)return r;return r=Eo(e).then((n)=>(a=n,r=null,n)).catch((n)=>{throw r=null,n}),r}}async function Ke(e,a,r){let n=new AbortController,i=setTimeout(()=>n.abort(),r);try{let o=await fetch(e,{...a,signal:n.signal});return clearTimeout(i),o}catch(o){throw clearTimeout(i),o}}function Ve(e,a){let r=new RegExp(`<${a}>([^<]+)</${a}>`),n=e.match(r);return n?n[1]:null}async function Vs(e){return Eo({profile:e})}function hd(e){let a=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(a)return a;let r=ka(Da(),".aws","config");if(Na(r))try{let n=Gt(r,"utf-8"),i=e||process.env.AWS_PROFILE||"default",o=i==="default"?"[default]":`[profile ${i}]`,c=n.split(`
|
|
2495
|
+
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===o;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function yd(e){let a=e||await Eo(),r=hd();await ze();let n=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,i="Action=GetCallerIdentity&Version=2011-06-15",o=oe({method:"POST",url:n,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...a,service:"sts",region:r}),c=await fetch(o.url,{method:o.method,headers:o.headers,body:o.body});if(!c.ok)throw Error(`Failed to get account ID: ${await c.text()}`);let u=await c.text(),d=Ve(u,"Account");if(!d)throw Error("Failed to parse account ID from response");return d}await ze();class Sd{profile;credentials=null;region;constructor(e="us-east-1",a="default"){this.profile=a,this.region=e}async init(){if(this.credentials=await Vs(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,a){let r=await this.ensureCredentials(),n={Action:e,Version:"2010-05-15",...Mt(a)},i=new URLSearchParams(n).toString(),o=await(await ui({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken})).text();return Bn(o)}async createStack(e){let a={StackName:e.stackName};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[n,[i,o]]of Object.entries(e.parameters).entries())a[`Parameters.member.${n+1}.ParameterKey`]=i,a[`Parameters.member.${n+1}.ParameterValue`]=o;if(e.capabilities)for(let[n,i]of e.capabilities.entries())a[`Capabilities.member.${n+1}`]=i;if(e.tags)for(let[n,[i,o]]of Object.entries(e.tags).entries())a[`Tags.member.${n+1}.Key`]=i,a[`Tags.member.${n+1}.Value`]=o;if(e.timeoutInMinutes)a.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)a.OnFailure=e.onFailure;let r=await this.request("CreateStack",a);return(r?.CreateStackResult||r?.CreateStackResponse?.CreateStackResult||r)?.StackId}async updateStack(e){let a={StackName:e.stackName};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;if(e.parameters)for(let[n,[i,o]]of Object.entries(e.parameters).entries())a[`Parameters.member.${n+1}.ParameterKey`]=i,a[`Parameters.member.${n+1}.ParameterValue`]=o;if(e.capabilities)for(let[n,i]of e.capabilities.entries())a[`Capabilities.member.${n+1}`]=i;if(e.tags)for(let[n,[i,o]]of Object.entries(e.tags).entries())a[`Tags.member.${n+1}.Key`]=i,a[`Tags.member.${n+1}.Value`]=o;let r=await this.request("UpdateStack",a);return(r?.UpdateStackResult||r?.UpdateStackResponse?.UpdateStackResult||r)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let a=await this.request("DescribeStacks",{StackName:e}),r=(a?.DescribeStacksResult||a?.DescribeStacksResponse?.DescribeStacksResult||a)?.Stacks?.member,n=Array.isArray(r)?r[0]:r;if(!n)throw Error(`Stack ${e} not found`);return _n(n)}async listStacks(e){let a={};if(e)for(let[n,i]of e.entries())a[`StackStatusFilter.member.${n+1}`]=i;let r=await this.request("ListStacks",a);return Wn(r)}async describeStackEvents(e){let a=await this.request("DescribeStackEvents",{StackName:e});return Gn(a)}async waitForStack(e,a,r){let n=0,i=null;while(n<360){n++;let o=await this.describeStack(e);if(r)try{let c=await this.describeStackEvents(e),u=[];if(i){for(let d of c){if(d.EventId===i)break;u.push(d)}u.reverse()}else if(c.length>0)u=[c[0]];for(let d of u)r(d);if(c.length>0)i=c[0].EventId}catch{}if(o.StackStatus&&a.includes(o.StackStatus))return o;if(o.StackStatus?.includes("FAILED")||o.StackStatus?.includes("ROLLBACK"))throw Error(`Stack reached failed state: ${o.StackStatus}
|
|
2496
|
+
Reason: ${o.StackStatusReason||"Unknown"}`);await new Promise((c)=>setTimeout(c,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,a,r){let n={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[a];if(!n)throw Error(`Unknown waiter: ${a}`);return this.waitForStack(e,n,r)}async createChangeSet(e){let a={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;if(e.parameters)for(let[r,[n,i]]of Object.entries(e.parameters).entries())a[`Parameters.member.${r+1}.ParameterKey`]=n,a[`Parameters.member.${r+1}.ParameterValue`]=i;if(e.capabilities)for(let[r,n]of e.capabilities.entries())a[`Capabilities.member.${r+1}`]=n;return(await this.request("CreateChangeSet",a)).ChangeSetId}async executeChangeSet(e,a){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:a})}async describeStacks(e){let a=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(a)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let a=await this.request("DescribeStacks",{StackName:e}),r=(a?.DescribeStacksResult||a?.DescribeStacksResponse?.DescribeStacksResult||a)?.Stacks?.member,n=Array.isArray(r)?r[0]:r;if(!n)return{};let i={},o=n.Outputs?.member;if(o){let c=Array.isArray(o)?o:[o];for(let u of c)if(u.OutputKey&&u.OutputValue)i[u.OutputKey]=u.OutputValue}return i}}function Mt(e,a=""){let r={};for(let[n,i]of Object.entries(e)){let o=a?`${a}.${n}`:n;if(Array.isArray(i))i.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Mt(c,`${o}.${u+1}`));else r[`${o}.${u+1}`]=String(c)});else if(typeof i==="object"&&i!==null)Object.assign(r,Mt(i,o));else if(i!==void 0&&i!==null)r[o]=String(i)}return r}function Bn(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function a(n,i,o){let c=1,u=o,d=`<${i}`,m=`</${i}>`;while(u<n.length&&c>0){let p=n.indexOf(d,u),g=n.indexOf(m,u);if(g===-1)return-1;if(p!==-1&&p<g){let h=n[p+d.length];if(h===">"||h===" "||h==="/"){let y=n.indexOf(">",p);if(y!==-1&&n[y-1]==="/")u=y+1;else c++,u=y+1}else u=p+d.length}else{if(c--,c===0)return g;u=g+m.length}}return-1}function r(n,i){while(i<n.length&&/\s/.test(n[i]))i++;if(i>=n.length||n[i]!=="<"){let y=n.indexOf("<",i);if(y===-1)return{value:n.slice(i).trim(),end:n.length};return{value:n.slice(i,y).trim(),end:y}}if(n[i+1]==="/")return{value:void 0,end:i};let o=n.slice(i).match(/^<(\w+)([^>]*?)\/?>/);if(!o)return{value:void 0,end:i+1};let c=o[1];if(o[0].endsWith("/>"))return{value:"",end:i+o[0].length};let u=i+o[0].length,d=`</${c}>`,m=a(n,c,u);if(m===-1)return{value:void 0,end:i+o[0].length};let p=n.slice(u,m).trim();if(!p.includes("<"))return{value:p,end:m+d.length};let g={},h=u;while(h<m){while(h<m&&/\s/.test(n[h]))h++;if(h>=m)break;if(n[h]!=="<"||n[h+1]==="/")break;let y=n.slice(h).match(/^<(\w+)/);if(!y)break;let f=y[1],b=r(n,h);if(b.value===void 0){h++;continue}if(f==="member"||g[f]!==void 0){if(!Array.isArray(g[f]))g[f]=g[f]!==void 0?[g[f]]:[];g[f].push(b.value)}else g[f]=b.value;h=b.end}return{value:g,end:m+d.length}}return r(e,0).value||{}}function _n(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Wn(e){let a=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackName:r.StackName||"",StackId:r.StackId,StackStatus:r.StackStatus,CreationTime:r.CreationTime,LastUpdatedTime:r.LastUpdatedTime,StackStatusReason:r.StackStatusReason,Description:r.Description}))}function Gn(e){let a=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackId:r.StackId||"",EventId:r.EventId||"",StackName:r.StackName||"",LogicalResourceId:r.LogicalResourceId||"",PhysicalResourceId:r.PhysicalResourceId,ResourceType:r.ResourceType||"",Timestamp:r.Timestamp||"",ResourceStatus:r.ResourceStatus||"",ResourceStatusReason:r.ResourceStatusReason}))}await ze();var Un=5242880,Pt=5242880,Fn=5242880;class tc{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 Eo(this.credentialOptions)}buildUrl(e,a){let r=a?encodeURIComponent(a).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return a?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let n=new URL(this.endpoint);return n.hostname=`${e}.${n.hostname}`,a?`${n.origin}/${r}`:n.origin}async get(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a),o={};if(r.range)o.Range=r.range;if(r.ifModifiedSince)o["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)o["If-Match"]=r.ifMatch;if(r.ifNoneMatch)o["If-None-Match"]=r.ifNoneMatch;let c=new URL(i);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=oe({method:"GET",url:c.toString(),headers:o,...n,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 Ce(`Failed to get object: ${m}`,d.status,e,a)}return d}async getText(e,a,r={}){return(await this.get(e,a,r)).text()}async getJSON(e,a,r={}){return(await this.get(e,a,r)).json()}async getBuffer(e,a,r={}){return(await this.get(e,a,r)).arrayBuffer()}async put(e,a,r,n={}){let i,o;if(typeof r==="string")i=new TextEncoder().encode(r).length,o=r;else if(r instanceof ArrayBuffer)i=r.byteLength,o=r;else if(r instanceof Uint8Array)i=r.byteLength,o=r;else if(r instanceof Blob)i=r.size,o=r;else return this.uploadMultipart(e,a,r,{...n,partSize:Pt});if(i>Fn){let c=Kn(o).stream();return this.uploadMultipart(e,a,c,{...n,partSize:Pt})}return this.putSimple(e,a,o,i,n)}async putSimple(e,a,r,n,i){let o=await this.getCredentials(),c=this.buildUrl(e,a),u={"Content-Length":String(n),"Content-Type":i.contentType||ua(a)};if(i.contentEncoding)u["Content-Encoding"]=i.contentEncoding;if(i.cacheControl)u["Cache-Control"]=i.cacheControl;if(i.contentDisposition)u["Content-Disposition"]=i.contentDisposition;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.serverSideEncryption)u["x-amz-server-side-encryption"]=i.serverSideEncryption;if(i.acl)u["x-amz-acl"]=i.acl;if(i.tagging)u["x-amz-tagging"]=i.tagging;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;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=oe({method:"PUT",url:c,headers:u,body:d,...o,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let g=await p.text();throw new Ce(`Failed to put object: ${g}`,p.status,e,a)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=oe({method:"DELETE",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok&&o.status!==204){let c=await o.text();throw new Ce(`Failed to delete object: ${c}`,o.status,e,a)}}async deleteMany(e,a){let r=await this.getCredentials(),n=`${this.buildUrl(e)}?delete`,i=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${a.map((y)=>`<Object><Key>${jn(y)}</Key></Object>`).join("")}</Delete>`,o=oe({method:"POST",url:n,headers:{"Content-Type":"application/xml"},body:i,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers,body:i});if(!c.ok){let y=await c.text();throw new Ce(`Failed to delete objects: ${y}`,c.status,e)}let u=await c.text(),d=[],m=[],p=/<Deleted><Key>([^<]+)<\/Key>/g,g;while((g=p.exec(u))!==null)d.push(g[1]);let h=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((g=h.exec(u))!==null)m.push({key:g[1],error:`${g[2]}: ${g[3]}`});return{deleted:d,errors:m}}async list(e,a={}){let r=await this.getCredentials(),n=new URL(this.buildUrl(e));if(n.searchParams.set("list-type","2"),a.prefix)n.searchParams.set("prefix",a.prefix);if(a.delimiter)n.searchParams.set("delimiter",a.delimiter);if(a.maxKeys)n.searchParams.set("max-keys",String(a.maxKeys));if(a.continuationToken)n.searchParams.set("continuation-token",a.continuationToken);if(a.startAfter)n.searchParams.set("start-after",a.startAfter);let i=oe({method:"GET",url:n.toString(),...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok){let u=await o.text();throw new Ce(`Failed to list objects: ${u}`,o.status,e)}let c=await o.text();return Vn(c)}async*listAll(e,a={}){let r;do{let n=await this.list(e,{...a,continuationToken:r});for(let i of n.contents)yield i;r=n.nextContinuationToken}while(r)}async head(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=oe({method:"HEAD",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(o.status===404)return null;if(!o.ok){let u=await o.text();throw new Ce(`Failed to head object: ${u}`,o.status,e,a)}let c={};return o.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(o.headers.get("Content-Length")||0),contentType:o.headers.get("Content-Type")||"application/octet-stream",etag:(o.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(o.headers.get("Last-Modified")||0),metadata:c,storageClass:o.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:o.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,a){return await this.head(e,a)!==null}async copy(e,a,r,n,i={}){let o=await this.getCredentials(),c=this.buildUrl(r,n),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(a)}`};if(i.metadataDirective)u["x-amz-metadata-directive"]=i.metadataDirective;if(i.contentType)u["Content-Type"]=i.contentType;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.acl)u["x-amz-acl"]=i.acl;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;let d=oe({method:"PUT",url:c,headers:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let g=await m.text();throw new Ce(`Failed to copy object: ${g}`,m.status,r,n)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async getPresignedUrl(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a);return Yl({url:i,method:r.method||"GET",expiresIn:r.expiresIn||3600,...n,service:"s3",region:this.region})}async uploadMultipart(e,a,r,n={}){let i=await this.getCredentials(),o=Math.max(n.partSize||Pt,Un),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,a,n);try{let p=await this.uploadParts(e,a,m,d,c,o,i,u,n.concurrency||4,n.onProgress);return await this.completeMultipartUpload(e,a,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,a,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,a,r){let n=await this.getCredentials(),i=this.buildUrl(e,a),o=`${i}?uploads`,c={"Content-Type":r.contentType||ua(a)};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[g,h]of Object.entries(r.metadata))c[`x-amz-meta-${g.toLowerCase()}`]=h;let u=oe({method:"POST",url:o,headers:c,...n,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let g=await d.text();throw new Ce(`Failed to initiate multipart upload: ${g}`,d.status,e,a)}let m=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!m)throw new Ce("Failed to parse upload ID from response",0,e,a);let p=i;if(d.url)try{let g=new URL(d.url);g.search="",p=g.toString()}catch{}return{uploadId:m[1],baseUrl:p}}async uploadParts(e,a,r,n,i,o,c,u,d,m){let p=[],g=i.getReader(),h=1,y=new Uint8Array(0),f=0,b=u?Math.ceil(u/o):void 0,v=new Map,P=async(T,N)=>{let I=`${r}?partNumber=${N}&uploadId=${encodeURIComponent(n)}`,k={"Content-Length":String(T.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},x=oe({method:"PUT",url:I,headers:k,...c,service:"s3",region:this.region}),L=await fetch(x.url,{method:x.method,headers:x.headers,body:T,redirect:"error"});if(!L.ok){let W=await L.text();throw new Ce(`Failed to upload part ${N}: ${W}`,L.status,e,a)}let O=(L.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new Ce(`Missing ETag for part ${N}`,L.status,e,a);return{partNumber:N,etag:O}},R=async()=>{let T=await Promise.race(v.values());v.delete(T.partNumber),p.push(T)};while(!0){let{done:T,value:N}=await g.read();if(N){let I=new Uint8Array(y.length+N.length);I.set(y),I.set(N,y.length),y=I}while(y.length>=o||T&&y.length>0){let I=y.slice(0,o);y=y.slice(o);let k=h++;if(v.size>=d)await R();if(v.set(k,P(I,k)),f+=I.byteLength,m)m({loaded:f,total:u||f,part:k,totalParts:b||k})}if(T)break}while(v.size>0)await R();return p.sort((T,N)=>T.partNumber-N.partNumber),p}async completeMultipartUpload(e,a,r,n,i){let o=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(n)}`,u=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${i.map((g)=>`<Part><PartNumber>${g.partNumber}</PartNumber><ETag>"${g.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,d=oe({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers,body:u});if(!m.ok){let g=await m.text();throw new Ce(`Failed to complete multipart upload: ${g}`,m.status,e,a)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async abortMultipartUpload(e,a,r,n){let i=await this.getCredentials(),o=`${n??this.buildUrl(e,a)}?uploadId=${encodeURIComponent(r)}`,c=oe({method:"DELETE",url:o,...i,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let a=[];for await(let o of this.listAll(e,{}))if(a.push(o.key),a.length>=1000)await this.deleteMany(e,a),a=[];if(a.length>0)await this.deleteMany(e,a);let r=await this.getCredentials(),n=this.buildUrl(e),i=oe({method:"DELETE",url:n,...r,service:"s3",region:this.region});await fetch(i.url,{method:i.method,headers:i.headers})}}class Ce extends Error{statusCode;bucket;key;constructor(e,a,r,n){super(e);this.statusCode=a,this.bucket=r,this.key=n,this.name="S3Error"}}function Vn(e){let a=[],r=[],n=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=n.exec(e))!==null){let c=i[1];a.push({key:Q(c,"Key")||"",lastModified:new Date(Q(c,"LastModified")||0),etag:(Q(c,"ETag")||"").replace(/"/g,""),size:Number(Q(c,"Size")||0),storageClass:Q(c,"StorageClass")||"STANDARD"})}let o=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((i=o.exec(e))!==null)r.push(i[1]);return{contents:a,commonPrefixes:r,isTruncated:Q(e,"IsTruncated")==="true",continuationToken:Q(e,"ContinuationToken")||void 0,nextContinuationToken:Q(e,"NextContinuationToken")||void 0,keyCount:Number(Q(e,"KeyCount")||0),maxKeys:Number(Q(e,"MaxKeys")||1000),prefix:Q(e,"Prefix")||void 0,delimiter:Q(e,"Delimiter")||void 0}}function Q(e,a){let r=new RegExp(`<${a}>([^<]*)</${a}>`),n=e.match(r);return n?n[1]:null}function jn(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function ua(e){let a=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"}[a||""]||"application/octet-stream"}function Kn(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function kp(e){return new tc(e)}await ze();class bd{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Vs(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let a=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,n=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2497
2497
|
<InvalidationBatch>
|
|
2498
2498
|
<Paths>
|
|
2499
2499
|
<Quantity>${e.paths.length}</Quantity>
|
|
@@ -2517,7 +2517,7 @@ Stack trace:`),console.error(a.stack)}}static success(e){console.log(`✔ ${e}`)
|
|
|
2517
2517
|
`,r=e.reduce((n,i)=>{if(!n[i.service])n[i.service]=[];return n[i.service].push(i),n},{});for(let[n,i]of Object.entries(r)){a+=`${n}:
|
|
2518
2518
|
`;for(let o of i){let c=o.warning?"⚠":"✓";a+=` ${c} ${o.quotaName}: ${o.currentValue}/${o.limit} (${o.percentage.toFixed(1)}%)
|
|
2519
2519
|
`}a+=`
|
|
2520
|
-
`}return a}function Bp(e){let a=[];for(let r of e)if(r.percentage>=100)a.push(`Request quota increase for ${r.service} - ${r.quotaName} (currently ${r.limit})`);else if(r.warning)a.push(`Consider requesting quota increase for ${r.service} - ${r.quotaName} (${r.percentage.toFixed(1)}% used)`);return a}class ic{cacheDir;ttl;constructor(e,a={}){this.cacheDir=e,this.ttl=a.ttl||86400000}ensureCacheDir(){if(!nt(this.cacheDir))Hn(this.cacheDir,{recursive:!0})}getCachePath(e){let a=$a("sha256").update(e).digest("hex");return It(this.cacheDir,`${a}.json`)}get(e){let a=this.getCachePath(e);if(!nt(a))return;try{let r=ma(a,"utf-8"),n=JSON.parse(r);if(Date.now()-n.timestamp>this.ttl){Fe(a);return}return n.value}catch{Fe(a);return}}set(e,a,r){this.ensureCacheDir();let n=this.getCachePath(e),i={value:a,timestamp:Date.now(),hash:r};qn(n,JSON.stringify(i),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!nt(this.cacheDir))return;let e=da(this.cacheDir);for(let a of e)Fe(It(this.cacheDir,a))}prune(){if(!nt(this.cacheDir))return;let e=da(this.cacheDir),a=Date.now();for(let r of e){let n=It(this.cacheDir,r);try{let i=ma(n,"utf-8"),o=JSON.parse(i);if(a-o.timestamp>this.ttl)Fe(n)}catch{Fe(n)}}}}class oc{cache;constructor(e=
|
|
2520
|
+
`}return a}function Bp(e){let a=[];for(let r of e)if(r.percentage>=100)a.push(`Request quota increase for ${r.service} - ${r.quotaName} (currently ${r.limit})`);else if(r.warning)a.push(`Consider requesting quota increase for ${r.service} - ${r.quotaName} (${r.percentage.toFixed(1)}% used)`);return a}class ic{cacheDir;ttl;constructor(e,a={}){this.cacheDir=e,this.ttl=a.ttl||86400000}ensureCacheDir(){if(!nt(this.cacheDir))Hn(this.cacheDir,{recursive:!0})}getCachePath(e){let a=$a("sha256").update(e).digest("hex");return It(this.cacheDir,`${a}.json`)}get(e){let a=this.getCachePath(e);if(!nt(a))return;try{let r=ma(a,"utf-8"),n=JSON.parse(r);if(Date.now()-n.timestamp>this.ttl){Fe(a);return}return n.value}catch{Fe(a);return}}set(e,a,r){this.ensureCacheDir();let n=this.getCachePath(e),i={value:a,timestamp:Date.now(),hash:r};qn(n,JSON.stringify(i),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!nt(this.cacheDir))return;let e=da(this.cacheDir);for(let a of e)Fe(It(this.cacheDir,a))}prune(){if(!nt(this.cacheDir))return;let e=da(this.cacheDir),a=Date.now();for(let r of e){let n=It(this.cacheDir,r);try{let i=ma(n,"utf-8"),o=JSON.parse(i);if(a-o.timestamp>this.ttl)Fe(n)}catch{Fe(n)}}}}class oc{cache;constructor(e=Qe("cache","templates")){this.cache=new ic(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,a){let r=this.hashTemplate(a);this.cache.set(`template:${e}`,a,r)}hasChanged(e,a){let r=this.cache.get(`template:${e}`);if(!r)return!0;let n=this.hashTemplate(r),i=this.hashTemplate(a);return n!==i}hashTemplate(e){return $a("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var Rt=null;function Fp(){if(!Rt)Rt=new oc;return Rt}async function sc(e,a={}){let r=a.algorithm||"sha256",n=a.chunkSize||65536;return new Promise((i,o)=>{let c=Kt(r),u=zn(e,{highWaterMark:n});u.on("data",(d)=>c.update(d)),u.on("end",()=>i(c.digest("hex"))),u.on("error",o)})}function ac(e,a="sha256"){return Kt(a).update(e).digest("hex")}function jp(e,a="sha256"){return Kt(a).update(e).digest("hex")}async function Vp(e,a={}){let r=a.ignorePatterns||["node_modules",".git","dist","build",ho()],n=[];async function i(o){let c=Qn(o,{withFileTypes:!0});for(let u of c){let d=Jn(o,u.name),m=Yn(e,d);if(r.some((p)=>m.includes(p)))continue;if(u.isDirectory())await i(d);else if(u.isFile()){let p=dt(d),g=await sc(d,a);n.push({path:m,hash:g,size:p.size,mtime:p.mtimeMs})}}}return await i(e),n}function zp(e){let a=[...e].sort((r,n)=>r.path.localeCompare(n.path)).map((r)=>`${r.path}:${r.hash}`).join(`
|
|
2521
2521
|
`);return ac(a)}function qp(e){let a=dt(e);return ac(`${e}:${a.size}:${a.mtimeMs}`)}function Hp(e,a){let r=new Map(e.map((u)=>[u.path,u])),n=new Map(a.map((u)=>[u.path,u])),i=[],o=[],c=[];for(let[u,d]of n){let m=r.get(u);if(!m)i.push(d);else if(m.hash!==d.hash)o.push(d)}for(let[u,d]of r)if(!n.has(u))c.push(d);return{added:i,modified:o,deleted:c}}class Ad{cache;constructor(){this.cache=new Map}get(e){let a=dt(e),r=this.cache.get(e);if(r&&r.mtime===a.mtimeMs&&r.size===a.size)return r.hash;return}set(e,a){let r=dt(e);this.cache.set(e,{hash:a,mtime:r.mtimeMs,size:r.size})}async getOrCompute(e,a={}){let r=this.get(e);if(r)return r;let n=await sc(e,a);return this.set(e,n),n}clear(){this.cache.clear()}}async function zs(e,a={}){let r=a.concurrency||5,n=a.stopOnError??!0,i=[],o=[],c=Date.now(),u=[...e],d=[];async function m(h,y){try{let f=await h();i[y]=f}catch(f){let b=f instanceof Error?f:Error(String(f));if(o.push(b),n)throw u.length=0,b}}let p=0;while(u.length>0||d.length>0){while(d.length<r&&u.length>0){let h=u.shift(),y=p++,f=m(h,y);d.push(f)}if(d.length>0){await Promise.race(d);for(let h=d.length-1;h>=0;h--)if(await Promise.race([d[h].then(()=>!0),Promise.resolve(!1)]))d.splice(h,1)}if(n&&o.length>0)break}let g=Date.now()-c;return{results:i.filter((h)=>h!==void 0),errors:o,duration:g}}async function Wp(e,a,r={}){let n=e.map((i)=>()=>a(i));return zs(n,r)}async function Gp(e,a,r=5){let n=e.map((o,c)=>()=>a(o,c)),i=await zs(n,{concurrency:r,stopOnError:!1});if(i.errors.length>0)throw AggregateError(i.errors,"Parallel map failed");return i.results}async function Kp(e,a={}){let r=a.retries||3,n=a.retryDelay||1000,i=e.map((o)=>async()=>{let c;for(let u=0;u<=r;u++)try{return await o()}catch(d){if(c=d instanceof Error?d:Error(String(d)),u<r)await La(n*(u+1))}throw c});return zs(i,a)}async function Jp(e){let a=[];for(let r of e){let n=await r();a.push(n)}return a}function La(e){return new Promise((a)=>setTimeout(a,e))}async function Xp(e,a,r="Operation timed out"){return Promise.race([e(),new Promise((n,i)=>setTimeout(()=>i(Error(r)),a))])}class Id{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(e=5,a=100){this.maxConcurrent=e,this.minInterval=a}async execute(e){await this.waitForSlot(),this.running++,this.lastExecution=Date.now();try{return await e()}finally{this.running--,this.processQueue()}}waitForSlot(){if(this.running<this.maxConcurrent){let e=Date.now()-this.lastExecution;if(e>=this.minInterval)return Promise.resolve();return La(this.minInterval-e)}return new Promise((e)=>this.queue.push(e))}processQueue(){if(this.queue.length>0&&this.running<this.maxConcurrent)this.queue.shift()()}stats(){return{running:this.running,queued:this.queue.length}}}function Rd(e,a){let r=[];for(let n=0;n<e.length;n+=a)r.push(e.slice(n,n+a));return r}async function Qp(e,a,r){let n=Rd(e,a),i=[];for(let o of n){let c=await r(o);i.push(...c)}return i}function Yp(e,a){let r=[],n=[],i=[],o=[],c=e.Resources||{},u=a.Resources||{},d=new Set(Object.keys(c)),m=new Set(Object.keys(u));for(let h of m)if(!d.has(h))r.push(h);for(let h of d)if(!m.has(h))i.push(h);for(let h of m)if(d.has(h)){let y=c[h],f=u[h];if(JSON.stringify(y)!==JSON.stringify(f))n.push(h);else o.push(h)}let p=JSON.stringify(e.Parameters||{})!==JSON.stringify(a.Parameters||{}),g=JSON.stringify(e.Outputs||{})!==JSON.stringify(a.Outputs||{});return{added:r,modified:n,deleted:i,unchanged:o,parametersChanged:p,outputsChanged:g,hasChanges:r.length>0||n.length>0||i.length>0||p||g}}function Zp(e){let a=[];if(!e.hasChanges)return"No changes detected";if(e.added.length>0){a.push(`Added resources (${e.added.length}):`);for(let r of e.added)a.push(` + ${r}`)}if(e.modified.length>0){a.push(`Modified resources (${e.modified.length}):`);for(let r of e.modified)a.push(` ~ ${r}`)}if(e.deleted.length>0){a.push(`Deleted resources (${e.deleted.length}):`);for(let r of e.deleted)a.push(` - ${r}`)}if(e.parametersChanged)a.push("Parameters changed");if(e.outputsChanged)a.push("Outputs changed");return a.join(`
|
|
2522
2522
|
`)}function em(e,a,r){if(e.deleted.length>0)return!0;for(let n of e.modified){let i=a.Resources[n],o=r.Resources[n];if(i.Type!==o.Type)return!0;let c=Zn(o.Type);for(let u of c){let d=i.Properties?.[u],m=o.Properties?.[u];if(JSON.stringify(d)!==JSON.stringify(m))return!0}}return!1}function Zn(e){return{"AWS::S3::Bucket":["BucketName"],"AWS::EC2::Instance":["ImageId","InstanceType","KeyName"],"AWS::RDS::DBInstance":["DBInstanceIdentifier","Engine"],"AWS::DynamoDB::Table":["TableName","KeySchema"],"AWS::Lambda::Function":["FunctionName"],"AWS::ECS::Service":["ServiceName"],"AWS::ElasticLoadBalancingV2::LoadBalancer":["Name","Type"]}[e]||[]}function tm(e){let a=[],r=[],n=[];a.push(...e.added);for(let i of e.modified)r.push(i);return n.push(...e.deleted),{safe:a,caution:r,dangerous:n}}function rm(e){if(!e.hasChanges)return{strategy:"skip",reason:"No changes detected"};if(e.deleted.length>0)return{strategy:"replace",reason:"Resources will be deleted"};if(e.added.length>0&&e.modified.length===0)return{strategy:"update",reason:"Only new resources added"};return{strategy:"update",reason:"Resources will be updated"}}function nm(e){let a=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,r=e.added.length+e.modified.length+e.deleted.length,n=a>0?r/a*100:0;return{total:a,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:n}}var im={$schema:"http://json-schema.org/draft-07/schema#",title:"ts-cloud Configuration",description:"Configuration schema for ts-cloud infrastructure-as-code",type:"object",required:["project"],properties:{project:{type:"object",description:"Project configuration",required:["name","slug"],properties:{name:{type:"string",description:"Human-readable project name",minLength:1},slug:{type:"string",description:"URL-safe project identifier (lowercase, alphanumeric, hyphens only)",pattern:"^[a-z0-9-]+$",minLength:1,maxLength:63},region:{type:"string",description:"Default AWS region",enum:["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"]}}},mode:{type:"string",description:"Deployment mode (server and serverless are mutually exclusive; auto-detected when omitted)",enum:["server","serverless"]},environments:{type:"object",description:"Environment-specific configurations",properties:{production:{$ref:"#/definitions/environment"},staging:{$ref:"#/definitions/environment"},development:{$ref:"#/definitions/environment"}}},infrastructure:{type:"object",description:"Infrastructure configuration",properties:{network:{$ref:"#/definitions/network"},storage:{type:"object",description:"S3 storage configuration",additionalProperties:{$ref:"#/definitions/storage"}},compute:{$ref:"#/definitions/compute"},database:{$ref:"#/definitions/database"},cache:{$ref:"#/definitions/cache"},cdn:{$ref:"#/definitions/cdn"},sftp:{$ref:"#/definitions/sftp"},functions:{type:"object",description:"Lambda functions configuration",additionalProperties:{type:"array",items:{$ref:"#/definitions/function"}}},monitoring:{$ref:"#/definitions/monitoring"},security:{$ref:"#/definitions/security"},queue:{type:"object",description:"SQS queue configuration",additionalProperties:{$ref:"#/definitions/queue"}}}}},definitions:{environment:{type:"object",properties:{domain:{type:"string",description:"Custom domain for this environment"},region:{type:"string",description:"AWS region override for this environment"},app:{type:"object",description:"Serverless application manifest (Laravel-Vapor-equivalent). Defining this opts the environment into the serverless app deploy pipeline (http/queue/cli Lambda functions, assets, build/deploy hooks).",properties:{runtime:{type:"string",description:"Lambda runtime override (usually derived from kind + runtimeVersion)"},runtimeVersion:{type:"string",description:"Node major (18/20/22 managed, 24+ custom layer) or Bun release for node/bun apps"},kind:{type:"string",enum:["node","bun","php"],description:"Application kind (drives packaging + runtime)"},entry:{type:"string",description:"Entry file exporting the request handler"},memory:{type:"number",description:"HTTP function memory in MB"},timeout:{type:"number",description:"HTTP request timeout in seconds"},gatewayVersion:{type:"number",enum:[1,2],description:"API Gateway version (2 = HTTP API, 1 = REST)"},warm:{type:"number",description:"Keep-warm / provisioned concurrency count"},lambdaInsights:{type:"object",description:"CloudWatch Lambda Insights extension configuration for zip deployments",required:["layerArn"],properties:{layerArn:{type:"string",description:"Region- and architecture-specific Lambda Insights extension layer ARN"}}},queues:{description:"Queue names (true = single default queue, false = disabled)"},scheduler:{type:"string",enum:["off","on","sub-minute"],description:"Task scheduler mode"},build:{type:"array",items:{type:"string"},description:"Commands run locally before packaging"},deploy:{type:"array",items:{type:"string"},description:"Commands run remotely after activation (e.g. migrations)"},octane:{type:"boolean",description:"Persistent application mode (Laravel Octane)"},packaging:{type:"string",enum:["zip","image"],description:"Deployment package format (zip or container image)"},phpVersion:{type:"string",description:"PHP version for the runtime layer (kind: php)"},architecture:{type:"string",enum:["x86_64","arm64"],description:"CPU architecture"}}}}},network:{type:"object",properties:{vpc:{type:"object",properties:{cidr:{type:"string",description:"VPC CIDR block",pattern:"^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$",default:"10.0.0.0/16"},availabilityZones:{type:"number",description:"Number of availability zones",minimum:1,maximum:3,default:2},natGateways:{type:"number",description:"Number of NAT gateways (0 for no NAT, saves cost)",minimum:0,maximum:3,default:1}}}}},storage:{type:"object",properties:{public:{type:"boolean",description:"Allow public access",default:!1},versioning:{type:"boolean",description:"Enable versioning",default:!1},encryption:{type:"boolean",description:"Enable server-side encryption",default:!0},website:{type:"boolean",description:"Enable static website hosting",default:!1},cors:{type:"object",description:"CORS configuration",properties:{allowedOrigins:{type:"array",items:{type:"string"}},allowedMethods:{type:"array",items:{type:"string",enum:["GET","PUT","POST","DELETE","HEAD"]}}}}}},compute:{type:"object",properties:{server:{type:"object",description:"EC2 server configuration",properties:{instanceType:{type:"string",description:"EC2 instance type",enum:["t3.micro","t3.small","t3.medium","t3.large","t3.xlarge","t3.2xlarge"]},autoScaling:{type:"object",properties:{min:{type:"number",minimum:1},max:{type:"number",minimum:1},desired:{type:"number",minimum:1}}}}},fargate:{type:"object",description:"ECS Fargate configuration",properties:{cpu:{type:"number",description:"CPU units (256, 512, 1024, 2048, 4096)",enum:[256,512,1024,2048,4096]},memory:{type:"number",description:"Memory in MB"},desiredCount:{type:"number",description:"Desired number of tasks",minimum:1}}}}},database:{type:"object",properties:{postgres:{type:"object",properties:{instanceClass:{type:"string",description:"RDS instance class",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"postgres"},version:{type:"string",description:"PostgreSQL version"},multiAZ:{type:"boolean",description:"Enable Multi-AZ deployment",default:!1},backupRetentionDays:{type:"number",description:"Backup retention period in days",minimum:0,maximum:35,default:7}}},mysql:{type:"object",properties:{instanceClass:{type:"string",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"mysql"},version:{type:"string"},multiAZ:{type:"boolean",default:!1},backupRetentionDays:{type:"number",minimum:0,maximum:35,default:7}}},dynamodb:{type:"object",properties:{tables:{type:"array",items:{type:"object",required:["name","partitionKey"],properties:{name:{type:"string"},partitionKey:{type:"string"},sortKey:{type:"string"},billingMode:{type:"string",enum:["PAY_PER_REQUEST","PROVISIONED"],default:"PAY_PER_REQUEST"}}}}}}}},cache:{type:"object",properties:{redis:{type:"object",properties:{nodeType:{type:"string",description:"ElastiCache node type",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1},engineVersion:{type:"string",description:"Redis engine version"}}},memcached:{type:"object",properties:{nodeType:{type:"string",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1}}}}},cdn:{type:"object",properties:{enabled:{type:"boolean",default:!0},originShield:{type:"boolean",description:"Enable CloudFront Origin Shield",default:!1},originShieldRegion:{type:"string",description:"AWS region used by CloudFront Origin Shield"},compress:{type:"boolean",description:"Enable automatic compression",default:!0},http3:{type:"boolean",description:"Enable HTTP/3 support",default:!0},customDomain:{type:"object",properties:{domain:{type:"string"},certificateArn:{type:"string"}}},cachePolicy:{type:"object",properties:{minTTL:{type:"number",minimum:0},defaultTTL:{type:"number",minimum:0},maxTTL:{type:"number",minimum:0}}}}},sftp:{type:"object",required:["bucket","users"],properties:{bucket:{type:"string",description:"S3 bucket backing the SFTP server"},endpointType:{type:"string",enum:["PUBLIC","VPC"],default:"PUBLIC"},endpointDetails:{type:"object",required:["vpcId","subnetIds"],properties:{vpcId:{type:"string"},subnetIds:{type:"array",items:{type:"string"},minItems:1},securityGroupIds:{type:"array",items:{type:"string"}},addressAllocationIds:{type:"array",items:{type:"string"}}}},securityPolicyName:{type:"string"},logging:{type:"boolean",default:!0},users:{type:"object",additionalProperties:{type:"object",required:["sshPublicKeys"],properties:{sshPublicKeys:{type:"array",items:{type:"string"},minItems:1},homeDirectory:{type:"string"},roleArn:{type:"string"}}}}}},function:{type:"object",required:["name","runtime"],properties:{name:{type:"string"},runtime:{type:"string",enum:["nodejs18.x","nodejs20.x","python3.10","python3.11","python3.12"]},handler:{type:"string",default:"index.handler"},timeout:{type:"number",minimum:1,maximum:900,default:30},memory:{type:"number",minimum:128,maximum:10240,default:1024}}},monitoring:{type:"object",properties:{alarms:{type:"array",items:{type:"object",required:["metric","threshold"],properties:{metric:{type:"string"},threshold:{type:"number"},evaluationPeriods:{type:"number",minimum:1,default:2}}}},dashboard:{type:"object",properties:{name:{type:"string"},widgets:{type:"array"}}}}},security:{type:"object",properties:{waf:{type:"boolean",description:"Enable AWS WAF",default:!1},certificates:{type:"array",items:{type:"object",required:["domain"],properties:{domain:{type:"string"},subdomains:{type:"array",items:{type:"string"}}}}}}},queue:{type:"object",properties:{fifo:{type:"boolean",default:!1},deadLetterQueue:{type:"boolean",default:!0},visibilityTimeout:{type:"number",minimum:0,maximum:43200,default:30},messageRetentionPeriod:{type:"number",minimum:60,maximum:1209600,default:345600}}}}};function om(e){let a=[];if(!e.project)a.push("Missing required field: project");else{if(!e.project.name)a.push("Missing required field: project.name");if(!e.project.slug)a.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))a.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let r=["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"];if(e.project?.region&&!r.includes(e.project.region))a.push(`Invalid region: ${e.project.region}. Must be one of: ${r.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))a.push("Invalid mode: must be one of server or serverless");return{valid:a.length===0,errors:a}}var cc={enabled:process.env.TS_CLOUD_LOCAL==="true"||!0,localstackEndpoint:process.env.LOCALSTACK_ENDPOINT||"http://localhost:4566",postgresUrl:process.env.POSTGRES_URL||"postgresql://tscloud:tscloud@localhost:5432/tscloud",redisUrl:process.env.REDIS_URL||"redis://localhost:6379",dynamodbEndpoint:process.env.DYNAMODB_ENDPOINT||"http://localhost:8000",s3Endpoint:process.env.S3_ENDPOINT||"http://localhost:9000",emailEndpoint:process.env.EMAIL_ENDPOINT||"smtp://localhost:1025",awsRegion:process.env.AWS_REGION||"us-east-1",awsAccessKeyId:process.env.AWS_ACCESS_KEY_ID||"test",awsSecretAccessKey:process.env.AWS_SECRET_ACCESS_KEY||"test"};function qs(){return cc}function sm(){return cc.enabled}function am(e){let a=qs();if(!a.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return a.dynamodbEndpoint;case"s3":return a.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return a.localstackEndpoint;default:return a.localstackEndpoint}}function cm(){let e=qs();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function lm(){let e=qs();if(!e.enabled)return{};return{AWS_ACCESS_KEY_ID:e.awsAccessKeyId,AWS_SECRET_ACCESS_KEY:e.awsSecretAccessKey,AWS_REGION:e.awsRegion,AWS_ENDPOINT_URL:e.localstackEndpoint,LOCALSTACK_ENDPOINT:e.localstackEndpoint,TS_CLOUD_LOCAL:"true"}}class lc{stacks=new Map;stackEvents=new Map;async createStack(e){let a=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:a,StackName:e.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:e.TemplateBody,Parameters:e.Parameters||[]}),this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let r=this.stacks.get(e.StackName);if(r)r.StackStatus="CREATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:a}}async updateStack(e){let a=this.stacks.get(e.StackName);if(!a)throw Error(`Stack ${e.StackName} does not exist`);return a.StackStatus="UPDATE_IN_PROGRESS",a.TemplateBody=e.TemplateBody||a.TemplateBody,this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_IN_PROGRESS"}),setTimeout(()=>{a.StackStatus="UPDATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_COMPLETE"})},100),{StackId:a.StackId}}async deleteStack(e){let a=this.stacks.get(e.StackName);if(!a)throw Error(`Stack ${e.StackName} does not exist`);a.StackStatus="DELETE_IN_PROGRESS",this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_IN_PROGRESS"}),setTimeout(()=>{this.stacks.delete(e.StackName),this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_COMPLETE"})},100)}async describeStacks(e){if(e.StackName){let a=this.stacks.get(e.StackName);if(!a)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[a]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,a){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(a)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class dc{buckets=new Map;async createBucket(e){return this.buckets.set(e.Bucket,new Map),{Location:`/${e.Bucket}`}}async deleteBucket(e){this.buckets.delete(e.Bucket)}async putObject(e){let a=this.buckets.get(e.Bucket);if(!a)a=new Map,this.buckets.set(e.Bucket,a);return a.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let a=this.buckets.get(e.Bucket);if(!a)throw Error(`Bucket ${e.Bucket} does not exist`);let r=a.get(e.Key);if(!r)throw Error(`Object ${e.Key} does not exist`);return{Body:r,ContentLength:r.length}}async deleteObject(e){let a=this.buckets.get(e.Bucket);if(a)a.delete(e.Key)}async listObjects(e){let a=this.buckets.get(e.Bucket);if(!a)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(a.keys()).map((r)=>({Key:r,Size:a.get(r).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class uc{tables=new Map;data=new Map;async createTable(e){return this.tables.set(e.TableName,{TableName:e.TableName,KeySchema:e.KeySchema,AttributeDefinitions:e.AttributeDefinitions,TableStatus:"ACTIVE",CreationDateTime:new Date().toISOString()}),this.data.set(e.TableName,new Map),{TableDescription:this.tables.get(e.TableName)}}async deleteTable(e){this.tables.delete(e.TableName),this.data.delete(e.TableName)}async putItem(e){let a=this.data.get(e.TableName);if(!a)a=new Map,this.data.set(e.TableName,a);let r=JSON.stringify(e.Item);a.set(r,e.Item)}async getItem(e){let a=this.data.get(e.TableName);if(!a)return{};let r=JSON.stringify(e.Key),n=a.get(r);return n?{Item:n}:{}}async deleteItem(e){let a=this.data.get(e.TableName);if(a){let r=JSON.stringify(e.Key);a.delete(r)}}async scan(e){let a=this.data.get(e.TableName);if(!a)return{Items:[]};return{Items:Array.from(a.values())}}reset(){this.tables.clear(),this.data.clear()}}function dm(e){return{cloudformation:new lc,s3:new dc,dynamodb:new uc}}class pc{environments=new Map;async createPreviewEnvironment(e){let{branch:a,pr:r,commitSha:n,ttl:i=24,baseConfig:o,region:c="us-east-1"}=e,u=this.generatePreviewId(a,r,n),d=this.generatePreviewName(a,r),m=`preview-${d}`,p=new Date,g=new Date(p.getTime()+i*60*60*1000),h={id:u,name:d,branch:a,pr:r,commitSha:n,createdAt:p,expiresAt:g,status:"creating",stackName:m,region:c,resources:[]};this.environments.set(u,h);try{let y=this.createPreviewConfig(o,d);return h.status="active",h.url=`https://${d}.preview.example.com`,h}catch(y){throw h.status="failed",y}}async destroyPreviewEnvironment(e){let a=this.environments.get(e);if(!a)throw Error(`Preview environment ${e} not found`);a.status="destroying";try{a.status="destroyed",this.environments.delete(e)}catch(r){throw Error(`Failed to destroy preview environment: ${r}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((a)=>a.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((a)=>a.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:a,keepCount:r,dryRun:n=!1}=e,i=[],o=[],c=new Date,u=this.listPreviewEnvironments().sort((d,m)=>m.createdAt.getTime()-d.createdAt.getTime());for(let d=0;d<u.length;d++){let m=u[d];if(m.status!=="active")continue;let p=!1;if(m.expiresAt<c)p=!0;if(a){if((c.getTime()-m.createdAt.getTime())/3600000>a)p=!0}if(r&&d>=r)p=!0;if(p)if(n)i.push(m.id);else try{await this.destroyPreviewEnvironment(m.id),i.push(m.id)}catch(g){o.push(m.id)}}return{destroyed:i,failed:o}}async updatePreviewEnvironment(e,a){let r=this.environments.get(e);if(!r)throw Error(`Preview environment ${e} not found`);r.commitSha=a,r.status="creating";try{return r.status="active",r}catch(n){throw r.status="failed",n}}async getPreviewEnvironmentsCost(){let e={},a=0;for(let r of this.environments.values())e[r.id]=0,a+=0;return{total:a,byEnvironment:e}}generatePreviewId(e,a,r){let n=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),i=r?.substring(0,7)||Date.now().toString();return a?`pr-${a}-${i}`:`${n}-${i}`}generatePreviewName(e,a){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return a?`pr-${a}`:r}createPreviewConfig(e,a){return{...e,project:{...e.project,name:`${e.project.name} Preview (${a})`,slug:`${e.project.slug}-preview-${a}`}}}}var um=new pc;function pm(e={}){let{workflowName:a="Preview Environment",trigger:r="pull_request",branches:n=["main","develop"],awsRegion:i="us-east-1",awsRole:o,configFile:c="cloud.config.ts",ttl:u=24}=e;return`name: ${a}
|
|
2523
2523
|
|
|
@@ -2771,8 +2771,8 @@ ${a.map((r)=>` • ${r}`).join(`
|
|
|
2771
2771
|
`))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((a)=>a.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class _d{variables=new Map;workingDirectory=process.cwd();set(e,a){this.variables.set(e,a)}get(e){return this.variables.get(e)}has(e){return this.variables.has(e)}delete(e){this.variables.delete(e)}getAll(){return Object.fromEntries(this.variables)}clear(){this.variables.clear()}setWorkingDirectory(e){this.workingDirectory=e}getWorkingDirectory(){return this.workingDirectory}}class $d{command={};name(e){return this.command.name=e,this}description(e){return this.command.description=e,this}aliases(...e){return this.command.aliases=e,this}handler(e){return this.command.handler=e,this}autocomplete(e){return this.command.autocomplete=e,this}build(){if(!this.command.name||!this.command.description||!this.command.handler)throw Error("Command must have name, description, and handler");return this.command}}class Od{entries=[];maxSize;persistFile;trackOutput;constructor(e={}){this.maxSize=e.maxSize||1000,this.persistFile=e.persistFile,this.trackOutput=e.trackOutput||!1}add(e){if(this.entries.push({...e,timestamp:new Date}),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}getAll(){return[...this.entries]}getRecent(e=10){return this.entries.slice(-e)}search(e){let a=e.toLowerCase();return this.entries.filter((r)=>r.command.toLowerCase().includes(a))}searchByDate(e,a){return this.entries.filter((r)=>r.timestamp>=e&&r.timestamp<=a)}getSuccessful(){return this.entries.filter((e)=>e.success)}getFailed(){return this.entries.filter((e)=>!e.success)}getMostUsed(e=10){let a=new Map;for(let r of this.entries){let n=r.command.split(" ")[0];a.set(n,(a.get(n)||0)+1)}return Array.from(a.entries()).map(([r,n])=>({command:r,count:n})).sort((r,n)=>n.count-r.count).slice(0,e)}getStats(){let e=this.entries.length,a=this.entries.filter((u)=>u.success).length,r=this.entries.filter((u)=>!u.success).length,n=this.entries.filter((u)=>u.duration!==void 0),i=n.length>0?n.reduce((u,d)=>u+(d.duration||0),0)/n.length:0,o=this.getMostUsed(1),c=o.length>0?o[0].command:"N/A";return{total:e,successful:a,failed:r,averageDuration:i,mostUsed:c}}clear(){this.entries=[]}getByIndex(e){if(e<0||e>=this.entries.length)return;return this.entries[e]}removeByIndex(e){if(e>=0&&e<this.entries.length)this.entries.splice(e,1)}async save(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),a=JSON.stringify(this.entries,null,2);await e.writeFile(this.persistFile,a,"utf-8")}catch(e){throw Error(`Failed to save history: ${e}`)}}async load(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),a=await e.readFile(this.persistFile,"utf-8"),r=JSON.parse(a);this.entries=r.map((n)=>({...n,timestamp:new Date(n.timestamp)}))}catch{this.entries=[]}}exportJSON(){return JSON.stringify(this.entries,null,2)}exportCSV(){return["Timestamp,Command,Success,Duration",...this.entries.map((e)=>[e.timestamp.toISOString(),`"${e.command.replace(/"/g,'""')}"`,e.success,e.duration||""].join(","))].join(`
|
|
2772
2772
|
`)}importJSON(e){let a=JSON.parse(e).map((r)=>({...r,timestamp:new Date(r.timestamp)}));if(this.entries.push(...a),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let a of this.entries){let r=a.timestamp.toISOString().split("T")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(a)}return e}groupByCommand(){let e=new Map;for(let a of this.entries){let r=a.command.split(" ")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(a)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,a=5){let r=e.toLowerCase(),n=this.entries.filter((i)=>i.command.toLowerCase().startsWith(r)).map((i)=>i.command);return[...new Set(n)].slice(0,a)}analyzePatterns(){let e=new Map,a=new Map;for(let n of this.entries){let i=n.timestamp.getHours(),o=n.timestamp.getDay();e.set(i,(e.get(i)||0)+1),a.set(o,(a.get(o)||0)+1)}let r=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:a,successRate:r}}}function xm(e,a={}){let{maxWidth:r=100}=a;if(e.length===0)return"No command history";let n=[];for(let i=0;i<e.length;i++){let o=e[i],c=(i+1).toString().padStart(4),u=o.timestamp.toLocaleString(),d=o.success?"✓":"✗",m=o.command;if(m.length>r-30)m=m.substring(0,r-33)+"...";let p=`${c} ${u} ${d} ${m}`;if(o.duration)p+=` (${o.duration}ms)`;n.push(p)}return n.join(`
|
|
2773
2773
|
`)}function _m(e){let a=[];return a.push("Command History Statistics"),a.push("─".repeat(30)),a.push(`Total commands: ${e.total}`),a.push(`Successful: ${e.successful}`),a.push(`Failed: ${e.failed}`),a.push(`Success rate: ${(e.successful/e.total*100).toFixed(1)}%`),a.push(`Average duration: ${e.averageDuration.toFixed(0)}ms`),a.push(`Most used: ${e.mostUsed}`),a.join(`
|
|
2774
|
-
`)}class fc{deployments=new Map;async deploy(e,a){let r=this.generateDeploymentId(),n={id:r,regions:a.regions.map((i)=>({region:i.code,stackName:this.getStackName(e,i.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,n);try{let i=a.regions.find((c)=>c.isPrimary)||a.regions[0];await this.deployToRegion(e,i,n);let o=a.regions.filter((c)=>c.code!==i.code);if(await Promise.all(o.map((c)=>this.deployToRegion(e,c,n))),a.globalResources)await this.deployGlobalResources(n,a);if(a.replication)await this.setupReplication(n,a);if(a.failover?.enabled)await this.setupFailover(n,a);return n.status="deployed",n.endTime=new Date,n}catch(i){throw n.status="failed",n.endTime=new Date,i}}async deployToRegion(e,a,r){let n=r.regions.find((i)=>i.region===a.code);if(!n)throw Error(`Region deployment not found: ${a.code}`);n.status="deploying",n.startTime=new Date;try{let i=this.createRegionConfig(e,a);await this.deployStack(n.stackName,i,a.code),n.status="deployed",n.endTime=new Date,n.outputs={stackId:`arn:aws:cloudformation:${a.code}:123456789012:stack/${n.stackName}/guid`,endpoint:`https://${n.stackName}.${a.code}.example.com`}}catch(i){throw n.status="failed",n.endTime=new Date,n.error=i instanceof Error?i.message:String(i),i}}async deployGlobalResources(e,a){let r={};if(a.globalResources?.route53)r.route53=await this.deployRoute53(e,a);if(a.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,a);if(a.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,a){let r=[],n=[];for(let i of e.regions){if(i.status!=="deployed")continue;let o={id:`health-${i.region}`,endpoint:i.outputs?.endpoint,path:a.failover?.healthCheckPath||"/health",region:i.region};r.push(o);let c={name:"example.com",type:"A",region:i.region,setIdentifier:i.region,healthCheckId:o.id,resourceRecords:[i.outputs?.endpoint]};n.push(c)}return{healthChecks:r,recordSets:n,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,a){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((r)=>r.status==="deployed").map((r,n)=>{let i=a.regions[n];return{id:`origin-${r.region}`,domainName:r.outputs?.endpoint,weight:i?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,a){if(a.replication?.s3)await this.setupS3Replication(e);if(a.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(a.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let a=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<a.length-1;r++){let n=a[r],i=a[r+1];console.log(`Setting up S3 replication: ${n.region} -> ${i.region}`)}}async setupDynamoDBReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${a.join(", ")}`)}async setupSecretsReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${a.join(", ")}`)}async setupFailover(e,a){let r=e.regions.find((i,o)=>a.regions[o]?.isPrimary)||e.regions[0],n=e.regions.filter((i)=>i.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${n.map((i)=>i.region).join(", ")}`)}async destroy(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);a.status="rolling-back";try{if(a.globalResources)await this.destroyGlobalResources(a.globalResources);await Promise.all(a.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw a.status="failed",r}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(a){throw e.status="failed",e.error=a instanceof Error?a.message:String(a),a}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,a){return`${e.project.slug}-${a}`}createRegionConfig(e,a){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,a,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var $m=new fc;class hc{references=[];exports=new Map;addExport(e){let a=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,a){let r=this.exports.get(e);if(!r)return;return r.find((n)=>n.exportName===a)?.value}createReference(e,a,r,n){let i=`/cross-region/${e}/${r}/${n}`;return this.references.push({sourceRegion:e,targetRegion:a,resourceType:r,resourceId:n,value:i}),i}async resolveReference(e,a){let r=this.references.find((n)=>n.targetRegion===e&&n.value===a);if(!r)throw Error(`Reference not found: ${a}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((a)=>a.sourceRegion===e||a.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class yc{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((a)=>a.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class Sc{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let a=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!a)return;return a.primary===e?a.secondary:a.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,a){return this.pairs.some((r)=>r.primary===e&&r.secondary===a||r.primary===a&&r.secondary===e)}clear(){this.pairs=[]}}class bc{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,a){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===a)}getDependents(e,a){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===a)}hasDependencies(e,a){return this.getDependencies(e,a).length>0}getDeploymentOrder(e){let a=new Set,r=[],n=(i)=>{let o=`${i.name}:${i.region}`;if(a.has(o))return;a.add(o);let c=this.getDependencies(i.name,i.region);for(let u of c)n({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(i)};for(let i of e)n(i);return r}detectCircularDependencies(){let e=new Set,a=new Set,r=(n,i)=>{let o=`${n}:${i}`;if(a.has(o))return!0;if(e.has(o))return!1;e.add(o),a.add(o);let c=this.getDependencies(n,i);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return a.delete(o),!1};for(let n of this.dependencies)if(r(n.dependentStack,n.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var Om=new hc,Lm=new yc,Mm=new Sc,Um=new bc,Ye=[{code:"us-east-1",name:"US East (N. Virginia)",location:"Virginia, USA",launchYear:2006,availabilityZones:6,localZones:16,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO","FedRAMP"]},{code:"us-east-2",name:"US East (Ohio)",location:"Ohio, USA",launchYear:2016,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-1",name:"US West (N. California)",location:"California, USA",launchYear:2009,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-2",name:"US West (Oregon)",location:"Oregon, USA",launchYear:2011,availabilityZones:4,localZones:2,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"eu-west-1",name:"Europe (Ireland)",location:"Dublin, Ireland",launchYear:2007,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1.05},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"eu-central-1",name:"Europe (Frankfurt)",location:"Frankfurt, Germany",launchYear:2014,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"ap-southeast-1",name:"Asia Pacific (Singapore)",location:"Singapore",launchYear:2010,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.12},compliance:["PCI-DSS","SOC","ISO","MTCS"]},{code:"ap-northeast-1",name:"Asia Pacific (Tokyo)",location:"Tokyo, Japan",launchYear:2011,availabilityZones:4,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.15},compliance:["PCI-DSS","SOC","ISO"]}];function yi(e){return Ye.find((a)=>a.code===e)}function Bm(){return Ye}function Fm(e){let a=e.toLowerCase();return Ye.filter((r)=>r.location.toLowerCase().includes(a))}function jm(e){return Ye.filter((a)=>a.compliance.includes(e))}function Vm(e){return Ye.filter((a)=>a.pricing.tier===e)}function zm(e){return Ye.some((a)=>a.code===e)}function qm(e){if(e.continent==="North America")return yi("us-east-1");if(e.continent==="Europe")return yi("eu-west-1");if(e.continent==="Asia")return yi("ap-southeast-1");return yi("us-east-1")}function Hm(e){let a=[...Ye];if(e.compliance)a=a.filter((r)=>e.compliance.every((n)=>r.compliance.includes(n)));if(e.requiredServices)a=a.filter((r)=>e.requiredServices.every((n)=>r.services[n]));if(e.pricingSensitive)a.sort((r,n)=>r.pricing.multiplier-n.pricing.multiplier);return a.slice(0,5)}function Wm(e){let a=yi(e);if(!a)throw Error(`Invalid region: ${e}`);let r=[];for(let n of Ye){if(n.code===e)continue;let i=ri(a,n),o=ni(a,n);r.push({primary:a,secondary:n,distance:i,sameContinent:o})}return r.sort((n,i)=>{if(n.sameContinent!==i.sameContinent)return n.sameContinent?1:-1;return n.distance-i.distance}),r.slice(0,3)}function ri(e,a){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},n=qe(e.location),i=qe(a.location);return Math.abs((r[n]||0)-(r[i]||0))}function ni(e,a){return qe(e.location)===qe(a.location)}function qe(e){if(e.includes("USA")||e.includes("Canada"))return"North America";if(e.includes("Europe")||e.includes("Ireland")||e.includes("Germany"))return"Europe";if(e.includes("Asia")||e.includes("Singapore")||e.includes("Japan"))return"Asia";if(e.includes("Brazil"))return"South America";if(e.includes("Australia"))return"Oceania";return"Unknown"}function Ld(e){return`${e.name} (${e.code})`}function Gm(e){return e.map((a)=>Ld(a)).join(`
|
|
2775
|
-
`)}function Km(){let e={total:Ye.length,byContinent:{},byPricingTier:{}};for(let a of Ye){let r=qe(a.location);e.byContinent[r]=(e.byContinent[r]||0)+1,e.byPricingTier[a.pricing.tier]=(e.byPricingTier[a.pricing.tier]||0)+1}return e}class vc{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((a)=>a.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((a)=>a.role===e)}createCrossAccountRole(e,a,r,n,i){let o={roleArn:`arn:aws:iam::${a}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:a,permissions:n,externalId:i?.externalId,sessionDuration:i?.sessionDuration||3600};return this.crossAccountRoles.push(o),o}getAssumeRolePolicyDocument(e,a){let r={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(a)r.Statement[0].Condition={StringEquals:{"sts:ExternalId":a}};return r}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,a,r){this.accountMappings.push({environment:e,accountId:a,region:r})}getAccountForEnvironment(e){return this.accountMappings.find((a)=>a.environment===e)}async assumeRole(e,a,r){return console.log(`Assuming role: ${e} with session: ${a}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let a=this.accounts.get(e);if(!a)throw Error(`Account not found: ${e}`);if(a.assumeRoleArn){let r=await this.assumeRole(a.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((a)=>a.sourceAccountId===e||a.targetAccountId===e)}async validateAccountAccess(e){try{let a=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let a of this.accounts.values())e[a.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((a,r)=>a+r,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Tc{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,a){let r={id:`ou-${Date.now()}`,name:e,parentId:a,accounts:[]};return this.organizationalUnits.set(r.id,r),r}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,a){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);if(!r.accounts.includes(a))r.accounts.push(a)}removeAccountFromOU(e,a){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);r.accounts=r.accounts.filter((n)=>n!==a)}getAccountsInOU(e){let a=this.organizationalUnits.get(e);if(!a)return[];return[...a.accounts]}applyServiceControlPolicy(e,a){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:a}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var Jm=new vc,Xm=new Tc,Md={basic:{name:"Basic (3 Accounts)",description:"Simple structure for small teams",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account for AWS Organizations"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production workloads"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development and testing"}],organizationalUnits:[{name:"root"},{name:"workloads",parent:"root"}]},standard:{name:"Standard (5 Accounts)",description:"Recommended for most organizations",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"security",email:"aws+security@example.com",role:"security",ou:"security",description:"Security tooling and audit logs"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared services (CI/CD, monitoring)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production environment"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"workloads",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root"},{name:"infrastructure",parent:"root"},{name:"workloads",parent:"root"}]},enterprise:{name:"Enterprise (7+ Accounts)",description:"For large organizations with strict compliance requirements",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"audit",email:"aws+audit@example.com",role:"security",ou:"security",description:"Audit and compliance"},{alias:"log-archive",email:"aws+logs@example.com",role:"security",ou:"security",description:"Centralized log storage"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared infrastructure"},{alias:"network",email:"aws+network@example.com",role:"shared-services",ou:"infrastructure",description:"Network infrastructure (Transit Gateway)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"production-ou",description:"Production workloads"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"non-production-ou",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"non-production-ou",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root",policies:["deny-root-access"]},{name:"infrastructure",parent:"root"},{name:"production-ou",parent:"root",policies:["require-mfa"]},{name:"non-production-ou",parent:"root"}]}},Qm={denyRootAccess:{name:"Deny Root User Access",description:"Prevent root user from performing any actions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyRootUser",Effect:"Deny",Action:"*",Resource:"*",Condition:{StringLike:{"aws:PrincipalArn":"arn:aws:iam::*:root"}}}]}},requireMFA:{name:"Require MFA for All Actions",description:"Require MFA for console and API access",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"RequireMFA",Effect:"Deny",Action:"*",Resource:"*",Condition:{BoolIfExists:{"aws:MultiFactorAuthPresent":"false"}}}]}},denyRegions:{name:"Deny Access to Non-Approved Regions",description:"Restrict operations to specific regions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyNonApprovedRegions",Effect:"Deny",NotAction:["iam:*","organizations:*","route53:*","cloudfront:*","support:*","s3:*"],Resource:"*",Condition:{StringNotEquals:{"aws:RequestedRegion":["us-east-1","us-west-2"]}}}]}},preventLeaving:{name:"Prevent Leaving Organization",description:"Prevent accounts from leaving the organization",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"PreventLeaving",Effect:"Deny",Action:"organizations:LeaveOrganization",Resource:"*"}]}},denyS3Unencrypted:{name:"Deny Unencrypted S3 Uploads",description:"Require encryption for all S3 uploads",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyUnencryptedS3Uploads",Effect:"Deny",Action:"s3:PutObject",Resource:"*",Condition:{StringNotEquals:{"s3:x-amz-server-side-encryption":["AES256","aws:kms"]}}}]}}},Ym={deploymentRole:{name:"CrossAccountDeploymentRole",description:"Role for deploying infrastructure from CI/CD",permissions:["cloudformation:*","s3:*","ec2:*","ecs:*","lambda:*","iam:GetRole","iam:PassRole","logs:*","events:*"]},readOnlyRole:{name:"CrossAccountReadOnlyRole",description:"Read-only access for monitoring and auditing",permissions:["cloudformation:Describe*","cloudformation:List*","ec2:Describe*","ecs:Describe*","lambda:Get*","lambda:List*","s3:Get*","s3:List*","logs:Get*","logs:Describe*"]},securityAuditRole:{name:"CrossAccountSecurityAuditRole",description:"Security audit and compliance checks",permissions:["iam:Get*","iam:List*","iam:Generate*","access-analyzer:*","guardduty:Get*","guardduty:List*","securityhub:Get*","securityhub:List*","config:Describe*","config:Get*","config:List*"]},breakGlassRole:{name:"CrossAccountBreakGlassRole",description:"Emergency access role (use with caution)",permissions:["*"]}};function Zm(e){return Md[e]}function eg(e,a){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...a&&{ManagedPolicyArns:a},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function tg(e){let a=[],r=[],n=e.accounts.filter((d)=>d.role==="management");if(n.length===0)a.push("No management account defined");if(n.length>1)a.push("Multiple management accounts defined");let i=e.accounts.map((d)=>d.email),o=i.filter((d,m)=>i.indexOf(d)!==m);if(o.length>0)a.push(`Duplicate email addresses: ${o.join(", ")}`);let c=e.accounts.map((d)=>d.alias),u=c.filter((d,m)=>c.indexOf(d)!==m);if(u.length>0)a.push(`Duplicate aliases: ${u.join(", ")}`);if(!e.accounts.some((d)=>d.role==="security"))r.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)r.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((d)=>d.role==="production"))r.push("No production account defined");return{valid:a.length===0,errors:a,warnings:r}}function rg(e){let a=[];if(a.push(`${e.name}`),a.push("─".repeat(e.name.length)),a.push(e.description),a.push(""),e.organizationalUnits){a.push("Organizational Units:");for(let r of e.organizationalUnits){let n=r.parent?" └─ ":" ";a.push(`${n}${r.name}`)}a.push("")}a.push("Accounts:");for(let r of e.accounts)a.push(` ${r.alias.padEnd(20)} ${r.role.padEnd(15)} ${r.email}`),a.push(` ${"".padEnd(20)} ${r.description}`),a.push("");return a.join(`
|
|
2774
|
+
`)}class fc{deployments=new Map;async deploy(e,a){let r=this.generateDeploymentId(),n={id:r,regions:a.regions.map((i)=>({region:i.code,stackName:this.getStackName(e,i.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,n);try{let i=a.regions.find((c)=>c.isPrimary)||a.regions[0];await this.deployToRegion(e,i,n);let o=a.regions.filter((c)=>c.code!==i.code);if(await Promise.all(o.map((c)=>this.deployToRegion(e,c,n))),a.globalResources)await this.deployGlobalResources(n,a);if(a.replication)await this.setupReplication(n,a);if(a.failover?.enabled)await this.setupFailover(n,a);return n.status="deployed",n.endTime=new Date,n}catch(i){throw n.status="failed",n.endTime=new Date,i}}async deployToRegion(e,a,r){let n=r.regions.find((i)=>i.region===a.code);if(!n)throw Error(`Region deployment not found: ${a.code}`);n.status="deploying",n.startTime=new Date;try{let i=this.createRegionConfig(e,a);await this.deployStack(n.stackName,i,a.code),n.status="deployed",n.endTime=new Date,n.outputs={stackId:`arn:aws:cloudformation:${a.code}:123456789012:stack/${n.stackName}/guid`,endpoint:`https://${n.stackName}.${a.code}.example.com`}}catch(i){throw n.status="failed",n.endTime=new Date,n.error=i instanceof Error?i.message:String(i),i}}async deployGlobalResources(e,a){let r={};if(a.globalResources?.route53)r.route53=await this.deployRoute53(e,a);if(a.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,a);if(a.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,a){let r=[],n=[];for(let i of e.regions){if(i.status!=="deployed")continue;let o={id:`health-${i.region}`,endpoint:i.outputs?.endpoint,path:a.failover?.healthCheckPath||"/health",region:i.region};r.push(o);let c={name:"example.com",type:"A",region:i.region,setIdentifier:i.region,healthCheckId:o.id,resourceRecords:[i.outputs?.endpoint]};n.push(c)}return{healthChecks:r,recordSets:n,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,a){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((r)=>r.status==="deployed").map((r,n)=>{let i=a.regions[n];return{id:`origin-${r.region}`,domainName:r.outputs?.endpoint,weight:i?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,a){if(a.replication?.s3)await this.setupS3Replication(e);if(a.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(a.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let a=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<a.length-1;r++){let n=a[r],i=a[r+1];console.log(`Setting up S3 replication: ${n.region} -> ${i.region}`)}}async setupDynamoDBReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${a.join(", ")}`)}async setupSecretsReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${a.join(", ")}`)}async setupFailover(e,a){let r=e.regions.find((i,o)=>a.regions[o]?.isPrimary)||e.regions[0],n=e.regions.filter((i)=>i.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${n.map((i)=>i.region).join(", ")}`)}async destroy(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);a.status="rolling-back";try{if(a.globalResources)await this.destroyGlobalResources(a.globalResources);await Promise.all(a.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw a.status="failed",r}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(a){throw e.status="failed",e.error=a instanceof Error?a.message:String(a),a}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,a){return`${e.project.slug}-${a}`}createRegionConfig(e,a){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,a,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var $m=new fc;class hc{references=[];exports=new Map;addExport(e){let a=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,a){let r=this.exports.get(e);if(!r)return;return r.find((n)=>n.exportName===a)?.value}createReference(e,a,r,n){let i=`/cross-region/${e}/${r}/${n}`;return this.references.push({sourceRegion:e,targetRegion:a,resourceType:r,resourceId:n,value:i}),i}async resolveReference(e,a){let r=this.references.find((n)=>n.targetRegion===e&&n.value===a);if(!r)throw Error(`Reference not found: ${a}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((a)=>a.sourceRegion===e||a.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class yc{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((a)=>a.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class Sc{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let a=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!a)return;return a.primary===e?a.secondary:a.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,a){return this.pairs.some((r)=>r.primary===e&&r.secondary===a||r.primary===a&&r.secondary===e)}clear(){this.pairs=[]}}class bc{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,a){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===a)}getDependents(e,a){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===a)}hasDependencies(e,a){return this.getDependencies(e,a).length>0}getDeploymentOrder(e){let a=new Set,r=[],n=(i)=>{let o=`${i.name}:${i.region}`;if(a.has(o))return;a.add(o);let c=this.getDependencies(i.name,i.region);for(let u of c)n({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(i)};for(let i of e)n(i);return r}detectCircularDependencies(){let e=new Set,a=new Set,r=(n,i)=>{let o=`${n}:${i}`;if(a.has(o))return!0;if(e.has(o))return!1;e.add(o),a.add(o);let c=this.getDependencies(n,i);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return a.delete(o),!1};for(let n of this.dependencies)if(r(n.dependentStack,n.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var Om=new hc,Lm=new yc,Mm=new Sc,Um=new bc,et=[{code:"us-east-1",name:"US East (N. Virginia)",location:"Virginia, USA",launchYear:2006,availabilityZones:6,localZones:16,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO","FedRAMP"]},{code:"us-east-2",name:"US East (Ohio)",location:"Ohio, USA",launchYear:2016,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-1",name:"US West (N. California)",location:"California, USA",launchYear:2009,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-2",name:"US West (Oregon)",location:"Oregon, USA",launchYear:2011,availabilityZones:4,localZones:2,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"eu-west-1",name:"Europe (Ireland)",location:"Dublin, Ireland",launchYear:2007,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1.05},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"eu-central-1",name:"Europe (Frankfurt)",location:"Frankfurt, Germany",launchYear:2014,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"ap-southeast-1",name:"Asia Pacific (Singapore)",location:"Singapore",launchYear:2010,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.12},compliance:["PCI-DSS","SOC","ISO","MTCS"]},{code:"ap-northeast-1",name:"Asia Pacific (Tokyo)",location:"Tokyo, Japan",launchYear:2011,availabilityZones:4,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.15},compliance:["PCI-DSS","SOC","ISO"]}];function yi(e){return et.find((a)=>a.code===e)}function Bm(){return et}function Fm(e){let a=e.toLowerCase();return et.filter((r)=>r.location.toLowerCase().includes(a))}function jm(e){return et.filter((a)=>a.compliance.includes(e))}function Vm(e){return et.filter((a)=>a.pricing.tier===e)}function zm(e){return et.some((a)=>a.code===e)}function qm(e){if(e.continent==="North America")return yi("us-east-1");if(e.continent==="Europe")return yi("eu-west-1");if(e.continent==="Asia")return yi("ap-southeast-1");return yi("us-east-1")}function Hm(e){let a=[...et];if(e.compliance)a=a.filter((r)=>e.compliance.every((n)=>r.compliance.includes(n)));if(e.requiredServices)a=a.filter((r)=>e.requiredServices.every((n)=>r.services[n]));if(e.pricingSensitive)a.sort((r,n)=>r.pricing.multiplier-n.pricing.multiplier);return a.slice(0,5)}function Wm(e){let a=yi(e);if(!a)throw Error(`Invalid region: ${e}`);let r=[];for(let n of et){if(n.code===e)continue;let i=ri(a,n),o=ni(a,n);r.push({primary:a,secondary:n,distance:i,sameContinent:o})}return r.sort((n,i)=>{if(n.sameContinent!==i.sameContinent)return n.sameContinent?1:-1;return n.distance-i.distance}),r.slice(0,3)}function ri(e,a){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},n=qe(e.location),i=qe(a.location);return Math.abs((r[n]||0)-(r[i]||0))}function ni(e,a){return qe(e.location)===qe(a.location)}function qe(e){if(e.includes("USA")||e.includes("Canada"))return"North America";if(e.includes("Europe")||e.includes("Ireland")||e.includes("Germany"))return"Europe";if(e.includes("Asia")||e.includes("Singapore")||e.includes("Japan"))return"Asia";if(e.includes("Brazil"))return"South America";if(e.includes("Australia"))return"Oceania";return"Unknown"}function Ld(e){return`${e.name} (${e.code})`}function Gm(e){return e.map((a)=>Ld(a)).join(`
|
|
2775
|
+
`)}function Km(){let e={total:et.length,byContinent:{},byPricingTier:{}};for(let a of et){let r=qe(a.location);e.byContinent[r]=(e.byContinent[r]||0)+1,e.byPricingTier[a.pricing.tier]=(e.byPricingTier[a.pricing.tier]||0)+1}return e}class vc{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((a)=>a.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((a)=>a.role===e)}createCrossAccountRole(e,a,r,n,i){let o={roleArn:`arn:aws:iam::${a}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:a,permissions:n,externalId:i?.externalId,sessionDuration:i?.sessionDuration||3600};return this.crossAccountRoles.push(o),o}getAssumeRolePolicyDocument(e,a){let r={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(a)r.Statement[0].Condition={StringEquals:{"sts:ExternalId":a}};return r}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,a,r){this.accountMappings.push({environment:e,accountId:a,region:r})}getAccountForEnvironment(e){return this.accountMappings.find((a)=>a.environment===e)}async assumeRole(e,a,r){return console.log(`Assuming role: ${e} with session: ${a}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let a=this.accounts.get(e);if(!a)throw Error(`Account not found: ${e}`);if(a.assumeRoleArn){let r=await this.assumeRole(a.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((a)=>a.sourceAccountId===e||a.targetAccountId===e)}async validateAccountAccess(e){try{let a=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let a of this.accounts.values())e[a.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((a,r)=>a+r,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Tc{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,a){let r={id:`ou-${Date.now()}`,name:e,parentId:a,accounts:[]};return this.organizationalUnits.set(r.id,r),r}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,a){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);if(!r.accounts.includes(a))r.accounts.push(a)}removeAccountFromOU(e,a){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);r.accounts=r.accounts.filter((n)=>n!==a)}getAccountsInOU(e){let a=this.organizationalUnits.get(e);if(!a)return[];return[...a.accounts]}applyServiceControlPolicy(e,a){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:a}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var Jm=new vc,Xm=new Tc,Md={basic:{name:"Basic (3 Accounts)",description:"Simple structure for small teams",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account for AWS Organizations"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production workloads"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development and testing"}],organizationalUnits:[{name:"root"},{name:"workloads",parent:"root"}]},standard:{name:"Standard (5 Accounts)",description:"Recommended for most organizations",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"security",email:"aws+security@example.com",role:"security",ou:"security",description:"Security tooling and audit logs"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared services (CI/CD, monitoring)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production environment"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"workloads",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root"},{name:"infrastructure",parent:"root"},{name:"workloads",parent:"root"}]},enterprise:{name:"Enterprise (7+ Accounts)",description:"For large organizations with strict compliance requirements",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"audit",email:"aws+audit@example.com",role:"security",ou:"security",description:"Audit and compliance"},{alias:"log-archive",email:"aws+logs@example.com",role:"security",ou:"security",description:"Centralized log storage"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared infrastructure"},{alias:"network",email:"aws+network@example.com",role:"shared-services",ou:"infrastructure",description:"Network infrastructure (Transit Gateway)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"production-ou",description:"Production workloads"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"non-production-ou",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"non-production-ou",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root",policies:["deny-root-access"]},{name:"infrastructure",parent:"root"},{name:"production-ou",parent:"root",policies:["require-mfa"]},{name:"non-production-ou",parent:"root"}]}},Qm={denyRootAccess:{name:"Deny Root User Access",description:"Prevent root user from performing any actions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyRootUser",Effect:"Deny",Action:"*",Resource:"*",Condition:{StringLike:{"aws:PrincipalArn":"arn:aws:iam::*:root"}}}]}},requireMFA:{name:"Require MFA for All Actions",description:"Require MFA for console and API access",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"RequireMFA",Effect:"Deny",Action:"*",Resource:"*",Condition:{BoolIfExists:{"aws:MultiFactorAuthPresent":"false"}}}]}},denyRegions:{name:"Deny Access to Non-Approved Regions",description:"Restrict operations to specific regions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyNonApprovedRegions",Effect:"Deny",NotAction:["iam:*","organizations:*","route53:*","cloudfront:*","support:*","s3:*"],Resource:"*",Condition:{StringNotEquals:{"aws:RequestedRegion":["us-east-1","us-west-2"]}}}]}},preventLeaving:{name:"Prevent Leaving Organization",description:"Prevent accounts from leaving the organization",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"PreventLeaving",Effect:"Deny",Action:"organizations:LeaveOrganization",Resource:"*"}]}},denyS3Unencrypted:{name:"Deny Unencrypted S3 Uploads",description:"Require encryption for all S3 uploads",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyUnencryptedS3Uploads",Effect:"Deny",Action:"s3:PutObject",Resource:"*",Condition:{StringNotEquals:{"s3:x-amz-server-side-encryption":["AES256","aws:kms"]}}}]}}},Ym={deploymentRole:{name:"CrossAccountDeploymentRole",description:"Role for deploying infrastructure from CI/CD",permissions:["cloudformation:*","s3:*","ec2:*","ecs:*","lambda:*","iam:GetRole","iam:PassRole","logs:*","events:*"]},readOnlyRole:{name:"CrossAccountReadOnlyRole",description:"Read-only access for monitoring and auditing",permissions:["cloudformation:Describe*","cloudformation:List*","ec2:Describe*","ecs:Describe*","lambda:Get*","lambda:List*","s3:Get*","s3:List*","logs:Get*","logs:Describe*"]},securityAuditRole:{name:"CrossAccountSecurityAuditRole",description:"Security audit and compliance checks",permissions:["iam:Get*","iam:List*","iam:Generate*","access-analyzer:*","guardduty:Get*","guardduty:List*","securityhub:Get*","securityhub:List*","config:Describe*","config:Get*","config:List*"]},breakGlassRole:{name:"CrossAccountBreakGlassRole",description:"Emergency access role (use with caution)",permissions:["*"]}};function Zm(e){return Md[e]}function eg(e,a){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...a&&{ManagedPolicyArns:a},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function tg(e){let a=[],r=[],n=e.accounts.filter((d)=>d.role==="management");if(n.length===0)a.push("No management account defined");if(n.length>1)a.push("Multiple management accounts defined");let i=e.accounts.map((d)=>d.email),o=i.filter((d,m)=>i.indexOf(d)!==m);if(o.length>0)a.push(`Duplicate email addresses: ${o.join(", ")}`);let c=e.accounts.map((d)=>d.alias),u=c.filter((d,m)=>c.indexOf(d)!==m);if(u.length>0)a.push(`Duplicate aliases: ${u.join(", ")}`);if(!e.accounts.some((d)=>d.role==="security"))r.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)r.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((d)=>d.role==="production"))r.push("No production account defined");return{valid:a.length===0,errors:a,warnings:r}}function rg(e){let a=[];if(a.push(`${e.name}`),a.push("─".repeat(e.name.length)),a.push(e.description),a.push(""),e.organizationalUnits){a.push("Organizational Units:");for(let r of e.organizationalUnits){let n=r.parent?" └─ ":" ";a.push(`${n}${r.name}`)}a.push("")}a.push("Accounts:");for(let r of e.accounts)a.push(` ${r.alias.padEnd(20)} ${r.role.padEnd(15)} ${r.email}`),a.push(` ${"".padEnd(20)} ${r.description}`),a.push("");return a.join(`
|
|
2776
2776
|
`)}function ng(e={}){let{workflowName:a="Deploy",trigger:r="push",branches:n=["main"],environments:i=["production"],awsRegion:o="us-east-1",awsRole:c,bunVersion:u="latest",deployCommand:d="bun run cloud deploy",testCommand:m="bun test",buildCommand:p="bun run build"}=e,g=!!c;return`name: ${a}
|
|
2777
2777
|
|
|
2778
2778
|
on:
|
|
@@ -7283,7 +7283,7 @@ export const queue = __handlers.queue
|
|
|
7283
7283
|
export const cli = __handlers.cli
|
|
7284
7284
|
`}var $i=["adapter.ts","recursion.ts","auto-recursion.ts"];function Li(){return Ie(Ri(ki(import.meta.url)),"runtime")}function zd(e,a,r){for(let n of e??[])r?.(`build: ${n}`),Ci(n,{stdio:"inherit",cwd:a})}function Ao(e){return Ti("sha256").update(e).digest("hex")}function Hs(e,a,r){return`deployments/${e}/${a}/${r}.zip`}async function sn(e){let a=Di(e.projectRoot??process.cwd()),{app:r}=e;if(!e.skipBuild)zd(r.build,a,e.onStep);let n=r.entry;if(!n)throw Error("serverless app: `entry` is required to package a Node/Bun application");let i=Ni(n)?n:Ie(a,n),o=wi(Ie(Ii(),"tscloud-pkg-"));try{for(let h of $i)vi(Ie(Li(),h),Ie(o,h));let c=Ie(o,"bootstrap.ts");Pi(c,Vd({entryImport:i,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 h=u.logs.map((y)=>String(y)).join(`
|
|
7285
7285
|
`);throw Error(`serverless app bundle failed:
|
|
7286
|
-
${h}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Si([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:Ao(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{Ei(o,{recursive:!0,force:!0})}}var qd=["18","20","22"];function Mi(e){if(!e)return"22";let a=String(e).match(/(\d+)/);return a?a[1]:"22"}function Io(e){let a=e.kind??"node";if(a==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(a==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=Mi(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&qd.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 jt(e,a,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${a}-${r}-default`}];return e.queues.map((n)=>{if(typeof n==="string")return{name:`${a}-${r}-${n}`};let[i,o]=Object.entries(n)[0];return{name:`${a}-${r}-${i}`,concurrency:o}})}function Ws(e,a,r){return jt(e,a,r).map((n)=>n.name)}function Gs(e){let{app:a,environment:r,handlers:n}=e,i=e.config.project.slug,o=Io(a).lambdaRuntime,c=a.architecture??"x86_64",u=e.config.project.region,d={http:`${i}-${r}-http`,queue:`${i}-${r}-queue`,cli:`${i}-${r}-cli`};if(a.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=jt(a,i,r),p=m.map((M)=>M.name),g=p.length>0,h=a.logRetention??14,y=a.packaging==="image";if(y&&a.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 f=(a.scheduler??"on")!=="off",b=(a.cache?.driver??"dynamodb")==="dynamodb",v=Boolean(a.assets),P=So(i,r),R=a.tmpStorage??512,T={},N={},I=[{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:${i}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${i}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${i}/${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}/*`),...a.storage?.bucket?[t.sub(`arn:aws:s3:::${a.storage.bucket}`),t.sub(`arn:aws:s3:::${a.storage.bucket}/*`)]:[]]}]}}];if(g)I[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}:${i}-${r}-*`)});if(b)I[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/${i}-${r}-cache*`)});let k=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(a.vpc?.subnets?.length)k.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(a.lambdaInsights)k.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");T.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:k,Policies:I}};let x=(M)=>({TSCLOUD_LAMBDA_MODE:M,TSCLOUD_ENV:r,...a.octane?{TSCLOUD_OCTANE:"1"}:{},...a.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...b?{TSCLOUD_CACHE_TABLE:`${i}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...a.env??{}}),L=Boolean(a.efs),O=typeof a.efs==="object"?a.efs:{},W=O.mountPath??"/mnt/local",K=L&&!O.accessPointArn,Z=O.accessPointArn??(K?t.getAtt("EfsAccessPoint","Arn"):void 0),z=a.vpc?.subnets??[],J=z.length>0,H=a.cache?.driver==="elasticache"||a.database?.connection==="aurora-serverless"||Boolean(a.rdsProxy)||L;if(H&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let de=J?{VpcConfig:{SubnetIds:z,SecurityGroupIds:[...a.vpc?.securityGroups??[],...H?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Oe=K?z.map((M,j)=>`EfsMountTarget${j}`):[],ft=L?{FileSystemConfigs:[{Arn:Z,LocalMountPath:W}]}:{};if(L)I[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function X(M,j,F,q,re,Ze,se,et=R){T[`${M}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${j}`,RetentionInDays:h}};let St=[...e.runtimeLayers??[],...a.lambdaInsights?[a.lambdaInsights.layerArn]:[]],bt=y?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...a.kind==="php"?{}:{ImageConfig:{Command:[F]}}}:{Runtime:o,Handler:F,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...St.length?{Layers:[...new Set(St)]}:{}};T[M]={Type:"AWS::Lambda::Function",DependsOn:[`${M}LogGroup`,...Oe],Properties:{FunctionName:j,Architectures:[c],MemorySize:re,Timeout:Ze,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:x(q)},EphemeralStorage:{Size:et},...bt,...se!==void 0?{ReservedConcurrentExecutions:se}:{},...de,...ft}}}if(X("HttpFunction",d.http,n.http,"http",a.memory??1024,a.timeout??28,a.concurrency,R),X("CliFunction",d.cli,n.cli,"cli",a.cliMemory??1024,a.cliTimeout??900,void 0,a.cliTmpStorage??R),g)X("QueueFunction",d.queue,n.queue,"queue",a.queueMemory??1024,a.queueTimeout??120,void 0,a.queueTmpStorage??R);let Y=(a.provisionedConcurrency??0)>0?a.provisionedConcurrency:0,te=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(Y)for(let M of te)T[`${M}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(M)}},T[`${M}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(M),Name:"live",FunctionVersion:t.getAtt(`${M}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Y}}};let me=(M)=>Y?t.ref(`${M}Alias`):t.getAtt(M,"Arn"),ae=(M)=>Y?t.ref(`${M}Alias`):t.ref(M);T.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${i}-${r}`,ProtocolType:"HTTP"}},T.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:me("HttpFunction"),PayloadFormatVersion:"2.0"}},T.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},T.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},T.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}/*/*")}},N.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},N.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ie=(Array.isArray(a.domain)?a.domain:a.domain?[a.domain]:[]).filter(Boolean);if(ie.length){if(!a.certificateArn&&!a.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let M=a.certificateArn;if(!M)T.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ie[0],...ie.length>1?{SubjectAlternativeNames:ie.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ie.map((j)=>({DomainName:j,HostedZoneId:a.hostedZoneId}))}},M=t.ref("HttpCertificate");ie.forEach((j,F)=>{let q=`HttpDomain${F}`;if(T[q]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:j,DomainNameConfigurations:[{CertificateArn:M,EndpointType:"REGIONAL"}]}},T[`HttpApiMapping${F}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(q),Stage:"$default"}},a.hostedZoneId)T[`HttpDomainRecord${F}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:j,Type:"A",AliasTarget:{DNSName:t.getAtt(q,"RegionalDomainName"),HostedZoneId:t.getAtt(q,"RegionalHostedZoneId")}}};N[`CustomDomain${F}`]={Description:`Custom domain ${j}`,Value:j},N[`CustomDomainTarget${F}`]={Description:`Point ${j} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(q,"RegionalDomainName")}})}if(g)T.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${i}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((M,j)=>{let F=`AppQueue${j}`,q=a.queueTimeout??120;T[F]={Type:"AWS::SQS::Queue",Properties:{QueueName:M.name,VisibilityTimeout:Math.min(43200,q*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:a.queueTries??3}}};let re=M.concurrency??a.queueConcurrency;T[`${F}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(F,"Arn"),FunctionName:ae("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...re?{ScalingConfig:{MaximumConcurrency:Math.max(2,re)}}:{}}},N[`QueueUrl${j}`]={Description:`Queue URL: ${M.name}`,Value:t.ref(F)}});if(f)T.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:me("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},T.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(a.warm&&a.warm>0){let M={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},j=(a.warmFunctions??["http"]).filter((F)=>F!=="queue"||g);for(let F of j){let q=F.charAt(0).toUpperCase()+F.slice(1),re=Math.ceil(a.warm/5),Ze=0;for(let se=0;se<re;se++){let et=Math.min(5,a.warm-Ze);T[`Warmer${q}Rule${se}`]={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-warmer-${F}-${se}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:et},(St,bt)=>({Id:`warm-${F}-${se}-${bt}`,Arn:t.getAtt(M[F],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Ze+=et}T[`Warmer${q}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(M[F]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${i}-${r}-warmer-${F}-*`)}}}}if(b)T.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${i}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},N.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(v){if(T.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:P,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},T.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${i}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},T.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:""}}],...a.assetDomain?{Aliases:[a.assetDomain],ViewerCertificate:{AcmCertificateArn:a.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},a.assetDomain){if(!a.assetCertificateArn){if(!a.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.`);T.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:a.assetDomain,HostedZoneId:a.hostedZoneId}]}}}if(a.hostedZoneId)T.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:a.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};N.AssetDomain={Description:"Custom asset CDN host",Value:a.assetDomain}}T.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}")}}}]}}},N.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},N.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(a.firewall?.enabled){let M=[],j=0;if(a.firewall.rateLimit)M.push({Name:"rate-limit",Priority:j++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:a.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-rate`}});let F={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let q of a.firewall.rules??[]){let re=F[q];if(!re)continue;M.push({Name:`managed-${q}`,Priority:j++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:re}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-${q}`}})}T.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${i}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:M,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-waf`}}},N.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&&H){if(!a.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.");T.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:a.vpc.id,GroupDescription:`${i}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(K)T.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${i}-${r}-efs`}]}},z.forEach((M,j)=>{T[`EfsMountTarget${j}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:M,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),T.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"}}}},N.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(a.cache?.driver==="elasticache")T.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${i}-${r} cache subnets`,SubnetIds:z}},T.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${i}-${r}-cache`,ReplicationGroupDescription:`${i}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},N.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(a.database?.connection==="aurora-serverless")T.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${i}-${r} db subnets`,SubnetIds:z}},T.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${i}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},T.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${i}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:a.database?.minCapacity??0.5,MaxCapacity:a.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},T.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},N.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(a.rdsProxy&&a.database?.connection==="aurora-serverless")T.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")}]}}]}},T.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof a.rdsProxy==="object"&&a.rdsProxy.name?a.rdsProxy.name:`${i}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:z,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},T.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},N.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(N.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},N.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)N.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let fe={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${i}-${r})`,Parameters:y?{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:T,Outputs:N},Be={};for(let M of Object.values(T))Be[M.Type]=(Be[M.Type]??0)+1;return{template:fe,functionNames:d,queueNames:p,resourceSummary:Be}}var Hd=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Wd(e){let a=`php${e.replace(".","")}`;return Hd.map((r)=>`${a}-php-${r}`)}function cl(e,a){let r=`php${e.replace(".","")}`,n=Wd(e).join(" \\\n "),i=`/opt/remi/${r}/root`,o=`/etc/opt/remi/${r}`;return`${a?`FROM almalinux:9 AS ${a}`:"FROM almalinux:9"}
|
|
7286
|
+
${h}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Si([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:Ao(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{Ei(o,{recursive:!0,force:!0})}}var qd=["18","20","22"];function Mi(e){if(!e)return"22";let a=String(e).match(/(\d+)/);return a?a[1]:"22"}function Io(e){let a=e.kind??"node";if(a==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(a==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=Mi(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&qd.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 Vt(e,a,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${a}-${r}-default`}];return e.queues.map((n)=>{if(typeof n==="string")return{name:`${a}-${r}-${n}`};let[i,o]=Object.entries(n)[0];return{name:`${a}-${r}-${i}`,concurrency:o}})}function Ws(e,a,r){return Vt(e,a,r).map((n)=>n.name)}function Gs(e){let{app:a,environment:r,handlers:n}=e,i=e.config.project.slug,o=Io(a).lambdaRuntime,c=a.architecture??"x86_64",u=e.config.project.region,d={http:`${i}-${r}-http`,queue:`${i}-${r}-queue`,cli:`${i}-${r}-cli`};if(a.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=Vt(a,i,r),p=m.map((M)=>M.name),g=p.length>0,h=a.logRetention??14,y=a.packaging==="image";if(y&&a.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 f=(a.scheduler??"on")!=="off",b=(a.cache?.driver??"dynamodb")==="dynamodb",v=Boolean(a.assets),P=So(i,r),R=a.tmpStorage??512,T={},N={},I=[{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:${i}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${i}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${i}/${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}/*`),...a.storage?.bucket?[t.sub(`arn:aws:s3:::${a.storage.bucket}`),t.sub(`arn:aws:s3:::${a.storage.bucket}/*`)]:[]]}]}}];if(g)I[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}:${i}-${r}-*`)});if(b)I[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/${i}-${r}-cache*`)});let k=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(a.vpc?.subnets?.length)k.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(a.lambdaInsights)k.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");T.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:k,Policies:I}};let x=(M)=>({TSCLOUD_LAMBDA_MODE:M,TSCLOUD_ENV:r,...a.octane?{TSCLOUD_OCTANE:"1"}:{},...a.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...b?{TSCLOUD_CACHE_TABLE:`${i}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...a.env??{}}),L=Boolean(a.efs),O=typeof a.efs==="object"?a.efs:{},W=O.mountPath??"/mnt/local",K=L&&!O.accessPointArn,Z=O.accessPointArn??(K?t.getAtt("EfsAccessPoint","Arn"):void 0),z=a.vpc?.subnets??[],J=z.length>0,H=a.cache?.driver==="elasticache"||a.database?.connection==="aurora-serverless"||Boolean(a.rdsProxy)||L;if(H&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let de=J?{VpcConfig:{SubnetIds:z,SecurityGroupIds:[...a.vpc?.securityGroups??[],...H?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Oe=K?z.map((M,j)=>`EfsMountTarget${j}`):[],ft=L?{FileSystemConfigs:[{Arn:Z,LocalMountPath:W}]}:{};if(L)I[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function X(M,j,F,q,re,Je,se,Xe=R){T[`${M}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${j}`,RetentionInDays:h}};let St=[...e.runtimeLayers??[],...a.lambdaInsights?[a.lambdaInsights.layerArn]:[]],bt=y?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...a.kind==="php"?{}:{ImageConfig:{Command:[F]}}}:{Runtime:o,Handler:F,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...St.length?{Layers:[...new Set(St)]}:{}};T[M]={Type:"AWS::Lambda::Function",DependsOn:[`${M}LogGroup`,...Oe],Properties:{FunctionName:j,Architectures:[c],MemorySize:re,Timeout:Je,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:x(q)},EphemeralStorage:{Size:Xe},...bt,...se!==void 0?{ReservedConcurrentExecutions:se}:{},...de,...ft}}}if(X("HttpFunction",d.http,n.http,"http",a.memory??1024,a.timeout??28,a.concurrency,R),X("CliFunction",d.cli,n.cli,"cli",a.cliMemory??1024,a.cliTimeout??900,void 0,a.cliTmpStorage??R),g)X("QueueFunction",d.queue,n.queue,"queue",a.queueMemory??1024,a.queueTimeout??120,void 0,a.queueTmpStorage??R);let Y=(a.provisionedConcurrency??0)>0?a.provisionedConcurrency:0,te=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(Y)for(let M of te)T[`${M}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(M)}},T[`${M}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(M),Name:"live",FunctionVersion:t.getAtt(`${M}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Y}}};let me=(M)=>Y?t.ref(`${M}Alias`):t.getAtt(M,"Arn"),ae=(M)=>Y?t.ref(`${M}Alias`):t.ref(M);T.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${i}-${r}`,ProtocolType:"HTTP"}},T.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:me("HttpFunction"),PayloadFormatVersion:"2.0"}},T.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},T.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},T.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}/*/*")}},N.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},N.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ie=(Array.isArray(a.domain)?a.domain:a.domain?[a.domain]:[]).filter(Boolean);if(ie.length){if(!a.certificateArn&&!a.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let M=a.certificateArn;if(!M)T.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ie[0],...ie.length>1?{SubjectAlternativeNames:ie.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ie.map((j)=>({DomainName:j,HostedZoneId:a.hostedZoneId}))}},M=t.ref("HttpCertificate");ie.forEach((j,F)=>{let q=`HttpDomain${F}`;if(T[q]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:j,DomainNameConfigurations:[{CertificateArn:M,EndpointType:"REGIONAL"}]}},T[`HttpApiMapping${F}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(q),Stage:"$default"}},a.hostedZoneId)T[`HttpDomainRecord${F}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:j,Type:"A",AliasTarget:{DNSName:t.getAtt(q,"RegionalDomainName"),HostedZoneId:t.getAtt(q,"RegionalHostedZoneId")}}};N[`CustomDomain${F}`]={Description:`Custom domain ${j}`,Value:j},N[`CustomDomainTarget${F}`]={Description:`Point ${j} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(q,"RegionalDomainName")}})}if(g)T.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${i}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((M,j)=>{let F=`AppQueue${j}`,q=a.queueTimeout??120;T[F]={Type:"AWS::SQS::Queue",Properties:{QueueName:M.name,VisibilityTimeout:Math.min(43200,q*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:a.queueTries??3}}};let re=M.concurrency??a.queueConcurrency;T[`${F}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(F,"Arn"),FunctionName:ae("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...re?{ScalingConfig:{MaximumConcurrency:Math.max(2,re)}}:{}}},N[`QueueUrl${j}`]={Description:`Queue URL: ${M.name}`,Value:t.ref(F)}});if(f)T.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:me("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},T.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(a.warm&&a.warm>0){let M={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},j=(a.warmFunctions??["http"]).filter((F)=>F!=="queue"||g);for(let F of j){let q=F.charAt(0).toUpperCase()+F.slice(1),re=Math.ceil(a.warm/5),Je=0;for(let se=0;se<re;se++){let Xe=Math.min(5,a.warm-Je);T[`Warmer${q}Rule${se}`]={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-warmer-${F}-${se}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Xe},(St,bt)=>({Id:`warm-${F}-${se}-${bt}`,Arn:t.getAtt(M[F],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Je+=Xe}T[`Warmer${q}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(M[F]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${i}-${r}-warmer-${F}-*`)}}}}if(b)T.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${i}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},N.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(v){if(T.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:P,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},T.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${i}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},T.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:""}}],...a.assetDomain?{Aliases:[a.assetDomain],ViewerCertificate:{AcmCertificateArn:a.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},a.assetDomain){if(!a.assetCertificateArn){if(!a.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.`);T.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:a.assetDomain,HostedZoneId:a.hostedZoneId}]}}}if(a.hostedZoneId)T.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:a.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};N.AssetDomain={Description:"Custom asset CDN host",Value:a.assetDomain}}T.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}")}}}]}}},N.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},N.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(a.firewall?.enabled){let M=[],j=0;if(a.firewall.rateLimit)M.push({Name:"rate-limit",Priority:j++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:a.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-rate`}});let F={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let q of a.firewall.rules??[]){let re=F[q];if(!re)continue;M.push({Name:`managed-${q}`,Priority:j++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:re}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-${q}`}})}T.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${i}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:M,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-waf`}}},N.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&&H){if(!a.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.");T.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:a.vpc.id,GroupDescription:`${i}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(K)T.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${i}-${r}-efs`}]}},z.forEach((M,j)=>{T[`EfsMountTarget${j}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:M,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),T.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"}}}},N.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(a.cache?.driver==="elasticache")T.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${i}-${r} cache subnets`,SubnetIds:z}},T.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${i}-${r}-cache`,ReplicationGroupDescription:`${i}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},N.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(a.database?.connection==="aurora-serverless")T.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${i}-${r} db subnets`,SubnetIds:z}},T.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${i}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},T.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${i}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:a.database?.minCapacity??0.5,MaxCapacity:a.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},T.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},N.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(a.rdsProxy&&a.database?.connection==="aurora-serverless")T.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")}]}}]}},T.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof a.rdsProxy==="object"&&a.rdsProxy.name?a.rdsProxy.name:`${i}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:z,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},T.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},N.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(N.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},N.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)N.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let fe={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${i}-${r})`,Parameters:y?{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:T,Outputs:N},Be={};for(let M of Object.values(T))Be[M.Type]=(Be[M.Type]??0)+1;return{template:fe,functionNames:d,queueNames:p,resourceSummary:Be}}var Hd=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Wd(e){let a=`php${e.replace(".","")}`;return Hd.map((r)=>`${a}-php-${r}`)}function cl(e,a){let r=`php${e.replace(".","")}`,n=Wd(e).join(" \\\n "),i=`/opt/remi/${r}/root`,o=`/etc/opt/remi/${r}`;return`${a?`FROM almalinux:9 AS ${a}`:"FROM almalinux:9"}
|
|
7287
7287
|
|
|
7288
7288
|
# Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
|
|
7289
7289
|
# cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
|
|
@@ -7344,7 +7344,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
7344
7344
|
|
|
7345
7345
|
# Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
|
|
7346
7346
|
CMD [ "index.http" ]
|
|
7347
|
-
`}function _a(){return xi(Oi(import.meta.url))}function ll(){return yt(ue(_a(),"runtime.mjs"),"utf-8")}function Ua(e){return yt(ue(_a(),`${e}-bootstrap`),"utf-8")}function cf(e){let a=e.architecture??"x86_64",r=a==="arm64"?"arm64":"x64",n=e.version.replace(/^v/,""),i=e.onStep??(()=>{}),o=xa(ue(Ba(),"tscloud-node-layer-"));try{let c=n.includes(".")?n:Bi(n),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;i(`downloading Node ${c} (${a})`);let m=ue(o,"node.tar.xz");Fa(d,m),i("extracting node binary"),ht("tar",["-xf",m,"-C",o,`${u}/bin/node`],{stdio:"inherit"});let p=yt(ue(o,u,"bin","node"));i("packaging layer");let g=[{name:"bootstrap",data:Ua("node"),mode:493},{name:"runtime.mjs",data:ll(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:Si(g),architecture:a,version:c,fileCount:g.length}}finally{Oa(o,{recursive:!0,force:!0})}}function lf(e){let a=e.architecture??"x86_64",r=a==="arm64"?"bun-linux-aarch64":"bun-linux-x64",n=e.version==="latest"?"":e.version.replace(/^v/,""),i=e.onStep??(()=>{}),o=xa(ue(Ba(),"tscloud-bun-layer-"));try{let c=n?`https://github.com/oven-sh/bun/releases/download/bun-v${n}/${r}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${r}.zip`;i(`downloading Bun ${n||"latest"} (${a})`);let u=ue(o,"bun.zip");Fa(c,u),i("extracting bun binary"),ht("unzip",["-o","-q",u,"-d",o],{stdio:"inherit"});let d=yt(ue(o,r,"bun"));i("packaging layer");let m=[{name:"bootstrap",data:Ua("bun"),mode:493},{name:"runtime.mjs",data:ll(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:Si(m),architecture:a,version:n||"latest",fileCount:m.length}}finally{Oa(o,{recursive:!0,force:!0})}}function Fa(e,a){ht("curl",["-fsSL","-o",a,e],{stdio:["ignore","ignore","inherit"]})}function Bi(e){let a=ht("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),r=JSON.parse(a).find((n)=>n.version.startsWith(`v${e}.`));if(!r)throw Error(`No Node release found for major version ${e}`);return r.version.replace(/^v/,"")}var Js="x-ts-cloud-invoke-depth",Xs="x-ts-cloud-invoke-chain",Qs="x-ts-cloud-trace-id";function dl(e){return Wi("sha256").update(e).digest("hex").slice(0,8)}var Ro={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Dt(e,a){if(typeof e.get==="function")return e.get(a)??void 0;let r=e;return r[a]??r[a.toLowerCase()]??r[a.toUpperCase()]}function ul(e,a=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-a)}function pl(e,a=Ro){let r=dl(e.functionId),n=ul(Dt(e.headers,Xs)),i=e.traceId??Dt(e.headers,Qs)??crypto.randomUUID(),o=[...n,r],c=n.filter((g)=>g===r).length,u=n[n.length-1]===r,d=Number.parseInt(Dt(e.headers,Js)??"",10),m=Math.max(o.length,Number.isFinite(d)?d+1:0),p="ok";if(m>a.maxDepth)p="depth_exceeded";else if(c>=a.maxRepeats)p="cycle_detected";else if(u&&a.maxRepeats<=1)p="self_invocation";return{reason:p,depth:m,chain:o,traceId:i,selfInvocation:u,repeats:c,propagate:{[Js]:String(m),[Xs]:o.join("."),[Qs]:i}}}var Va={ok:"",depth_exceeded:"Invocation chain is deeper than the configured limit; the call was refused to stop a runaway loop.",cycle_detected:"This function already appears in the invocation chain; the call was refused as a recursion loop.",self_invocation:"This function invoked itself directly; the call was refused.",trace_budget_exceeded:"This request has already made more invocations than its budget allows.",breaker_open:"Recursion protection is open for this function after repeated loop detections."};class Ys{limits;clock;traces=new Map;breakers=new Map;constructor(e=Ro,a=()=>Date.now()){this.limits=e,this.clock=a}check(e){let a=this.clock();this.expireTraces(a);let r=pl(e,this.limits),n=this.breakers.get(e.functionId);if(n?.openUntil!=null&&n.openUntil>a)return this.deny(e.functionId,r,"breaker_open",a,!1);if(r.reason!=="ok")return this.deny(e.functionId,r,r.reason,a,!0);let i=this.traces.get(r.traceId)??{count:0,firstAt:a};if(i.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,i),this.deny(e.functionId,r,"trace_budget_exceeded",a,!0);if(this.traces.set(r.traceId,{count:i.count+1,firstAt:i.firstAt}),n)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,a,r,n,i){if(i){let o=this.breakers.get(e)??{consecutiveBlocks:0},c=o.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?n+this.limits.breakerCooldownMs:o.openUntil})}return{...a,allowed:!1,reason:r,message:Va[r]}}breakerOpen(e){let a=this.breakers.get(e);return a?.openUntil!=null&&a.openUntil>this.clock()}reset(e){if(e){this.breakers.delete(e);return}this.breakers.clear(),this.traces.clear()}expireTraces(e){if(this.traces.size===0)return;for(let[a,r]of this.traces)if(e-r.firstAt>this.limits.traceWindowMs)this.traces.delete(a)}get trackedTraces(){return this.traces.size}}function ml(e){return{...e.propagate}}function gl(e){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":e.reason},body:{error:"recursion_blocked",reason:e.reason,message:e.message??Va[e.reason],depth:e.depth,traceId:e.traceId}}}var fl=new _i;function ga(e){let a=globalThis.process?.env?.[e];if(a==null||a==="")return;return a!=="0"&&a.toLowerCase()!=="false"}function Gi(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Kd(e){let a=e===!1?{enabled:!1}:e??{},r=ga("TS_CLOUD_RECURSION_PROTECTION"),n=ga("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??a.enabled??!0,detectionOnly:n??a.detectionOnly??!1,limits:{...Ro,...a.limits},functionId:a.functionId??Gi()}}var he,ne;function Jd(){let e=globalThis.fetch;if(!e||he===e)return()=>{};ne=e;let a=async(r,n)=>{let i=fl.getStore();if(!i)return ne(r,n);let o=new Headers(n?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(ml(i)))o.set(c,u);if(r instanceof Request)return ne(new Request(r,{headers:o}),n);return ne(r,{...n,headers:o})};return Object.assign(a,e),globalThis.fetch=a,he=a,()=>{if(globalThis.fetch===he&&ne)globalThis.fetch=ne;he=void 0}}var st,
|
|
7347
|
+
`}function _a(){return xi(Oi(import.meta.url))}function ll(){return yt(ue(_a(),"runtime.mjs"),"utf-8")}function Ua(e){return yt(ue(_a(),`${e}-bootstrap`),"utf-8")}function cf(e){let a=e.architecture??"x86_64",r=a==="arm64"?"arm64":"x64",n=e.version.replace(/^v/,""),i=e.onStep??(()=>{}),o=xa(ue(Ba(),"tscloud-node-layer-"));try{let c=n.includes(".")?n:Bi(n),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;i(`downloading Node ${c} (${a})`);let m=ue(o,"node.tar.xz");Fa(d,m),i("extracting node binary"),ht("tar",["-xf",m,"-C",o,`${u}/bin/node`],{stdio:"inherit"});let p=yt(ue(o,u,"bin","node"));i("packaging layer");let g=[{name:"bootstrap",data:Ua("node"),mode:493},{name:"runtime.mjs",data:ll(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:Si(g),architecture:a,version:c,fileCount:g.length}}finally{Oa(o,{recursive:!0,force:!0})}}function lf(e){let a=e.architecture??"x86_64",r=a==="arm64"?"bun-linux-aarch64":"bun-linux-x64",n=e.version==="latest"?"":e.version.replace(/^v/,""),i=e.onStep??(()=>{}),o=xa(ue(Ba(),"tscloud-bun-layer-"));try{let c=n?`https://github.com/oven-sh/bun/releases/download/bun-v${n}/${r}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${r}.zip`;i(`downloading Bun ${n||"latest"} (${a})`);let u=ue(o,"bun.zip");Fa(c,u),i("extracting bun binary"),ht("unzip",["-o","-q",u,"-d",o],{stdio:"inherit"});let d=yt(ue(o,r,"bun"));i("packaging layer");let m=[{name:"bootstrap",data:Ua("bun"),mode:493},{name:"runtime.mjs",data:ll(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:Si(m),architecture:a,version:n||"latest",fileCount:m.length}}finally{Oa(o,{recursive:!0,force:!0})}}function Fa(e,a){ht("curl",["-fsSL","-o",a,e],{stdio:["ignore","ignore","inherit"]})}function Bi(e){let a=ht("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),r=JSON.parse(a).find((n)=>n.version.startsWith(`v${e}.`));if(!r)throw Error(`No Node release found for major version ${e}`);return r.version.replace(/^v/,"")}var Js="x-ts-cloud-invoke-depth",Xs="x-ts-cloud-invoke-chain",Qs="x-ts-cloud-trace-id";function dl(e){return Wi("sha256").update(e).digest("hex").slice(0,8)}var Ro={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Dt(e,a){if(typeof e.get==="function")return e.get(a)??void 0;let r=e;return r[a]??r[a.toLowerCase()]??r[a.toUpperCase()]}function ul(e,a=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-a)}function pl(e,a=Ro){let r=dl(e.functionId),n=ul(Dt(e.headers,Xs)),i=e.traceId??Dt(e.headers,Qs)??crypto.randomUUID(),o=[...n,r],c=n.filter((g)=>g===r).length,u=n[n.length-1]===r,d=Number.parseInt(Dt(e.headers,Js)??"",10),m=Math.max(o.length,Number.isFinite(d)?d+1:0),p="ok";if(m>a.maxDepth)p="depth_exceeded";else if(c>=a.maxRepeats)p="cycle_detected";else if(u&&a.maxRepeats<=1)p="self_invocation";return{reason:p,depth:m,chain:o,traceId:i,selfInvocation:u,repeats:c,propagate:{[Js]:String(m),[Xs]:o.join("."),[Qs]:i}}}var Va={ok:"",depth_exceeded:"Invocation chain is deeper than the configured limit; the call was refused to stop a runaway loop.",cycle_detected:"This function already appears in the invocation chain; the call was refused as a recursion loop.",self_invocation:"This function invoked itself directly; the call was refused.",trace_budget_exceeded:"This request has already made more invocations than its budget allows.",breaker_open:"Recursion protection is open for this function after repeated loop detections."};class Ys{limits;clock;traces=new Map;breakers=new Map;constructor(e=Ro,a=()=>Date.now()){this.limits=e,this.clock=a}check(e){let a=this.clock();this.expireTraces(a);let r=pl(e,this.limits),n=this.breakers.get(e.functionId);if(n?.openUntil!=null&&n.openUntil>a)return this.deny(e.functionId,r,"breaker_open",a,!1);if(r.reason!=="ok")return this.deny(e.functionId,r,r.reason,a,!0);let i=this.traces.get(r.traceId)??{count:0,firstAt:a};if(i.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,i),this.deny(e.functionId,r,"trace_budget_exceeded",a,!0);if(this.traces.set(r.traceId,{count:i.count+1,firstAt:i.firstAt}),n)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,a,r,n,i){if(i){let o=this.breakers.get(e)??{consecutiveBlocks:0},c=o.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?n+this.limits.breakerCooldownMs:o.openUntil})}return{...a,allowed:!1,reason:r,message:Va[r]}}breakerOpen(e){let a=this.breakers.get(e);return a?.openUntil!=null&&a.openUntil>this.clock()}reset(e){if(e){this.breakers.delete(e);return}this.breakers.clear(),this.traces.clear()}expireTraces(e){if(this.traces.size===0)return;for(let[a,r]of this.traces)if(e-r.firstAt>this.limits.traceWindowMs)this.traces.delete(a)}get trackedTraces(){return this.traces.size}}function ml(e){return{...e.propagate}}function gl(e){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":e.reason},body:{error:"recursion_blocked",reason:e.reason,message:e.message??Va[e.reason],depth:e.depth,traceId:e.traceId}}}var fl=new _i;function ga(e){let a=globalThis.process?.env?.[e];if(a==null||a==="")return;return a!=="0"&&a.toLowerCase()!=="false"}function Gi(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Kd(e){let a=e===!1?{enabled:!1}:e??{},r=ga("TS_CLOUD_RECURSION_PROTECTION"),n=ga("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??a.enabled??!0,detectionOnly:n??a.detectionOnly??!1,limits:{...Ro,...a.limits},functionId:a.functionId??Gi()}}var he,ne;function Jd(){let e=globalThis.fetch;if(!e||he===e)return()=>{};ne=e;let a=async(r,n)=>{let i=fl.getStore();if(!i)return ne(r,n);let o=new Headers(n?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(ml(i)))o.set(c,u);if(r instanceof Request)return ne(new Request(r,{headers:o}),n);return ne(r,{...n,headers:o})};return Object.assign(a,e),globalThis.fetch=a,he=a,()=>{if(globalThis.fetch===he&&ne)globalThis.fetch=ne;he=void 0}}var st,xt;function Xd(e){if(!st||JSON.stringify(xt)!==JSON.stringify(e))st=new Ys(e),xt=e;return st}function df(){if(st=void 0,xt=void 0,he&&ne&&globalThis.fetch===he)globalThis.fetch=ne;he=void 0,ne=void 0}function Qd(e,a){let r=Kd(a);if(!r.enabled)return;let n=Xd(r.limits),i={functionId:r.functionId,headers:e},o=n.check(i);return{verdict:o,blocked:!o.allowed&&!r.detectionOnly,observed:!o.allowed&&r.detectionOnly}}function Yd(e,a){return Jd(),fl.run(e,a)}function uf(e){let a=e,r=a?.default??a;if(typeof r==="function")return{fetch:r};return{fetch:r?.fetch??a?.fetch,queue:r?.queue??a?.queue,cli:r?.cli??a?.cli}}var Ui=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Fi(e){if(!e)return!0;return Ui.test(e)}function Vi(e){if(e?.maintenance)return e.maintenance;let a=globalThis.process?.env??{};return{enabled:a.MAINTENANCE_MODE==="1"||a.MAINTENANCE_MODE==="true",bypassSecret:a.MAINTENANCE_BYPASS_SECRET}}function Zd(e){let a=e.requestContext?.domainName??"localhost",r=e.rawQueryString?`?${e.rawQueryString}`:"",n=`https://${a}${e.rawPath||"/"}${r}`,i=new Headers;for(let[u,d]of Object.entries(e.headers??{}))if(d!==void 0)i.set(u,d);if(e.cookies?.length)i.set("cookie",e.cookies.join("; "));let o=e.requestContext.http.method,c;if(e.body!==void 0&&o!=="GET"&&o!=="HEAD")c=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(n,{method:o,headers:i,body:c})}async function hl(e){let a={},r=[],n=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let c of n)r.push(c);e.headers.forEach((c,u)=>{if(u.toLowerCase()==="set-cookie")return;a[u]=c});let i=Buffer.from(await e.arrayBuffer()),o=Fi(e.headers.get("content-type"));return{statusCode:e.status,headers:a,...r.length?{cookies:r}:{},body:o?i.toString("utf-8"):i.toString("base64"),isBase64Encoded:!o}}function eu(e,a){return async(r)=>{if(r.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!e)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let n=Vi(a);if(n.enabled){let c=r.headers?.["x-maintenance-bypass"]??r.cookies?.find((u)=>u.startsWith("tscloud_bypass="))?.split("=")[1];if(!n.bypassSecret||c!==n.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let i=Qd(r.headers??{},a?.recursionProtection);if(i?.blocked){let c=gl(i.verdict);return{statusCode:c.status,headers:{...c.headers,"retry-after":"60"},body:JSON.stringify(c.body),isBase64Encoded:!1}}let o=Zd(r);if(!i){let c=await e(o);return hl(c)}if(i.observed)console.warn(`[ts-cloud] recursion detected (${i.verdict.reason}) at depth ${i.verdict.depth}; detection-only mode let it run`);return Yd(i.verdict,async()=>hl(await e(o)))}}function ji(e){try{return JSON.parse(e)}catch{return e}}function tu(e){return async(a)=>{let r=[];if(a.warmer)return{batchItemFailures:r};if(!e)return{batchItemFailures:r};for(let n of a.Records??[])try{await e(ji(n.body),n)}catch{r.push({itemIdentifier:n.messageId})}return{batchItemFailures:r}}}function ru(e){return async(a)=>{if(a.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(a)}}function pf(e,a){return{http:eu(e.fetch,a),queue:tu(e.queue),cli:ru(e.cli)}}function nu(e={}){let a=e.socketPath??"/tmp/.tscloud-fpm.sock",r=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7348
7348
|
[global]
|
|
7349
7349
|
daemonize = no
|
|
7350
7350
|
error_log = ${e.errorLog??"/tmp/storage/logs/php-fpm.log"}
|
|
@@ -7361,4 +7361,4 @@ decorate_workers_output = no
|
|
|
7361
7361
|
php_admin_value[error_log] = /dev/stderr
|
|
7362
7362
|
php_admin_flag[log_errors] = on
|
|
7363
7363
|
clear_env = no
|
|
7364
|
-
`}function zi(){return ja(Hi(qi(import.meta.url)),"runtime-assets")}function bi(){let e=zi(),a=(r)=>Ki(ja(e,r),"utf-8");return[{path:"bootstrap",contents:a("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:a("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:a("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:a("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:a("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:nu(),mode:420}]}function Zs(e={}){let a=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:a,CACHE_DRIVER:a,SESSION_DRIVER:a,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 iu=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];function*qa(e){for(let a of Zi(e)){let r=Re(e,a);if(Ha(r).isDirectory())yield*qa(r);else yield r}}function mf(e={}){let a=e.architecture??"x86_64",r=e.platform??(a==="arm64"?"linux/arm64":"linux/amd64"),n=e.onStep??(()=>{}),i=Yi(Re(as(),"tscloud-php-layer-")),o="tscloud-php-layer:build";try{ts(Re(i,"Dockerfile"),Gd(e)),n("Building PHP runtime image (docker)"),it("docker",["build","--platform",r,"-t","tscloud-php-layer:build",i],{stdio:"inherit"}),n("Extracting /opt/php from image");let c=it("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Re(i,"opt");Ji(u,{recursive:!0});try{it("docker",["cp",`${c}:/opt/php`,Re(u,"php")],{stdio:"inherit"})}finally{it("docker",["rm",c],{stdio:"ignore"})}if(!Qi(Re(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let g of qa(u)){let h=rs(u,g).replace(/\\/g,"/"),y=Ha(g).mode&73?493:420;d.push({name:h,data:Xi(g),mode:y})}n("Injecting runtime assets");let m=new Set(bi().map((g)=>g.path)),p=d.filter((g)=>!m.has(g.name));for(let g of bi())p.push({name:g.path,data:g.contents,mode:g.mode});return n("Packaging layer ZIP"),{zip:Si(p),architecture:a,fileCount:p.length}}finally{es(i,{recursive:!0,force:!0})}}var ou=[".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 ls(e,a){return a.some((r)=>e===r||e.startsWith(`${r}/`))}function*tr(e,a,r){for(let n of ss(e)){let i=cs(e,n),o=er(a,i).replace(/\\/g,"/");if(ls(o,r))continue;if(za(i).isDirectory())yield*tr(i,a,r);else yield i}}function Po(e){if(e.skipBuild)return;let a=ia(e.projectRoot??process.cwd()),r=e.app.build??iu;for(let n of r)e.onStep?.(`build: ${n}`),ns(n,{stdio:"inherit",cwd:a})}function No(e,a=[]){let r=ia(e),n=[...ou,ho(),...a],i=[];for(let o of tr(r,r,n)){let c=er(r,o).replace(/\\/g,"/"),u=(za(o).mode&73)!==0;i.push({name:c,data:os(o),mode:u?493:420})}return i}function ea(e){let a=ia(e.projectRoot??process.cwd());Po(e),e.onStep?.("packaging application tree");let r=No(a,e.exclude);if(!r.length)throw Error(`No files to package under ${a}`);let n=Si(r),i=e.app.handlers?.http??"public/index.php";return{zip:n,sha256:is("sha256").update(n).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:r.length}}class yl{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let a=`asset-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.optimizations.set(a,r),r}createImageOptimization(e){let a=`image-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.imageConfigs.set(a,r),r}createSSGConfig(e){let a=`ssg-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.ssgConfigs.set(a,r),r}createPrerenderConfig(e){let a=`prerender-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.prerenderConfigs.set(a,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 gf=new yl;class Sl{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,a){let r=`lifecycle-${Date.now()}-${this.counter++}`,n={id:r,transitions:e,expiration:a};return this.policies.set(r,n),n}enableVersioning(e=!1){let a=`versioning-${Date.now()}-${this.counter++}`,r={id:a,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(a,r),r}createReplicationRule(e,a,r){let n=`replication-${Date.now()}-${this.counter++}`,i={id:n,sourceRegion:e,destRegion:a,destBucket:r};return this.replicationRules.set(n,i),i}createIntelligentTiering(e,a){let r=`tiering-${Date.now()}-${this.counter++}`,n={id:r,archiveDays:e,deepArchiveDays:a};return this.tieringConfigs.set(r,n),n}enableObjectLock(e){let a=`object-lock-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(a,r),r}enableTransferAcceleration(e){let a=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(a,r),r}createAccessPoint(e){let a=`access-point-${Date.now()}-${this.counter++}`,r={id:a,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(a,r),r}createGlacierArchive(e){let a=`glacier-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createInventory(e){let a=`inventory-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createBatchOperation(e){let a=`batch-op-${Date.now()}-${this.counter++}`,r={id:a,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(a,r),r}executeBatchOperation(e){let a=this.batchOps.get(e);if(!a)throw Error(`Batch operation not found: ${e}`);return a.status="in_progress",a.totalObjects=1000,a.processedObjects=0,a}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSQSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSNSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}generateObjectLockCF(e){let a={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)a.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)a.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return a}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 a=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",n={Event:e.events[0],[r]:e.destination.arn};if(e.filter)n.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[a]:[n]}}}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 ff=new Sl;class bl{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,a=30,r=10){let n=`health-${Date.now()}-${this.counter++}`,i={id:n,url:e,interval:a,timeout:r,status:"healthy"};return this.checks.set(n,i),i}createSyntheticMonitor(e,a,r,n){let i=`synthetic-${Date.now()}-${this.counter++}`,o={id:i,name:e,script:a,frequency:r,locations:n};return this.synthetics.set(i,o),o}trackUptime(e,a,r){let n=`uptime-${Date.now()}-${this.counter++}`,i=a/(a+r)*100,o={id:n,resource:e,uptime:a,downtime:r,availability:i};return this.uptimeTrackers.set(n,o),o}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var hf=new bl;class vl{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,a,r,n){let i=`waf-${Date.now()}-${this.counter++}`,o={id:i,name:e,priority:a,action:r,conditions:n};return this.wafRules.set(i,o),o}enableShield(e,a="standard"){let r=`shield-${Date.now()}-${this.counter++}`,n={id:r,resourceArn:e,protectionType:a};return this.shieldProtections.set(r,n),n}createSecurityGroup(e,a,r){let n=`sg-${Date.now()}-${this.counter++}`,i={id:n,name:e,vpcId:a,rules:r};return this.securityGroups.set(n,i),i}createNACL(e,a){let r=`nacl-${Date.now()}-${this.counter++}`,n={id:r,vpcId:e,rules:a};return this.nacls.set(r,n),n}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var yf=new vl;class Tl{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,a){let r=`tagging-${Date.now()}-${this.counter++}`,n={id:r,tags:e,resources:a};return this.strategies.set(r,n),n}createCostAllocation(e,a){let r=`cost-${Date.now()}-${this.counter++}`,n={id:r,tagKey:e,allocations:a};return this.allocations.set(r,n),n}createResourceGroup(e,a,r){let n=`group-${Date.now()}-${this.counter++}`,i={id:n,name:e,query:{resourceTypeFilters:a,tagFilters:r}};return this.groups.set(n,i),i}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var Sf=new Tl;export{Wa,oe,Ga,Yl,Mu,ui,Uu,Bu,Ds,Fu,ju,Vu,zu,qu,Hu,Wu,Ka,Ja,ks,xs,ho,Je,A,_s,Xa,V,wr,C,Zl,pi,$s,Os,U,yo,Gu,Ku,Ju,Xu,l,s,Qu,Yu,E,Ls,Ms,Us,Zu,ep,Pe,Bs,So,ed,tp,rp,Le,vt,Xe,Se,B,S,_,Qe,D,td,Tt,pe,Mt,np,rd,be,bo,Me,Ut,mi,ve,vo,Ne,nd,gi,Te,Ee,ee,fi,G,Bt,Et,we,t,To,ip,Qa,Fs,op,sp,ap,cp,js,lp,dp,up,pp,mp,gp,fp,hp,yp,Sp,bp,vp,id,od,sd,ad,cd,ld,dd,Ft,Ya,Za,Cr,hi,Tp,ec,Ep,wp,rn,Cp,Ap,Ip,Rp,Pp,Np,ud,pd,md,gd,fd,Eo,Dp,Vs,hd,yd,Sd,tc,Ce,kp,bd,wt,wo,Ar,vd,rc,Td,Ed,wd,nc,De,xp,_p,$p,Op,Cd,Lp,Ae,Mp,Up,Bp,ic,oc,Fp,sc,ac,jp,Vp,zp,qp,Hp,Ad,zs,Wp,Gp,Kp,Jp,Xp,Id,Rd,Qp,Yp,Zp,em,tm,rm,nm,im,om,cc,qs,sm,am,cm,lm,lc,dc,uc,dm,pc,um,pm,mm,gm,mc,fm,hm,ym,Sm,bm,vm,Tm,Em,Pd,Nd,Dd,kd,gc,wm,Cm,Am,Im,Rm,Pm,Nm,Dm,km,xd,_d,$d,Od,xm,_m,fc,$m,hc,yc,Sc,bc,Om,Lm,Mm,Um,Ye,yi,Bm,Fm,jm,Vm,zm,qm,Hm,Wm,Ld,Gm,Km,vc,Tc,Jm,Xm,Md,Qm,Ym,Zm,eg,tg,rg,ng,ig,og,sg,ag,cg,lg,dg,ug,pg,mg,gg,fg,hg,yg,Ec,Sg,wc,bg,Cc,vg,Ac,Tg,Ic,Eg,nn,wg,Rc,Cg,Co,Ag,Pc,Ig,Nc,Rg,Dc,Pg,kc,Ng,xc,Dg,on,kg,_c,xg,$c,_g,Oc,$g,Lc,Og,Mc,Lg,Uc,Mg,Bc,Ug,Fc,Bg,jc,Fg,Vc,jg,zc,Vg,qc,zg,Hc,qg,Wc,Hg,Gc,Wg,Kc,Gg,Jc,Kg,Xc,Jg,Qc,Xg,Yc,Qg,Zc,Yg,el,Zg,tl,ef,rl,tf,nl,rf,Ud,Bd,Fd,jd,il,nf,ol,of,sl,sf,al,af,Si,Vd,zd,Ao,Hs,sn,qd,Io,jt,Ws,Gs,Hd,Wd,cl,Gd,Ks,ll,cf,lf,Js,Xs,Qs,dl,Ro,ul,pl,Ys,ml,gl,fl,Kd,Jd,Xd,df,Qd,Yd,uf,Zd,hl,eu,tu,ru,pf,nu,bi,Zs,iu,mf,ou,Po,No,ea,yl,gf,Sl,ff,bl,hf,vl,yf,Tl,Sf};
|
|
7364
|
+
`}function zi(){return ja(Hi(qi(import.meta.url)),"runtime-assets")}function bi(){let e=zi(),a=(r)=>Ki(ja(e,r),"utf-8");return[{path:"bootstrap",contents:a("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:a("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:a("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:a("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:a("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:nu(),mode:420}]}function Zs(e={}){let a=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:a,CACHE_DRIVER:a,SESSION_DRIVER:a,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 iu=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];function*qa(e){for(let a of Zi(e)){let r=Re(e,a);if(Ha(r).isDirectory())yield*qa(r);else yield r}}function mf(e={}){let a=e.architecture??"x86_64",r=e.platform??(a==="arm64"?"linux/arm64":"linux/amd64"),n=e.onStep??(()=>{}),i=Yi(Re(as(),"tscloud-php-layer-")),o="tscloud-php-layer:build";try{ts(Re(i,"Dockerfile"),Gd(e)),n("Building PHP runtime image (docker)"),it("docker",["build","--platform",r,"-t","tscloud-php-layer:build",i],{stdio:"inherit"}),n("Extracting /opt/php from image");let c=it("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Re(i,"opt");Ji(u,{recursive:!0});try{it("docker",["cp",`${c}:/opt/php`,Re(u,"php")],{stdio:"inherit"})}finally{it("docker",["rm",c],{stdio:"ignore"})}if(!Qi(Re(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let g of qa(u)){let h=rs(u,g).replace(/\\/g,"/"),y=Ha(g).mode&73?493:420;d.push({name:h,data:Xi(g),mode:y})}n("Injecting runtime assets");let m=new Set(bi().map((g)=>g.path)),p=d.filter((g)=>!m.has(g.name));for(let g of bi())p.push({name:g.path,data:g.contents,mode:g.mode});return n("Packaging layer ZIP"),{zip:Si(p),architecture:a,fileCount:p.length}}finally{es(i,{recursive:!0,force:!0})}}var ou=[".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 ls(e,a){return a.some((r)=>e===r||e.startsWith(`${r}/`))}function*tr(e,a,r){for(let n of ss(e)){let i=cs(e,n),o=er(a,i).replace(/\\/g,"/");if(ls(o,r))continue;if(za(i).isDirectory())yield*tr(i,a,r);else yield i}}function Po(e){if(e.skipBuild)return;let a=ia(e.projectRoot??process.cwd()),r=e.app.build??iu;for(let n of r)e.onStep?.(`build: ${n}`),ns(n,{stdio:"inherit",cwd:a})}function No(e,a=[]){let r=ia(e),n=[...ou,ho(),...a],i=[];for(let o of tr(r,r,n)){let c=er(r,o).replace(/\\/g,"/"),u=(za(o).mode&73)!==0;i.push({name:c,data:os(o),mode:u?493:420})}return i}function ea(e){let a=ia(e.projectRoot??process.cwd());Po(e),e.onStep?.("packaging application tree");let r=No(a,e.exclude);if(!r.length)throw Error(`No files to package under ${a}`);let n=Si(r),i=e.app.handlers?.http??"public/index.php";return{zip:n,sha256:is("sha256").update(n).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:r.length}}class yl{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let a=`asset-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.optimizations.set(a,r),r}createImageOptimization(e){let a=`image-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.imageConfigs.set(a,r),r}createSSGConfig(e){let a=`ssg-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.ssgConfigs.set(a,r),r}createPrerenderConfig(e){let a=`prerender-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.prerenderConfigs.set(a,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 gf=new yl;class Sl{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,a){let r=`lifecycle-${Date.now()}-${this.counter++}`,n={id:r,transitions:e,expiration:a};return this.policies.set(r,n),n}enableVersioning(e=!1){let a=`versioning-${Date.now()}-${this.counter++}`,r={id:a,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(a,r),r}createReplicationRule(e,a,r){let n=`replication-${Date.now()}-${this.counter++}`,i={id:n,sourceRegion:e,destRegion:a,destBucket:r};return this.replicationRules.set(n,i),i}createIntelligentTiering(e,a){let r=`tiering-${Date.now()}-${this.counter++}`,n={id:r,archiveDays:e,deepArchiveDays:a};return this.tieringConfigs.set(r,n),n}enableObjectLock(e){let a=`object-lock-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(a,r),r}enableTransferAcceleration(e){let a=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(a,r),r}createAccessPoint(e){let a=`access-point-${Date.now()}-${this.counter++}`,r={id:a,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(a,r),r}createGlacierArchive(e){let a=`glacier-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createInventory(e){let a=`inventory-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createBatchOperation(e){let a=`batch-op-${Date.now()}-${this.counter++}`,r={id:a,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(a,r),r}executeBatchOperation(e){let a=this.batchOps.get(e);if(!a)throw Error(`Batch operation not found: ${e}`);return a.status="in_progress",a.totalObjects=1000,a.processedObjects=0,a}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSQSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSNSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}generateObjectLockCF(e){let a={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)a.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)a.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return a}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 a=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",n={Event:e.events[0],[r]:e.destination.arn};if(e.filter)n.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[a]:[n]}}}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 ff=new Sl;class bl{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,a=30,r=10){let n=`health-${Date.now()}-${this.counter++}`,i={id:n,url:e,interval:a,timeout:r,status:"healthy"};return this.checks.set(n,i),i}createSyntheticMonitor(e,a,r,n){let i=`synthetic-${Date.now()}-${this.counter++}`,o={id:i,name:e,script:a,frequency:r,locations:n};return this.synthetics.set(i,o),o}trackUptime(e,a,r){let n=`uptime-${Date.now()}-${this.counter++}`,i=a/(a+r)*100,o={id:n,resource:e,uptime:a,downtime:r,availability:i};return this.uptimeTrackers.set(n,o),o}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var hf=new bl;class vl{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,a,r,n){let i=`waf-${Date.now()}-${this.counter++}`,o={id:i,name:e,priority:a,action:r,conditions:n};return this.wafRules.set(i,o),o}enableShield(e,a="standard"){let r=`shield-${Date.now()}-${this.counter++}`,n={id:r,resourceArn:e,protectionType:a};return this.shieldProtections.set(r,n),n}createSecurityGroup(e,a,r){let n=`sg-${Date.now()}-${this.counter++}`,i={id:n,name:e,vpcId:a,rules:r};return this.securityGroups.set(n,i),i}createNACL(e,a){let r=`nacl-${Date.now()}-${this.counter++}`,n={id:r,vpcId:e,rules:a};return this.nacls.set(r,n),n}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var yf=new vl;class Tl{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,a){let r=`tagging-${Date.now()}-${this.counter++}`,n={id:r,tags:e,resources:a};return this.strategies.set(r,n),n}createCostAllocation(e,a){let r=`cost-${Date.now()}-${this.counter++}`,n={id:r,tagKey:e,allocations:a};return this.allocations.set(r,n),n}createResourceGroup(e,a,r){let n=`group-${Date.now()}-${this.counter++}`,i={id:n,name:e,query:{resourceTypeFilters:a,tagFilters:r}};return this.groups.set(n,i),i}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var Sf=new Tl;export{Wa,oe,Ga,Yl,Mu,ui,Uu,Bu,Ds,Fu,ju,Vu,zu,qu,Hu,Wu,Ka,Ja,ks,xs,ho,Qe,A,_s,Xa,V,wr,C,Zl,pi,$s,Os,U,yo,Gu,Ku,Ju,Xu,l,s,Qu,Yu,E,Ls,Ms,Us,Zu,ep,Pe,Bs,So,ed,tp,rp,Le,vt,Ye,Se,B,S,_,Ze,D,td,Tt,pe,Ut,np,rd,be,bo,Me,Bt,mi,ve,vo,Ne,nd,gi,Te,Ee,ee,fi,G,Ft,Et,we,t,To,ip,Qa,Fs,op,sp,ap,cp,js,lp,dp,up,pp,mp,gp,fp,hp,yp,Sp,bp,vp,id,od,sd,ad,cd,ld,dd,jt,Ya,Za,Cr,hi,Tp,ec,Ep,wp,rn,Cp,Ap,Ip,Rp,Pp,Np,ud,pd,md,gd,fd,Eo,Dp,Vs,hd,yd,Sd,tc,Ce,kp,bd,wt,wo,Ar,vd,rc,Td,Ed,wd,nc,De,xp,_p,$p,Op,Cd,Lp,Ae,Mp,Up,Bp,ic,oc,Fp,sc,ac,jp,Vp,zp,qp,Hp,Ad,zs,Wp,Gp,Kp,Jp,Xp,Id,Rd,Qp,Yp,Zp,em,tm,rm,nm,im,om,cc,qs,sm,am,cm,lm,lc,dc,uc,dm,pc,um,pm,mm,gm,mc,fm,hm,ym,Sm,bm,vm,Tm,Em,Pd,Nd,Dd,kd,gc,wm,Cm,Am,Im,Rm,Pm,Nm,Dm,km,xd,_d,$d,Od,xm,_m,fc,$m,hc,yc,Sc,bc,Om,Lm,Mm,Um,et,yi,Bm,Fm,jm,Vm,zm,qm,Hm,Wm,Ld,Gm,Km,vc,Tc,Jm,Xm,Md,Qm,Ym,Zm,eg,tg,rg,ng,ig,og,sg,ag,cg,lg,dg,ug,pg,mg,gg,fg,hg,yg,Ec,Sg,wc,bg,Cc,vg,Ac,Tg,Ic,Eg,nn,wg,Rc,Cg,Co,Ag,Pc,Ig,Nc,Rg,Dc,Pg,kc,Ng,xc,Dg,on,kg,_c,xg,$c,_g,Oc,$g,Lc,Og,Mc,Lg,Uc,Mg,Bc,Ug,Fc,Bg,jc,Fg,Vc,jg,zc,Vg,qc,zg,Hc,qg,Wc,Hg,Gc,Wg,Kc,Gg,Jc,Kg,Xc,Jg,Qc,Xg,Yc,Qg,Zc,Yg,el,Zg,tl,ef,rl,tf,nl,rf,Ud,Bd,Fd,jd,il,nf,ol,of,sl,sf,al,af,Si,Vd,zd,Ao,Hs,sn,qd,Io,Vt,Ws,Gs,Hd,Wd,cl,Gd,Ks,ll,cf,lf,Js,Xs,Qs,dl,Ro,ul,pl,Ys,ml,gl,fl,Kd,Jd,Xd,df,Qd,Yd,uf,Zd,hl,eu,tu,ru,pf,nu,bi,Zs,iu,mf,ou,Po,No,ea,yl,gf,Sl,ff,bl,hf,vl,yf,Tl,Sf};
|