From 6da0a4ad82359be595734ffc8b81bd6699119947 Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 12:35:57 +0100
Subject: [PATCH 01/49] feat(dx): add Astro website with i18n landing page
Introduce the envilder marketing/docs website built with Astro. Includes landing page components (hero, features, providers, docs, changelog, roadmap), theme switcher, and full i18n support for English, Catalan, and Spanish. Registers the website package in the pnpm workspace and updates .gitignore for Astro artifacts.
---
.gitignore | 8 +
pnpm-lock.yaml | 2685 ++++++++++++++++-
pnpm-workspace.yaml | 1 +
src/apps/website/astro.config.mjs | 18 +
src/apps/website/package.json | 16 +
src/apps/website/public/AWS.svg | 4 +
src/apps/website/public/Azure.svg | 1 +
src/apps/website/public/GitHubActions.svg | 1 +
src/apps/website/public/NPM.svg | 1 +
src/apps/website/public/favicon.svg | 6 +
.../website/src/components/Changelog.astro | 139 +
.../website/src/components/CodeBlock.astro | 61 +
.../website/src/components/DemoVideo.astro | 109 +
.../website/src/components/DocsContent.astro | 930 ++++++
.../website/src/components/FeaturesGrid.astro | 47 +
src/apps/website/src/components/Footer.astro | 260 ++
.../website/src/components/GetStarted.astro | 228 ++
.../website/src/components/GitHubAction.astro | 182 ++
src/apps/website/src/components/Hero.astro | 209 ++
.../website/src/components/HowItWorks.astro | 187 ++
src/apps/website/src/components/Navbar.astro | 222 ++
.../src/components/ProblemSolution.astro | 103 +
.../website/src/components/Providers.astro | 234 ++
src/apps/website/src/components/Roadmap.astro | 144 +
.../src/components/TerminalMockup.astro | 115 +
.../src/components/ThemeSwitcher.astro | 109 +
.../website/src/components/TrustBadges.astro | 117 +
src/apps/website/src/i18n/ca.ts | 567 ++++
src/apps/website/src/i18n/en.ts | 558 ++++
src/apps/website/src/i18n/es.ts | 567 ++++
src/apps/website/src/i18n/types.ts | 402 +++
src/apps/website/src/i18n/utils.ts | 26 +
src/apps/website/src/layouts/BaseLayout.astro | 68 +
src/apps/website/src/pages/ca/changelog.astro | 95 +
src/apps/website/src/pages/ca/docs.astro | 17 +
src/apps/website/src/pages/ca/index.astro | 36 +
src/apps/website/src/pages/changelog.astro | 180 ++
src/apps/website/src/pages/docs.astro | 17 +
src/apps/website/src/pages/es/changelog.astro | 95 +
src/apps/website/src/pages/es/docs.astro | 17 +
src/apps/website/src/pages/es/index.astro | 36 +
src/apps/website/src/pages/index.astro | 36 +
src/apps/website/src/styles/global.css | 452 +++
src/apps/website/tsconfig.json | 3 +
44 files changed, 9305 insertions(+), 4 deletions(-)
create mode 100644 src/apps/website/astro.config.mjs
create mode 100644 src/apps/website/package.json
create mode 100644 src/apps/website/public/AWS.svg
create mode 100644 src/apps/website/public/Azure.svg
create mode 100644 src/apps/website/public/GitHubActions.svg
create mode 100644 src/apps/website/public/NPM.svg
create mode 100644 src/apps/website/public/favicon.svg
create mode 100644 src/apps/website/src/components/Changelog.astro
create mode 100644 src/apps/website/src/components/CodeBlock.astro
create mode 100644 src/apps/website/src/components/DemoVideo.astro
create mode 100644 src/apps/website/src/components/DocsContent.astro
create mode 100644 src/apps/website/src/components/FeaturesGrid.astro
create mode 100644 src/apps/website/src/components/Footer.astro
create mode 100644 src/apps/website/src/components/GetStarted.astro
create mode 100644 src/apps/website/src/components/GitHubAction.astro
create mode 100644 src/apps/website/src/components/Hero.astro
create mode 100644 src/apps/website/src/components/HowItWorks.astro
create mode 100644 src/apps/website/src/components/Navbar.astro
create mode 100644 src/apps/website/src/components/ProblemSolution.astro
create mode 100644 src/apps/website/src/components/Providers.astro
create mode 100644 src/apps/website/src/components/Roadmap.astro
create mode 100644 src/apps/website/src/components/TerminalMockup.astro
create mode 100644 src/apps/website/src/components/ThemeSwitcher.astro
create mode 100644 src/apps/website/src/components/TrustBadges.astro
create mode 100644 src/apps/website/src/i18n/ca.ts
create mode 100644 src/apps/website/src/i18n/en.ts
create mode 100644 src/apps/website/src/i18n/es.ts
create mode 100644 src/apps/website/src/i18n/types.ts
create mode 100644 src/apps/website/src/i18n/utils.ts
create mode 100644 src/apps/website/src/layouts/BaseLayout.astro
create mode 100644 src/apps/website/src/pages/ca/changelog.astro
create mode 100644 src/apps/website/src/pages/ca/docs.astro
create mode 100644 src/apps/website/src/pages/ca/index.astro
create mode 100644 src/apps/website/src/pages/changelog.astro
create mode 100644 src/apps/website/src/pages/docs.astro
create mode 100644 src/apps/website/src/pages/es/changelog.astro
create mode 100644 src/apps/website/src/pages/es/docs.astro
create mode 100644 src/apps/website/src/pages/es/index.astro
create mode 100644 src/apps/website/src/pages/index.astro
create mode 100644 src/apps/website/src/styles/global.css
create mode 100644 src/apps/website/tsconfig.json
diff --git a/.gitignore b/.gitignore
index 4699b1db..10de286c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -379,3 +379,11 @@ deactivate/
# Rider
.idea/
+
+# Playwright test results
+.playwright-mcp/
+
+dist/
+
+# Astro
+.astro/
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index aa1c35fa..c2dfd091 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -91,8 +91,37 @@ importers:
specifier: ^4.0.18
version: 4.0.18(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)
+ src/apps/website:
+ dependencies:
+ '@astrojs/sitemap':
+ specifier: ^3.3.1
+ version: 3.7.2
+ astro:
+ specifier: ^5.8.0
+ version: 5.18.1(@azure/identity@4.13.0)(@azure/keyvault-secrets@4.10.0(@azure/core-client@1.10.1))(@types/node@25.3.3)(jiti@2.6.1)(rollup@4.59.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)
+
packages:
+ '@astrojs/compiler@2.13.1':
+ resolution: {integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==}
+
+ '@astrojs/internal-helpers@0.7.6':
+ resolution: {integrity: sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==}
+
+ '@astrojs/markdown-remark@6.3.11':
+ resolution: {integrity: sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==}
+
+ '@astrojs/prism@3.3.0':
+ resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==}
+ engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
+
+ '@astrojs/sitemap@3.7.2':
+ resolution: {integrity: sha512-PqkzkcZTb5ICiyIR8VoKbIAP/laNRXi5tw616N1Ckk+40oNB8Can1AzVV56lrbC5GKSZFCyJYUVYqVivMisvpA==}
+
+ '@astrojs/telemetry@3.3.0':
+ resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==}
+ engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
+
'@aws-crypto/sha256-browser@5.2.0':
resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==}
@@ -345,24 +374,28 @@ packages:
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@biomejs/cli-linux-arm64@2.4.5':
resolution: {integrity: sha512-U1GAG6FTjhAO04MyH4xn23wRNBkT6H7NentHh+8UxD6ShXKBm5SY4RedKJzkUThANxb9rUKIPc7B8ew9Xo/cWg==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@biomejs/cli-linux-x64-musl@2.4.5':
resolution: {integrity: sha512-NlKa7GpbQmNhZf9kakQeddqZyT7itN7jjWdakELeXyTU3pg/83fTysRRDPJD0akTfKDl6vZYNT9Zqn4MYZVBOA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@biomejs/cli-linux-x64@2.4.5':
resolution: {integrity: sha512-NdODlSugMzTlENPTa4z0xB82dTUlCpsrOxc43///aNkTLblIYH4XpYflBbf5ySlQuP8AA4AZd1qXhV07IdrHdQ==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@biomejs/cli-win32-arm64@2.4.5':
resolution: {integrity: sha512-EBfrTqRIWOFSd7CQb/0ttjHMR88zm3hGravnDwUA9wHAaCAYsULKDebWcN5RmrEo1KBtl/gDVJMrFjNR0pdGUw==}
@@ -376,6 +409,10 @@ packages:
cpu: [x64]
os: [win32]
+ '@capsizecss/unpack@4.0.0':
+ resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==}
+ engines: {node: '>=18'}
+
'@commitlint/cli@20.4.3':
resolution: {integrity: sha512-Z37EMoDT7+Upg500vlr/vZrgRsb6Xc5JAA3Tv7BYbobnN/ZpqUeZnSLggBg2+1O+NptRDtyujr2DD1CPV2qwhA==}
engines: {node: '>=v18'}
@@ -449,156 +486,315 @@ packages:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
+ '@emnapi/runtime@1.9.1':
+ resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==}
+
+ '@esbuild/aix-ppc64@0.25.12':
+ resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/aix-ppc64@0.27.3':
resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
+ '@esbuild/android-arm64@0.25.12':
+ resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm64@0.27.3':
resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm@0.25.12':
+ resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-arm@0.27.3':
resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
+ '@esbuild/android-x64@0.25.12':
+ resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/android-x64@0.27.3':
resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
+ '@esbuild/darwin-arm64@0.25.12':
+ resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-arm64@0.27.3':
resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-x64@0.25.12':
+ resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.27.3':
resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
+ '@esbuild/freebsd-arm64@0.25.12':
+ resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-arm64@0.27.3':
resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.25.12':
+ resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.27.3':
resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
+ '@esbuild/linux-arm64@0.25.12':
+ resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm64@0.27.3':
resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm@0.25.12':
+ resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-arm@0.27.3':
resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
+ '@esbuild/linux-ia32@0.25.12':
+ resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-ia32@0.27.3':
resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-loong64@0.25.12':
+ resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-loong64@0.27.3':
resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-mips64el@0.25.12':
+ resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.27.3':
resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-ppc64@0.25.12':
+ resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.27.3':
resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-riscv64@0.25.12':
+ resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.27.3':
resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-s390x@0.25.12':
+ resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-s390x@0.27.3':
resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-x64@0.25.12':
+ resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/linux-x64@0.27.3':
resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
+ '@esbuild/netbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
'@esbuild/netbsd-arm64@0.27.3':
resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.25.12':
+ resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
'@esbuild/netbsd-x64@0.27.3':
resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
+ '@esbuild/openbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-arm64@0.27.3':
resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.25.12':
+ resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.27.3':
resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
+ '@esbuild/openharmony-arm64@0.25.12':
+ resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
'@esbuild/openharmony-arm64@0.27.3':
resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
+ '@esbuild/sunos-x64@0.25.12':
+ resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/sunos-x64@0.27.3':
resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
+ '@esbuild/win32-arm64@0.25.12':
+ resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-arm64@0.27.3':
resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-ia32@0.25.12':
+ resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-ia32@0.27.3':
resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-x64@0.25.12':
+ resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@esbuild/win32-x64@0.27.3':
resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
engines: {node: '>=18'}
@@ -619,6 +815,159 @@ packages:
engines: {node: '>=6'}
hasBin: true
+ '@img/colour@1.1.0':
+ resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
+ engines: {node: '>=18'}
+
+ '@img/sharp-darwin-arm64@0.34.5':
+ resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-darwin-x64@0.34.5':
+ resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-arm64@1.2.4':
+ resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-x64@1.2.4':
+ resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-linux-arm64@1.2.4':
+ resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-arm@1.2.4':
+ resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-ppc64@1.2.4':
+ resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-riscv64@1.2.4':
+ resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-s390x@1.2.4':
+ resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linux-x64@1.2.4':
+ resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
+ resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.4':
+ resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-linux-arm64@0.34.5':
+ resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-arm@0.34.5':
+ resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-ppc64@0.34.5':
+ resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-riscv64@0.34.5':
+ resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-s390x@0.34.5':
+ resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linux-x64@0.34.5':
+ resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@img/sharp-linuxmusl-arm64@0.34.5':
+ resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-linuxmusl-x64@0.34.5':
+ resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@img/sharp-wasm32@0.34.5':
+ resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [wasm32]
+
+ '@img/sharp-win32-arm64@0.34.5':
+ resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@img/sharp-win32-ia32@0.34.5':
+ resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@img/sharp-win32-x64@0.34.5':
+ resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [win32]
+
'@inversifyjs/common@1.5.2':
resolution: {integrity: sha512-WlzR9xGadABS9gtgZQ+luoZ8V6qm4Ii6RQfcfC9Ho2SOlE6ZuemFo7PKJvKI0ikm8cmKbU8hw5UK6E4qovH21w==}
@@ -676,6 +1025,9 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@oslojs/encoding@1.1.0':
+ resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
+
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -710,6 +1062,15 @@ packages:
'@protobufjs/utf8@1.1.0':
resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
+ '@rollup/pluginutils@5.3.0':
+ resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
'@rollup/rollup-android-arm-eabi@4.59.0':
resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==}
cpu: [arm]
@@ -744,66 +1105,79 @@ packages:
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.59.0':
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.59.0':
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.59.0':
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
cpu: [loong64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.59.0':
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
cpu: [loong64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.59.0':
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
cpu: [ppc64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.59.0':
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.59.0':
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.59.0':
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.59.0':
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-openbsd-x64@4.59.0':
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
@@ -873,6 +1247,27 @@ packages:
resolution: {integrity: sha512-6PU7JLivE6Swavrw1TxiPVbvk1Nafihm+v6hNpsEAt7raLlazoFXFK/O8YeSEK15u+4oofSBqwipy81HAbLnlg==}
engines: {node: '>=20.0.0'}
+ '@shikijs/core@3.23.0':
+ resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==}
+
+ '@shikijs/engine-javascript@3.23.0':
+ resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==}
+
+ '@shikijs/engine-oniguruma@3.23.0':
+ resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==}
+
+ '@shikijs/langs@3.23.0':
+ resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==}
+
+ '@shikijs/themes@3.23.0':
+ resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==}
+
+ '@shikijs/types@3.23.0':
+ resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==}
+
+ '@shikijs/vscode-textmate@10.0.2':
+ resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
+
'@simple-libs/stream-utils@1.2.0':
resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==}
engines: {node: '>=18'}
@@ -1093,6 +1488,9 @@ packages:
'@types/chai@5.2.3':
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
+ '@types/debug@4.1.13':
+ resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==}
+
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
@@ -1105,15 +1503,33 @@ packages:
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+ '@types/hast@3.0.4':
+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+
+ '@types/mdast@4.0.4':
+ resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
+
+ '@types/ms@2.1.0':
+ resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
+
+ '@types/nlcst@2.0.3':
+ resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==}
+
'@types/node@18.19.130':
resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==}
+ '@types/node@24.12.0':
+ resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==}
+
'@types/node@25.3.3':
resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==}
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
+ '@types/sax@1.2.7':
+ resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
+
'@types/ssh2-streams@0.1.13':
resolution: {integrity: sha512-faHyY3brO9oLEA0QlcO8N2wT7R0+1sHWZvQ+y3rMLwdY1ZyS1z0W3t65j9PqT4HmQ6ALzNe7RZlNuCNE0wBSWA==}
@@ -1123,10 +1539,16 @@ packages:
'@types/ssh2@1.15.5':
resolution: {integrity: sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ==}
+ '@types/unist@3.0.3':
+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+
'@typespec/ts-http-runtime@0.3.3':
resolution: {integrity: sha512-91fp6CAAJSRtH5ja95T1FHSKa8aPW9/Zw6cta81jlZTUw/+Vq8jM/AfF/14h2b71wwR84JUTW/3Y8QPhDAawFA==}
engines: {node: '>=20.0.0'}
+ '@ungap/structured-clone@1.3.0':
+ resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+
'@vercel/ncc@0.38.4':
resolution: {integrity: sha512-8LwjnlP39s08C08J5NstzriPvW1SP8Zfpp1BvC2sI35kPeZnHfxVkCwu4/+Wodgnd60UtT1n8K8zw+Mp7J9JmQ==}
hasBin: true
@@ -1189,6 +1611,9 @@ packages:
ajv@8.18.0:
resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==}
+ ansi-align@3.0.1:
+ resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
+
ansi-escapes@7.3.0:
resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==}
engines: {node: '>=18'}
@@ -1209,6 +1634,10 @@ packages:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
archiver-utils@5.0.2:
resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==}
engines: {node: '>= 14'}
@@ -1220,12 +1649,22 @@ packages:
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+ arg@5.0.2:
+ resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
array-ify@1.0.0:
resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
+ array-iterate@2.0.1:
+ resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==}
+
asn1@0.2.6:
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
@@ -1240,12 +1679,21 @@ packages:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
+ astro@5.18.1:
+ resolution: {integrity: sha512-m4VWilWZ+Xt6NPoYzC4CgGZim/zQUO7WFL0RHCH0AiEavF1153iC3+me2atDvXpf/yX4PyGUeD8wZLq1cirT3g==}
+ engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'}
+ hasBin: true
+
async-lock@1.4.1:
resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==}
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+ axobject-query@4.1.0:
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+ engines: {node: '>= 0.4'}
+
b4a@1.8.0:
resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==}
peerDependencies:
@@ -1254,6 +1702,9 @@ packages:
react-native-b4a:
optional: true
+ bail@2.0.2:
+ resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
+
balanced-match@4.0.4:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
@@ -1296,6 +1747,9 @@ packages:
bare-url@2.3.2:
resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==}
+ base-64@1.0.0:
+ resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
+
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -1309,12 +1763,19 @@ packages:
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+ boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
boundary@2.0.0:
resolution: {integrity: sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==}
bowser@2.14.1:
resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==}
+ boxen@8.0.1:
+ resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==}
+ engines: {node: '>=18'}
+
brace-expansion@5.0.4:
resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==}
engines: {node: 18 || 20 || >=22}
@@ -1352,6 +1813,13 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
+ camelcase@8.0.0:
+ resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==}
+ engines: {node: '>=16'}
+
+ ccount@2.0.1:
+ resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+
chai@6.2.2:
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
@@ -1364,13 +1832,38 @@ packages:
resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ character-entities-html4@2.1.0:
+ resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
+
+ character-entities-legacy@3.0.0:
+ resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
+
+ character-entities@2.0.2:
+ resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
+
+ chokidar@5.0.0:
+ resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
+ engines: {node: '>= 20.19.0'}
+
chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+ ci-info@4.4.0:
+ resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==}
+ engines: {node: '>=8'}
+
+ cli-boxes@3.0.0:
+ resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
+ engines: {node: '>=10'}
+
cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -1378,10 +1871,20 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ comma-separated-tokens@2.0.3:
+ resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
+
+ commander@11.1.0:
+ resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
+ engines: {node: '>=16'}
+
commander@14.0.3:
resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
engines: {node: '>=20'}
+ common-ancestor-path@1.0.1:
+ resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==}
+
compare-func@2.0.0:
resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
@@ -1402,6 +1905,13 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ cookie-es@1.2.2:
+ resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
+
+ cookie@1.1.1:
+ resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
+ engines: {node: '>=18'}
+
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@@ -1442,6 +1952,33 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ crossws@0.3.5:
+ resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
+
+ css-select@5.2.2:
+ resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
+
+ css-tree@2.2.1:
+ resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
+ css-tree@3.2.1:
+ resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+ css-what@6.2.2:
+ resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
+ engines: {node: '>= 6'}
+
+ cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ csso@5.0.5:
+ resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
dargs@8.1.0:
resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==}
engines: {node: '>=12'}
@@ -1455,6 +1992,9 @@ packages:
supports-color:
optional: true
+ decode-named-character-reference@1.3.0:
+ resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
+
default-browser-id@5.0.1:
resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==}
engines: {node: '>=18'}
@@ -1467,10 +2007,41 @@ packages:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
- diff@4.0.4:
- resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
+ defu@6.1.4:
+ resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
+
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
+ destr@2.0.5:
+ resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ deterministic-object-hash@2.0.2:
+ resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==}
+ engines: {node: '>=18'}
+
+ devalue@5.6.4:
+ resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==}
+
+ devlop@1.1.0:
+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+
+ diff@4.0.4:
+ resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
engines: {node: '>=0.3.1'}
+ diff@8.0.4:
+ resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
+ engines: {node: '>=0.3.1'}
+
+ dlv@1.1.3:
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+
docker-compose@1.3.1:
resolution: {integrity: sha512-rF0wH69G3CCcmkN9J1RVMQBaKe8o77LT/3XmqcLIltWWVxcWAzp2TnO7wS3n/umZHN3/EVrlT3exSBMal+Ou1w==}
engines: {node: '>= 6.0.0'}
@@ -1483,6 +2054,19 @@ packages:
resolution: {integrity: sha512-iND4mcOWhPaCNh54WmK/KoSb35AFqPAUWFMffTQcp52uQt36b5uNwEJTSXntJZBbeGad72Crbi/hvDIv6us/6Q==}
engines: {node: '>= 8.0'}
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
dot-prop@5.3.0:
resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
engines: {node: '>=8'}
@@ -1491,6 +2075,10 @@ packages:
resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==}
engines: {node: '>=12'}
+ dset@3.1.4:
+ resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
+ engines: {node: '>=4'}
+
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -1501,6 +2089,9 @@ packages:
resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==}
engines: {ecmascript: '>= es5', node: '>=4'}
+ emoji-regex@10.6.0:
+ resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
+
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1510,6 +2101,14 @@ packages:
end-of-stream@1.4.5:
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ entities@6.0.1:
+ resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
+ engines: {node: '>=0.12'}
+
env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
@@ -1524,6 +2123,11 @@ packages:
es-module-lexer@1.7.0:
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
+ esbuild@0.25.12:
+ resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
esbuild@0.27.3:
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
engines: {node: '>=18'}
@@ -1533,6 +2137,13 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
+ escape-string-regexp@5.0.0:
+ resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+ engines: {node: '>=12'}
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
@@ -1540,6 +2151,9 @@ packages:
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
engines: {node: '>=6'}
+ eventemitter3@5.0.4:
+ resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
+
events-universal@1.0.1:
resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==}
@@ -1551,6 +2165,9 @@ packages:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
+ extend@3.0.2:
+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -1587,6 +2204,17 @@ packages:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
+ flattie@1.1.1:
+ resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==}
+ engines: {node: '>=8'}
+
+ fontace@0.4.1:
+ resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==}
+
+ fontkitten@1.0.3:
+ resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==}
+ engines: {node: '>=20'}
+
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
@@ -1603,6 +2231,10 @@ packages:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
+ get-east-asian-width@1.5.0:
+ resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==}
+ engines: {node: '>=18'}
+
get-port@7.1.0:
resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==}
engines: {node: '>=16'}
@@ -1616,6 +2248,9 @@ packages:
deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.
hasBin: true
+ github-slugger@2.0.0:
+ resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
+
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -1640,10 +2275,43 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ h3@1.15.10:
+ resolution: {integrity: sha512-YzJeWSkDZxAhvmp8dexjRK5hxziRO7I9m0N53WhvYL5NiWfkUkzssVzY9jvGu0HBoLFW6+duYmNSn6MaZBCCtg==}
+
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
+ hast-util-from-html@2.0.3:
+ resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
+
+ hast-util-from-parse5@8.0.3:
+ resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
+
+ hast-util-is-element@3.0.0:
+ resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
+
+ hast-util-parse-selector@4.0.0:
+ resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
+
+ hast-util-raw@9.1.0:
+ resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==}
+
+ hast-util-to-html@9.0.5:
+ resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
+
+ hast-util-to-parse5@8.0.1:
+ resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==}
+
+ hast-util-to-text@4.0.2:
+ resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==}
+
+ hast-util-whitespace@3.0.0:
+ resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
+
+ hastscript@9.0.1:
+ resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
+
hosted-git-info@7.0.2:
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
engines: {node: ^16.14.0 || >=18.0.0}
@@ -1651,6 +2319,15 @@ packages:
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+ html-escaper@3.0.3:
+ resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
+
+ html-void-elements@3.0.0:
+ resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
+
+ http-cache-semantics@4.2.0:
+ resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
+
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
@@ -1687,6 +2364,9 @@ packages:
inversify@7.11.0:
resolution: {integrity: sha512-yZDprSSr8TyVeMGI/AOV4ws6gwjX22hj9Z8/oHAVpJORY6WRFTcUzhnZtibBUHEw2U8ArvHcR+i863DplQ3Cwg==}
+ iron-webcrypto@1.2.1:
+ resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
+
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
@@ -1792,6 +2472,10 @@ packages:
jws@4.0.1:
resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
+ kleur@3.0.3:
+ resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+ engines: {node: '>=6'}
+
lazystream@1.0.1:
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
engines: {node: '>= 0.6.3'}
@@ -1901,6 +2585,9 @@ packages:
long@5.3.2:
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
+ longest-streak@3.1.0:
+ resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
+
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
@@ -1908,6 +2595,10 @@ packages:
resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==}
engines: {node: 20 || >=22}
+ lru-cache@11.2.7:
+ resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==}
+ engines: {node: 20 || >=22}
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -1921,6 +2612,54 @@ packages:
make-error@1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+ markdown-table@3.0.4:
+ resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
+
+ mdast-util-definitions@6.0.0:
+ resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==}
+
+ mdast-util-find-and-replace@3.0.2:
+ resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==}
+
+ mdast-util-from-markdown@2.0.3:
+ resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==}
+
+ mdast-util-gfm-autolink-literal@2.0.1:
+ resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
+
+ mdast-util-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==}
+
+ mdast-util-gfm-strikethrough@2.0.0:
+ resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
+
+ mdast-util-gfm-table@2.0.0:
+ resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
+
+ mdast-util-gfm-task-list-item@2.0.0:
+ resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
+
+ mdast-util-gfm@3.1.0:
+ resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==}
+
+ mdast-util-phrasing@4.1.0:
+ resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
+
+ mdast-util-to-hast@13.2.1:
+ resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==}
+
+ mdast-util-to-markdown@2.1.2:
+ resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
+
+ mdast-util-to-string@4.0.0:
+ resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+
+ mdn-data@2.0.28:
+ resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
+
+ mdn-data@2.27.1:
+ resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
+
meow@12.1.1:
resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==}
engines: {node: '>=16.10'}
@@ -1933,6 +2672,90 @@ packages:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
+ micromark-core-commonmark@2.0.3:
+ resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
+
+ micromark-extension-gfm-autolink-literal@2.1.0:
+ resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==}
+
+ micromark-extension-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==}
+
+ micromark-extension-gfm-strikethrough@2.1.0:
+ resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==}
+
+ micromark-extension-gfm-table@2.1.1:
+ resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==}
+
+ micromark-extension-gfm-tagfilter@2.0.0:
+ resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
+
+ micromark-extension-gfm-task-list-item@2.1.0:
+ resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==}
+
+ micromark-extension-gfm@3.0.0:
+ resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
+
+ micromark-factory-destination@2.0.1:
+ resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
+
+ micromark-factory-label@2.0.1:
+ resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==}
+
+ micromark-factory-space@2.0.1:
+ resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==}
+
+ micromark-factory-title@2.0.1:
+ resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==}
+
+ micromark-factory-whitespace@2.0.1:
+ resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==}
+
+ micromark-util-character@2.1.1:
+ resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
+
+ micromark-util-chunked@2.0.1:
+ resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==}
+
+ micromark-util-classify-character@2.0.1:
+ resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==}
+
+ micromark-util-combine-extensions@2.0.1:
+ resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==}
+
+ micromark-util-decode-numeric-character-reference@2.0.2:
+ resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==}
+
+ micromark-util-decode-string@2.0.1:
+ resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==}
+
+ micromark-util-encode@2.0.1:
+ resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
+
+ micromark-util-html-tag-name@2.0.1:
+ resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==}
+
+ micromark-util-normalize-identifier@2.0.1:
+ resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==}
+
+ micromark-util-resolve-all@2.0.1:
+ resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==}
+
+ micromark-util-sanitize-uri@2.0.1:
+ resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
+
+ micromark-util-subtokenize@2.1.0:
+ resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==}
+
+ micromark-util-symbol@2.0.1:
+ resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
+
+ micromark-util-types@2.0.2:
+ resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
+
+ micromark@4.0.2:
+ resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
+
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
@@ -1956,6 +2779,10 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ mrmime@2.0.1:
+ resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+ engines: {node: '>=10'}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -1967,6 +2794,19 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ neotraverse@0.6.18:
+ resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==}
+ engines: {node: '>= 10'}
+
+ nlcst-to-string@4.0.0:
+ resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==}
+
+ node-fetch-native@1.6.7:
+ resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
+
+ node-mock-http@1.0.4:
+ resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==}
+
normalize-package-data@6.0.2:
resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==}
engines: {node: ^16.14.0 || >=18.0.0}
@@ -1975,23 +2815,53 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
obug@2.1.1:
resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
+ ofetch@1.5.1:
+ resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
+
+ ohash@2.0.11:
+ resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ oniguruma-parser@0.12.1:
+ resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==}
+
+ oniguruma-to-es@4.3.5:
+ resolution: {integrity: sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==}
+
open@10.2.0:
resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==}
engines: {node: '>=18'}
+ p-limit@6.2.0:
+ resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==}
+ engines: {node: '>=18'}
+
p-map@7.0.4:
resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==}
engines: {node: '>=18'}
+ p-queue@8.1.1:
+ resolution: {integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==}
+ engines: {node: '>=18'}
+
+ p-timeout@6.1.4:
+ resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==}
+ engines: {node: '>=14.16'}
+
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+ package-manager-detector@1.6.0:
+ resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
+
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@@ -2004,6 +2874,12 @@ packages:
resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==}
engines: {node: '>=18'}
+ parse-latin@7.0.0:
+ resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
+
+ parse5@7.3.0:
+ resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
+
path-expression-matcher@1.2.0:
resolution: {integrity: sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==}
engines: {node: '>=14.0.0'}
@@ -2027,6 +2903,9 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+ piccolore@0.1.3:
+ resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==}
+
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -2049,6 +2928,10 @@ packages:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
+ prismjs@1.30.0:
+ resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
+ engines: {node: '>=6'}
+
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
@@ -2056,6 +2939,10 @@ packages:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
+ prompts@2.4.2:
+ resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
+ engines: {node: '>= 6'}
+
proper-lockfile@4.1.2:
resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==}
@@ -2063,6 +2950,9 @@ packages:
resolution: {integrity: sha512-WPn+h9RGEExOKdu4bsF4HksG/uzd3cFq3MFtq8PsFeExPse5Ha/VOjQNyHhjboBFwGXGev6muJYTSPAOkROq2g==}
engines: {node: '>=18'}
+ property-information@7.1.0:
+ resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
+
protobufjs@7.5.4:
resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
engines: {node: '>=12.0.0'}
@@ -2073,6 +2963,9 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ radix3@1.1.2:
+ resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
+
rc-config-loader@4.1.4:
resolution: {integrity: sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==}
@@ -2094,9 +2987,50 @@ packages:
readdir-glob@1.1.3:
resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==}
+ readdirp@5.0.0:
+ resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
+ engines: {node: '>= 20.19.0'}
+
reflect-metadata@0.2.2:
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
+ regex-recursion@6.0.2:
+ resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
+
+ regex-utilities@2.3.0:
+ resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==}
+
+ regex@6.1.0:
+ resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==}
+
+ rehype-parse@9.0.1:
+ resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==}
+
+ rehype-raw@7.0.0:
+ resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
+
+ rehype-stringify@10.0.1:
+ resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==}
+
+ rehype@13.0.2:
+ resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==}
+
+ remark-gfm@4.0.1:
+ resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
+
+ remark-parse@11.0.0:
+ resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
+
+ remark-rehype@11.1.2:
+ resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
+
+ remark-smartypants@3.0.2:
+ resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==}
+ engines: {node: '>=16.0.0'}
+
+ remark-stringify@11.0.0:
+ resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
+
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
@@ -2116,6 +3050,18 @@ packages:
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ retext-latin@4.0.0:
+ resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==}
+
+ retext-smartypants@6.2.0:
+ resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==}
+
+ retext-stringify@4.0.0:
+ resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==}
+
+ retext@9.0.0:
+ resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==}
+
retry@0.12.0:
resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
engines: {node: '>= 4'}
@@ -2145,6 +3091,10 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ sax@1.6.0:
+ resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==}
+ engines: {node: '>=11.0.0'}
+
secretlint@11.3.1:
resolution: {integrity: sha512-CThioOhzkK/D7CdwYw2WgNaIAS4pTjUMb9aN296zNVxQV02aJIjzjfRS5Bih/auHXd0mHSfypGYLj5mmjUleNw==}
engines: {node: '>=20.0.0'}
@@ -2155,6 +3105,10 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ sharp@0.34.5:
+ resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -2163,6 +3117,9 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
+ shiki@3.23.0:
+ resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==}
+
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
@@ -2173,6 +3130,14 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
+ sisteransi@1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+
+ sitemap@9.0.1:
+ resolution: {integrity: sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==}
+ engines: {node: '>=20.19.5', npm: '>=10.8.2'}
+ hasBin: true
+
slash@5.1.0:
resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
engines: {node: '>=14.16'}
@@ -2181,10 +3146,17 @@ packages:
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
engines: {node: '>=10'}
+ smol-toml@1.6.1:
+ resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==}
+ engines: {node: '>= 18'}
+
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ space-separated-tokens@2.0.2:
+ resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
+
spdx-correct@3.2.0:
resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
@@ -2217,6 +3189,9 @@ packages:
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
+ stream-replace-string@2.0.0:
+ resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==}
+
streamx@2.23.0:
resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==}
@@ -2228,12 +3203,19 @@ packages:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
+ string-width@7.2.0:
+ resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
+ engines: {node: '>=18'}
+
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ stringify-entities@4.0.4:
+ resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
+
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
@@ -2256,6 +3238,11 @@ packages:
resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==}
engines: {node: '>=14.18'}
+ svgo@4.0.1:
+ resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==}
+ engines: {node: '>=16'}
+ hasBin: true
+
table@6.9.0:
resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==}
engines: {node: '>=10.0.0'}
@@ -2293,6 +3280,9 @@ packages:
resolution: {integrity: sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==}
engines: {node: '>=4'}
+ tiny-inflate@1.0.3:
+ resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
+
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
@@ -2316,6 +3306,12 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
+ trim-lines@3.0.1:
+ resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
+
+ trough@2.2.0:
+ resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
+
ts-node@10.9.2:
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
hasBin: true
@@ -2330,6 +3326,16 @@ packages:
'@swc/wasm':
optional: true
+ tsconfck@3.1.6:
+ resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
+ engines: {node: ^18 || >=20}
+ hasBin: true
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
@@ -2350,9 +3356,21 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ ufo@1.6.3:
+ resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
+
+ ultrahtml@1.6.0:
+ resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
+
+ uncrypto@0.1.3:
+ resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
+
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+ undici-types@7.16.0:
+ resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+
undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
@@ -2368,6 +3386,101 @@ packages:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
+ unified@11.0.5:
+ resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
+
+ unifont@0.7.4:
+ resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==}
+
+ unist-util-find-after@5.0.0:
+ resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
+
+ unist-util-is@6.0.1:
+ resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
+
+ unist-util-modify-children@4.0.0:
+ resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==}
+
+ unist-util-position@5.0.0:
+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+
+ unist-util-remove-position@5.0.0:
+ resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==}
+
+ unist-util-stringify-position@4.0.0:
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+
+ unist-util-visit-children@3.0.0:
+ resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==}
+
+ unist-util-visit-parents@6.0.2:
+ resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==}
+
+ unist-util-visit@5.1.0:
+ resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
+
+ unstorage@1.17.5:
+ resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==}
+ peerDependencies:
+ '@azure/app-configuration': ^1.8.0
+ '@azure/cosmos': ^4.2.0
+ '@azure/data-tables': ^13.3.0
+ '@azure/identity': ^4.6.0
+ '@azure/keyvault-secrets': ^4.9.0
+ '@azure/storage-blob': ^12.26.0
+ '@capacitor/preferences': ^6 || ^7 || ^8
+ '@deno/kv': '>=0.9.0'
+ '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
+ '@planetscale/database': ^1.19.0
+ '@upstash/redis': ^1.34.3
+ '@vercel/blob': '>=0.27.1'
+ '@vercel/functions': ^2.2.12 || ^3.0.0
+ '@vercel/kv': ^1 || ^2 || ^3
+ aws4fetch: ^1.0.20
+ db0: '>=0.2.1'
+ idb-keyval: ^6.2.1
+ ioredis: ^5.4.2
+ uploadthing: ^7.4.4
+ peerDependenciesMeta:
+ '@azure/app-configuration':
+ optional: true
+ '@azure/cosmos':
+ optional: true
+ '@azure/data-tables':
+ optional: true
+ '@azure/identity':
+ optional: true
+ '@azure/keyvault-secrets':
+ optional: true
+ '@azure/storage-blob':
+ optional: true
+ '@capacitor/preferences':
+ optional: true
+ '@deno/kv':
+ optional: true
+ '@netlify/blobs':
+ optional: true
+ '@planetscale/database':
+ optional: true
+ '@upstash/redis':
+ optional: true
+ '@vercel/blob':
+ optional: true
+ '@vercel/functions':
+ optional: true
+ '@vercel/kv':
+ optional: true
+ aws4fetch:
+ optional: true
+ db0:
+ optional: true
+ idb-keyval:
+ optional: true
+ ioredis:
+ optional: true
+ uploadthing:
+ optional: true
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -2389,6 +3502,55 @@ packages:
resolution: {integrity: sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==}
engines: {node: '>=4'}
+ vfile-location@5.0.3:
+ resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
+
+ vfile-message@4.0.3:
+ resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==}
+
+ vfile@6.0.3:
+ resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
+
+ vite@6.4.1:
+ resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: '>=1.21.0'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
vite@7.3.1:
resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -2429,6 +3591,14 @@ packages:
yaml:
optional: true
+ vitefu@1.1.2:
+ resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==}
+ peerDependencies:
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
vitest@4.0.18:
resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==}
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
@@ -2463,6 +3633,13 @@ packages:
jsdom:
optional: true
+ web-namespaces@2.0.1:
+ resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
+
+ which-pm-runs@1.1.0:
+ resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==}
+ engines: {node: '>=4'}
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -2473,7 +3650,11 @@ packages:
engines: {node: '>=8'}
hasBin: true
- wrap-ansi@7.0.0:
+ widest-line@5.0.0:
+ resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==}
+ engines: {node: '>=18'}
+
+ wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
@@ -2481,6 +3662,10 @@ packages:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
+ wrap-ansi@9.0.2:
+ resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
+ engines: {node: '>=18'}
+
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@@ -2488,6 +3673,9 @@ packages:
resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==}
engines: {node: '>=18'}
+ xxhash-wasm@1.1.0:
+ resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==}
+
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@@ -2509,12 +3697,96 @@ packages:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
engines: {node: '>=6'}
+ yocto-queue@1.2.2:
+ resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==}
+ engines: {node: '>=12.20'}
+
+ yocto-spinner@0.2.3:
+ resolution: {integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==}
+ engines: {node: '>=18.19'}
+
+ yoctocolors@2.1.2:
+ resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
+ engines: {node: '>=18'}
+
zip-stream@6.0.1:
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
engines: {node: '>= 14'}
+ zod-to-json-schema@3.25.1:
+ resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
+ peerDependencies:
+ zod: ^3.25 || ^4
+
+ zod-to-ts@1.2.0:
+ resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==}
+ peerDependencies:
+ typescript: ^4.9.4 || ^5.0.2
+ zod: ^3
+
+ zod@3.25.76:
+ resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
+
+ zod@4.3.6:
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
+
+ zwitch@2.0.4:
+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+
snapshots:
+ '@astrojs/compiler@2.13.1': {}
+
+ '@astrojs/internal-helpers@0.7.6': {}
+
+ '@astrojs/markdown-remark@6.3.11':
+ dependencies:
+ '@astrojs/internal-helpers': 0.7.6
+ '@astrojs/prism': 3.3.0
+ github-slugger: 2.0.0
+ hast-util-from-html: 2.0.3
+ hast-util-to-text: 4.0.2
+ import-meta-resolve: 4.2.0
+ js-yaml: 4.1.1
+ mdast-util-definitions: 6.0.0
+ rehype-raw: 7.0.0
+ rehype-stringify: 10.0.1
+ remark-gfm: 4.0.1
+ remark-parse: 11.0.0
+ remark-rehype: 11.1.2
+ remark-smartypants: 3.0.2
+ shiki: 3.23.0
+ smol-toml: 1.6.1
+ unified: 11.0.5
+ unist-util-remove-position: 5.0.0
+ unist-util-visit: 5.1.0
+ unist-util-visit-parents: 6.0.2
+ vfile: 6.0.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@astrojs/prism@3.3.0':
+ dependencies:
+ prismjs: 1.30.0
+
+ '@astrojs/sitemap@3.7.2':
+ dependencies:
+ sitemap: 9.0.1
+ stream-replace-string: 2.0.0
+ zod: 4.3.6
+
+ '@astrojs/telemetry@3.3.0':
+ dependencies:
+ ci-info: 4.4.0
+ debug: 4.4.3
+ dlv: 1.1.3
+ dset: 3.1.4
+ is-docker: 3.0.0
+ is-wsl: 3.1.1
+ which-pm-runs: 1.1.0
+ transitivePeerDependencies:
+ - supports-color
+
'@aws-crypto/sha256-browser@5.2.0':
dependencies:
'@aws-crypto/sha256-js': 5.2.0
@@ -3129,6 +4401,10 @@ snapshots:
'@biomejs/cli-win32-x64@2.4.5':
optional: true
+ '@capsizecss/unpack@4.0.0':
+ dependencies:
+ fontkitten: 1.0.3
+
'@commitlint/cli@20.4.3(@types/node@25.3.3)(typescript@5.9.3)':
dependencies:
'@commitlint/format': 20.4.3
@@ -3242,81 +4518,164 @@ snapshots:
dependencies:
'@jridgewell/trace-mapping': 0.3.9
+ '@emnapi/runtime@1.9.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@esbuild/aix-ppc64@0.25.12':
+ optional: true
+
'@esbuild/aix-ppc64@0.27.3':
optional: true
+ '@esbuild/android-arm64@0.25.12':
+ optional: true
+
'@esbuild/android-arm64@0.27.3':
optional: true
+ '@esbuild/android-arm@0.25.12':
+ optional: true
+
'@esbuild/android-arm@0.27.3':
optional: true
+ '@esbuild/android-x64@0.25.12':
+ optional: true
+
'@esbuild/android-x64@0.27.3':
optional: true
+ '@esbuild/darwin-arm64@0.25.12':
+ optional: true
+
'@esbuild/darwin-arm64@0.27.3':
optional: true
+ '@esbuild/darwin-x64@0.25.12':
+ optional: true
+
'@esbuild/darwin-x64@0.27.3':
optional: true
+ '@esbuild/freebsd-arm64@0.25.12':
+ optional: true
+
'@esbuild/freebsd-arm64@0.27.3':
optional: true
+ '@esbuild/freebsd-x64@0.25.12':
+ optional: true
+
'@esbuild/freebsd-x64@0.27.3':
optional: true
+ '@esbuild/linux-arm64@0.25.12':
+ optional: true
+
'@esbuild/linux-arm64@0.27.3':
optional: true
+ '@esbuild/linux-arm@0.25.12':
+ optional: true
+
'@esbuild/linux-arm@0.27.3':
optional: true
+ '@esbuild/linux-ia32@0.25.12':
+ optional: true
+
'@esbuild/linux-ia32@0.27.3':
optional: true
+ '@esbuild/linux-loong64@0.25.12':
+ optional: true
+
'@esbuild/linux-loong64@0.27.3':
optional: true
+ '@esbuild/linux-mips64el@0.25.12':
+ optional: true
+
'@esbuild/linux-mips64el@0.27.3':
optional: true
+ '@esbuild/linux-ppc64@0.25.12':
+ optional: true
+
'@esbuild/linux-ppc64@0.27.3':
optional: true
+ '@esbuild/linux-riscv64@0.25.12':
+ optional: true
+
'@esbuild/linux-riscv64@0.27.3':
optional: true
+ '@esbuild/linux-s390x@0.25.12':
+ optional: true
+
'@esbuild/linux-s390x@0.27.3':
optional: true
+ '@esbuild/linux-x64@0.25.12':
+ optional: true
+
'@esbuild/linux-x64@0.27.3':
optional: true
+ '@esbuild/netbsd-arm64@0.25.12':
+ optional: true
+
'@esbuild/netbsd-arm64@0.27.3':
optional: true
+ '@esbuild/netbsd-x64@0.25.12':
+ optional: true
+
'@esbuild/netbsd-x64@0.27.3':
optional: true
+ '@esbuild/openbsd-arm64@0.25.12':
+ optional: true
+
'@esbuild/openbsd-arm64@0.27.3':
optional: true
+ '@esbuild/openbsd-x64@0.25.12':
+ optional: true
+
'@esbuild/openbsd-x64@0.27.3':
optional: true
+ '@esbuild/openharmony-arm64@0.25.12':
+ optional: true
+
'@esbuild/openharmony-arm64@0.27.3':
optional: true
+ '@esbuild/sunos-x64@0.25.12':
+ optional: true
+
'@esbuild/sunos-x64@0.27.3':
optional: true
+ '@esbuild/win32-arm64@0.25.12':
+ optional: true
+
'@esbuild/win32-arm64@0.27.3':
optional: true
+ '@esbuild/win32-ia32@0.25.12':
+ optional: true
+
'@esbuild/win32-ia32@0.27.3':
optional: true
+ '@esbuild/win32-x64@0.25.12':
+ optional: true
+
'@esbuild/win32-x64@0.27.3':
optional: true
@@ -3339,6 +4698,103 @@ snapshots:
protobufjs: 7.5.4
yargs: 17.7.2
+ '@img/colour@1.1.0':
+ optional: true
+
+ '@img/sharp-darwin-arm64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-arm64': 1.2.4
+ optional: true
+
+ '@img/sharp-darwin-x64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-x64': 1.2.4
+ optional: true
+
+ '@img/sharp-libvips-darwin-arm64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-darwin-x64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-ppc64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-riscv64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-s390x@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-x64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.4':
+ optional: true
+
+ '@img/sharp-linux-arm64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-arm@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-ppc64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-ppc64': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-riscv64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-riscv64': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-s390x@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-s390x': 1.2.4
+ optional: true
+
+ '@img/sharp-linux-x64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-x64': 1.2.4
+ optional: true
+
+ '@img/sharp-linuxmusl-arm64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
+ optional: true
+
+ '@img/sharp-linuxmusl-x64@0.34.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.4
+ optional: true
+
+ '@img/sharp-wasm32@0.34.5':
+ dependencies:
+ '@emnapi/runtime': 1.9.1
+ optional: true
+
+ '@img/sharp-win32-arm64@0.34.5':
+ optional: true
+
+ '@img/sharp-win32-ia32@0.34.5':
+ optional: true
+
+ '@img/sharp-win32-x64@0.34.5':
+ optional: true
+
'@inversifyjs/common@1.5.2': {}
'@inversifyjs/container@1.15.0(reflect-metadata@0.2.2)':
@@ -3410,6 +4866,8 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.20.1
+ '@oslojs/encoding@1.1.0': {}
+
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -3436,6 +4894,14 @@ snapshots:
'@protobufjs/utf8@1.1.0': {}
+ '@rollup/pluginutils@5.3.0(rollup@4.59.0)':
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-walker: 2.0.2
+ picomatch: 4.0.4
+ optionalDependencies:
+ rollup: 4.59.0
+
'@rollup/rollup-android-arm-eabi@4.59.0':
optional: true
@@ -3577,6 +5043,39 @@ snapshots:
'@secretlint/types@11.3.1': {}
+ '@shikijs/core@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+ hast-util-to-html: 9.0.5
+
+ '@shikijs/engine-javascript@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+ oniguruma-to-es: 4.3.5
+
+ '@shikijs/engine-oniguruma@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+
+ '@shikijs/langs@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+
+ '@shikijs/themes@3.23.0':
+ dependencies:
+ '@shikijs/types': 3.23.0
+
+ '@shikijs/types@3.23.0':
+ dependencies:
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
+ '@shikijs/vscode-textmate@10.0.2': {}
+
'@simple-libs/stream-utils@1.2.0': {}
'@sindresorhus/merge-streams@2.3.0': {}
@@ -3915,6 +5414,10 @@ snapshots:
'@types/deep-eql': 4.0.2
assertion-error: 2.0.1
+ '@types/debug@4.1.13':
+ dependencies:
+ '@types/ms': 2.1.0
+
'@types/deep-eql@4.0.2': {}
'@types/docker-modem@3.0.6':
@@ -3930,16 +5433,38 @@ snapshots:
'@types/estree@1.0.8': {}
+ '@types/hast@3.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/mdast@4.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/ms@2.1.0': {}
+
+ '@types/nlcst@2.0.3':
+ dependencies:
+ '@types/unist': 3.0.3
+
'@types/node@18.19.130':
dependencies:
undici-types: 5.26.5
+ '@types/node@24.12.0':
+ dependencies:
+ undici-types: 7.16.0
+
'@types/node@25.3.3':
dependencies:
undici-types: 7.18.2
'@types/normalize-package-data@2.4.4': {}
+ '@types/sax@1.2.7':
+ dependencies:
+ '@types/node': 25.3.3
+
'@types/ssh2-streams@0.1.13':
dependencies:
'@types/node': 25.3.3
@@ -3953,6 +5478,8 @@ snapshots:
dependencies:
'@types/node': 18.19.130
+ '@types/unist@3.0.3': {}
+
'@typespec/ts-http-runtime@0.3.3':
dependencies:
http-proxy-agent: 7.0.2
@@ -3961,6 +5488,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@ungap/structured-clone@1.3.0': {}
+
'@vercel/ncc@0.38.4': {}
'@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))':
@@ -4035,6 +5564,10 @@ snapshots:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
+ ansi-align@3.0.1:
+ dependencies:
+ string-width: 4.2.3
+
ansi-escapes@7.3.0:
dependencies:
environment: 1.1.0
@@ -4049,6 +5582,11 @@ snapshots:
ansi-styles@6.2.3: {}
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.2
+
archiver-utils@5.0.2:
dependencies:
glob: 10.5.0
@@ -4075,10 +5613,16 @@ snapshots:
arg@4.1.3: {}
+ arg@5.0.2: {}
+
argparse@2.0.1: {}
+ aria-query@5.3.2: {}
+
array-ify@1.0.0: {}
+ array-iterate@2.0.1: {}
+
asn1@0.2.6:
dependencies:
safer-buffer: 2.1.2
@@ -4093,12 +5637,118 @@ snapshots:
astral-regex@2.0.0: {}
+ astro@5.18.1(@azure/identity@4.13.0)(@azure/keyvault-secrets@4.10.0(@azure/core-client@1.10.1))(@types/node@25.3.3)(jiti@2.6.1)(rollup@4.59.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3):
+ dependencies:
+ '@astrojs/compiler': 2.13.1
+ '@astrojs/internal-helpers': 0.7.6
+ '@astrojs/markdown-remark': 6.3.11
+ '@astrojs/telemetry': 3.3.0
+ '@capsizecss/unpack': 4.0.0
+ '@oslojs/encoding': 1.1.0
+ '@rollup/pluginutils': 5.3.0(rollup@4.59.0)
+ acorn: 8.16.0
+ aria-query: 5.3.2
+ axobject-query: 4.1.0
+ boxen: 8.0.1
+ ci-info: 4.4.0
+ clsx: 2.1.1
+ common-ancestor-path: 1.0.1
+ cookie: 1.1.1
+ cssesc: 3.0.0
+ debug: 4.4.3
+ deterministic-object-hash: 2.0.2
+ devalue: 5.6.4
+ diff: 8.0.4
+ dlv: 1.1.3
+ dset: 3.1.4
+ es-module-lexer: 1.7.0
+ esbuild: 0.27.3
+ estree-walker: 3.0.3
+ flattie: 1.1.1
+ fontace: 0.4.1
+ github-slugger: 2.0.0
+ html-escaper: 3.0.3
+ http-cache-semantics: 4.2.0
+ import-meta-resolve: 4.2.0
+ js-yaml: 4.1.1
+ magic-string: 0.30.21
+ magicast: 0.5.2
+ mrmime: 2.0.1
+ neotraverse: 0.6.18
+ p-limit: 6.2.0
+ p-queue: 8.1.1
+ package-manager-detector: 1.6.0
+ piccolore: 0.1.3
+ picomatch: 4.0.4
+ prompts: 2.4.2
+ rehype: 13.0.2
+ semver: 7.7.4
+ shiki: 3.23.0
+ smol-toml: 1.6.1
+ svgo: 4.0.1
+ tinyexec: 1.0.2
+ tinyglobby: 0.2.15
+ tsconfck: 3.1.6(typescript@5.9.3)
+ ultrahtml: 1.6.0
+ unifont: 0.7.4
+ unist-util-visit: 5.1.0
+ unstorage: 1.17.5(@azure/identity@4.13.0)(@azure/keyvault-secrets@4.10.0(@azure/core-client@1.10.1))
+ vfile: 6.0.3
+ vite: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)
+ vitefu: 1.1.2(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))
+ xxhash-wasm: 1.1.0
+ yargs-parser: 21.1.1
+ yocto-spinner: 0.2.3
+ zod: 3.25.76
+ zod-to-json-schema: 3.25.1(zod@3.25.76)
+ zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76)
+ optionalDependencies:
+ sharp: 0.34.5
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@types/node'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - db0
+ - idb-keyval
+ - ioredis
+ - jiti
+ - less
+ - lightningcss
+ - rollup
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - typescript
+ - uploadthing
+ - yaml
+
async-lock@1.4.1: {}
async@3.2.6: {}
+ axobject-query@4.1.0: {}
+
b4a@1.8.0: {}
+ bail@2.0.2: {}
+
balanced-match@4.0.4: {}
bare-events@2.8.2: {}
@@ -4134,6 +5784,8 @@ snapshots:
dependencies:
bare-path: 3.0.0
+ base-64@1.0.0: {}
+
base64-js@1.5.1: {}
bcrypt-pbkdf@1.0.2:
@@ -4150,10 +5802,23 @@ snapshots:
inherits: 2.0.4
readable-stream: 3.6.2
+ boolbase@1.0.0: {}
+
boundary@2.0.0: {}
bowser@2.14.1: {}
+ boxen@8.0.1:
+ dependencies:
+ ansi-align: 3.0.1
+ camelcase: 8.0.0
+ chalk: 5.6.2
+ cli-boxes: 3.0.0
+ string-width: 7.2.0
+ type-fest: 4.41.0
+ widest-line: 5.0.0
+ wrap-ansi: 9.0.2
+
brace-expansion@5.0.4:
dependencies:
balanced-match: 4.0.4
@@ -4187,6 +5852,10 @@ snapshots:
callsites@3.1.0: {}
+ camelcase@8.0.0: {}
+
+ ccount@2.0.1: {}
+
chai@6.2.2: {}
chalk@4.1.2:
@@ -4196,22 +5865,44 @@ snapshots:
chalk@5.6.2: {}
+ character-entities-html4@2.1.0: {}
+
+ character-entities-legacy@3.0.0: {}
+
+ character-entities@2.0.2: {}
+
+ chokidar@5.0.0:
+ dependencies:
+ readdirp: 5.0.0
+
chownr@1.1.4: {}
+ ci-info@4.4.0: {}
+
+ cli-boxes@3.0.0: {}
+
cliui@8.0.1:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
+ clsx@2.1.1: {}
+
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
color-name@1.1.4: {}
+ comma-separated-tokens@2.0.3: {}
+
+ commander@11.1.0: {}
+
commander@14.0.3: {}
+ common-ancestor-path@1.0.1: {}
+
compare-func@2.0.0:
dependencies:
array-ify: 1.0.0
@@ -4238,6 +5929,10 @@ snapshots:
'@simple-libs/stream-utils': 1.2.0
meow: 13.2.0
+ cookie-es@1.2.2: {}
+
+ cookie@1.1.1: {}
+
core-util-is@1.0.3: {}
cosmiconfig-typescript-loader@6.2.0(@types/node@25.3.3)(cosmiconfig@9.0.1(typescript@5.9.3))(typescript@5.9.3):
@@ -4277,12 +5972,46 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
- dargs@8.1.0: {}
+ crossws@0.3.5:
+ dependencies:
+ uncrypto: 0.1.3
+
+ css-select@5.2.2:
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 6.2.2
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ nth-check: 2.1.1
+
+ css-tree@2.2.1:
+ dependencies:
+ mdn-data: 2.0.28
+ source-map-js: 1.2.1
+
+ css-tree@3.2.1:
+ dependencies:
+ mdn-data: 2.27.1
+ source-map-js: 1.2.1
+
+ css-what@6.2.2: {}
+
+ cssesc@3.0.0: {}
+
+ csso@5.0.5:
+ dependencies:
+ css-tree: 2.2.1
+
+ dargs@8.1.0: {}
debug@4.4.3:
dependencies:
ms: 2.1.3
+ decode-named-character-reference@1.3.0:
+ dependencies:
+ character-entities: 2.0.2
+
default-browser-id@5.0.1: {}
default-browser@5.5.0:
@@ -4292,8 +6021,31 @@ snapshots:
define-lazy-prop@3.0.0: {}
+ defu@6.1.4: {}
+
+ dequal@2.0.3: {}
+
+ destr@2.0.5: {}
+
+ detect-libc@2.1.2:
+ optional: true
+
+ deterministic-object-hash@2.0.2:
+ dependencies:
+ base-64: 1.0.0
+
+ devalue@5.6.4: {}
+
+ devlop@1.1.0:
+ dependencies:
+ dequal: 2.0.3
+
diff@4.0.4: {}
+ diff@8.0.4: {}
+
+ dlv@1.1.3: {}
+
docker-compose@1.3.1:
dependencies:
yaml: 2.8.3
@@ -4319,12 +6071,32 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
dot-prop@5.3.0:
dependencies:
is-obj: 2.0.0
dotenv@17.3.1: {}
+ dset@3.1.4: {}
+
eastasianwidth@0.2.0: {}
ecdsa-sig-formatter@1.0.11:
@@ -4335,6 +6107,8 @@ snapshots:
dependencies:
version-range: 4.15.0
+ emoji-regex@10.6.0: {}
+
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
@@ -4343,6 +6117,10 @@ snapshots:
dependencies:
once: 1.4.0
+ entities@4.5.0: {}
+
+ entities@6.0.1: {}
+
env-paths@2.2.1: {}
environment@1.1.0: {}
@@ -4353,6 +6131,35 @@ snapshots:
es-module-lexer@1.7.0: {}
+ esbuild@0.25.12:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.12
+ '@esbuild/android-arm': 0.25.12
+ '@esbuild/android-arm64': 0.25.12
+ '@esbuild/android-x64': 0.25.12
+ '@esbuild/darwin-arm64': 0.25.12
+ '@esbuild/darwin-x64': 0.25.12
+ '@esbuild/freebsd-arm64': 0.25.12
+ '@esbuild/freebsd-x64': 0.25.12
+ '@esbuild/linux-arm': 0.25.12
+ '@esbuild/linux-arm64': 0.25.12
+ '@esbuild/linux-ia32': 0.25.12
+ '@esbuild/linux-loong64': 0.25.12
+ '@esbuild/linux-mips64el': 0.25.12
+ '@esbuild/linux-ppc64': 0.25.12
+ '@esbuild/linux-riscv64': 0.25.12
+ '@esbuild/linux-s390x': 0.25.12
+ '@esbuild/linux-x64': 0.25.12
+ '@esbuild/netbsd-arm64': 0.25.12
+ '@esbuild/netbsd-x64': 0.25.12
+ '@esbuild/openbsd-arm64': 0.25.12
+ '@esbuild/openbsd-x64': 0.25.12
+ '@esbuild/openharmony-arm64': 0.25.12
+ '@esbuild/sunos-x64': 0.25.12
+ '@esbuild/win32-arm64': 0.25.12
+ '@esbuild/win32-ia32': 0.25.12
+ '@esbuild/win32-x64': 0.25.12
+
esbuild@0.27.3:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.3
@@ -4384,12 +6191,18 @@ snapshots:
escalade@3.2.0: {}
+ escape-string-regexp@5.0.0: {}
+
+ estree-walker@2.0.2: {}
+
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.8
event-target-shim@5.0.1: {}
+ eventemitter3@5.0.4: {}
+
events-universal@1.0.1:
dependencies:
bare-events: 2.8.2
@@ -4400,6 +6213,8 @@ snapshots:
expect-type@1.3.0: {}
+ extend@3.0.2: {}
+
fast-deep-equal@3.1.3: {}
fast-fifo@1.3.2: {}
@@ -4436,6 +6251,16 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
+ flattie@1.1.1: {}
+
+ fontace@0.4.1:
+ dependencies:
+ fontkitten: 1.0.3
+
+ fontkitten@1.0.3:
+ dependencies:
+ tiny-inflate: 1.0.3
+
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
@@ -4448,6 +6273,8 @@ snapshots:
get-caller-file@2.0.5: {}
+ get-east-asian-width@1.5.0: {}
+
get-port@7.1.0: {}
get-tsconfig@4.13.7:
@@ -4460,6 +6287,8 @@ snapshots:
meow: 12.1.1
split2: 4.2.0
+ github-slugger@2.0.0: {}
+
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -4494,14 +6323,119 @@ snapshots:
graceful-fs@4.2.11: {}
+ h3@1.15.10:
+ dependencies:
+ cookie-es: 1.2.2
+ crossws: 0.3.5
+ defu: 6.1.4
+ destr: 2.0.5
+ iron-webcrypto: 1.2.1
+ node-mock-http: 1.0.4
+ radix3: 1.1.2
+ ufo: 1.6.3
+ uncrypto: 0.1.3
+
has-flag@4.0.0: {}
+ hast-util-from-html@2.0.3:
+ dependencies:
+ '@types/hast': 3.0.4
+ devlop: 1.1.0
+ hast-util-from-parse5: 8.0.3
+ parse5: 7.3.0
+ vfile: 6.0.3
+ vfile-message: 4.0.3
+
+ hast-util-from-parse5@8.0.3:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ devlop: 1.1.0
+ hastscript: 9.0.1
+ property-information: 7.1.0
+ vfile: 6.0.3
+ vfile-location: 5.0.3
+ web-namespaces: 2.0.1
+
+ hast-util-is-element@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-parse-selector@4.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hast-util-raw@9.1.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ '@ungap/structured-clone': 1.3.0
+ hast-util-from-parse5: 8.0.3
+ hast-util-to-parse5: 8.0.1
+ html-void-elements: 3.0.0
+ mdast-util-to-hast: 13.2.1
+ parse5: 7.3.0
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.1.0
+ vfile: 6.0.3
+ web-namespaces: 2.0.1
+ zwitch: 2.0.4
+
+ hast-util-to-html@9.0.5:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ comma-separated-tokens: 2.0.3
+ hast-util-whitespace: 3.0.0
+ html-void-elements: 3.0.0
+ mdast-util-to-hast: 13.2.1
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ stringify-entities: 4.0.4
+ zwitch: 2.0.4
+
+ hast-util-to-parse5@8.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ devlop: 1.1.0
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ web-namespaces: 2.0.1
+ zwitch: 2.0.4
+
+ hast-util-to-text@4.0.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ hast-util-is-element: 3.0.0
+ unist-util-find-after: 5.0.0
+
+ hast-util-whitespace@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hastscript@9.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ hast-util-parse-selector: 4.0.0
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+
hosted-git-info@7.0.2:
dependencies:
lru-cache: 10.4.3
html-escaper@2.0.2: {}
+ html-escaper@3.0.3: {}
+
+ html-void-elements@3.0.0: {}
+
+ http-cache-semantics@4.2.0: {}
+
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.4
@@ -4541,6 +6475,8 @@ snapshots:
transitivePeerDependencies:
- reflect-metadata
+ iron-webcrypto@1.2.1: {}
+
is-arrayish@0.2.1: {}
is-docker@3.0.0: {}
@@ -4638,6 +6574,8 @@ snapshots:
jwa: 2.0.1
safe-buffer: 5.2.1
+ kleur@3.0.3: {}
+
lazystream@1.0.1:
dependencies:
readable-stream: 2.3.8
@@ -4719,10 +6657,14 @@ snapshots:
long@5.3.2: {}
+ longest-streak@3.1.0: {}
+
lru-cache@10.4.3: {}
lru-cache@11.2.6: {}
+ lru-cache@11.2.7: {}
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -4739,12 +6681,329 @@ snapshots:
make-error@1.3.6: {}
+ markdown-table@3.0.4: {}
+
+ mdast-util-definitions@6.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ unist-util-visit: 5.1.0
+
+ mdast-util-find-and-replace@3.0.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ escape-string-regexp: 5.0.0
+ unist-util-is: 6.0.1
+ unist-util-visit-parents: 6.0.2
+
+ mdast-util-from-markdown@2.0.3:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ decode-named-character-reference: 1.3.0
+ devlop: 1.1.0
+ mdast-util-to-string: 4.0.0
+ micromark: 4.0.2
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-decode-string: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ unist-util-stringify-position: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-autolink-literal@2.0.1:
+ dependencies:
+ '@types/mdast': 4.0.4
+ ccount: 2.0.1
+ devlop: 1.1.0
+ mdast-util-find-and-replace: 3.0.2
+ micromark-util-character: 2.1.1
+
+ mdast-util-gfm-footnote@2.1.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ micromark-util-normalize-identifier: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-strikethrough@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-table@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ markdown-table: 3.0.4
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm-task-list-item@2.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-gfm@3.1.0:
+ dependencies:
+ mdast-util-from-markdown: 2.0.3
+ mdast-util-gfm-autolink-literal: 2.0.1
+ mdast-util-gfm-footnote: 2.1.0
+ mdast-util-gfm-strikethrough: 2.0.0
+ mdast-util-gfm-table: 2.0.0
+ mdast-util-gfm-task-list-item: 2.0.0
+ mdast-util-to-markdown: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ mdast-util-phrasing@4.1.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ unist-util-is: 6.0.1
+
+ mdast-util-to-hast@13.2.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@ungap/structured-clone': 1.3.0
+ devlop: 1.1.0
+ micromark-util-sanitize-uri: 2.0.1
+ trim-lines: 3.0.1
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.1.0
+ vfile: 6.0.3
+
+ mdast-util-to-markdown@2.1.2:
+ dependencies:
+ '@types/mdast': 4.0.4
+ '@types/unist': 3.0.3
+ longest-streak: 3.1.0
+ mdast-util-phrasing: 4.1.0
+ mdast-util-to-string: 4.0.0
+ micromark-util-classify-character: 2.0.1
+ micromark-util-decode-string: 2.0.1
+ unist-util-visit: 5.1.0
+ zwitch: 2.0.4
+
+ mdast-util-to-string@4.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+
+ mdn-data@2.0.28: {}
+
+ mdn-data@2.27.1: {}
+
meow@12.1.1: {}
meow@13.2.0: {}
merge2@1.4.1: {}
+ micromark-core-commonmark@2.0.3:
+ dependencies:
+ decode-named-character-reference: 1.3.0
+ devlop: 1.1.0
+ micromark-factory-destination: 2.0.1
+ micromark-factory-label: 2.0.1
+ micromark-factory-space: 2.0.1
+ micromark-factory-title: 2.0.1
+ micromark-factory-whitespace: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-html-tag-name: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-subtokenize: 2.1.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-autolink-literal@2.1.0:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-footnote@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-strikethrough@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-table@2.1.1:
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-tagfilter@2.0.0:
+ dependencies:
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm-task-list-item@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-extension-gfm@3.0.0:
+ dependencies:
+ micromark-extension-gfm-autolink-literal: 2.1.0
+ micromark-extension-gfm-footnote: 2.1.0
+ micromark-extension-gfm-strikethrough: 2.1.0
+ micromark-extension-gfm-table: 2.1.1
+ micromark-extension-gfm-tagfilter: 2.0.0
+ micromark-extension-gfm-task-list-item: 2.1.0
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-destination@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-label@2.0.1:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-space@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-title@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-factory-whitespace@2.0.1:
+ dependencies:
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-character@2.1.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-chunked@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-classify-character@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-combine-extensions@2.0.1:
+ dependencies:
+ micromark-util-chunked: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-decode-numeric-character-reference@2.0.2:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-decode-string@2.0.1:
+ dependencies:
+ decode-named-character-reference: 1.3.0
+ micromark-util-character: 2.1.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-encode@2.0.1: {}
+
+ micromark-util-html-tag-name@2.0.1: {}
+
+ micromark-util-normalize-identifier@2.0.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-resolve-all@2.0.1:
+ dependencies:
+ micromark-util-types: 2.0.2
+
+ micromark-util-sanitize-uri@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-encode: 2.0.1
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-subtokenize@2.1.0:
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-symbol@2.0.1: {}
+
+ micromark-util-types@2.0.2: {}
+
+ micromark@4.0.2:
+ dependencies:
+ '@types/debug': 4.1.13
+ debug: 4.4.3
+ decode-named-character-reference: 1.3.0
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-chunked: 2.0.1
+ micromark-util-combine-extensions: 2.0.1
+ micromark-util-decode-numeric-character-reference: 2.0.2
+ micromark-util-encode: 2.0.1
+ micromark-util-normalize-identifier: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-sanitize-uri: 2.0.1
+ micromark-util-subtokenize: 2.1.0
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
micromatch@4.0.8:
dependencies:
braces: 3.0.3
@@ -4762,6 +7021,8 @@ snapshots:
mkdirp@3.0.1: {}
+ mrmime@2.0.1: {}
+
ms@2.1.3: {}
nan@2.25.0:
@@ -4769,6 +7030,16 @@ snapshots:
nanoid@3.3.11: {}
+ neotraverse@0.6.18: {}
+
+ nlcst-to-string@4.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+
+ node-fetch-native@1.6.7: {}
+
+ node-mock-http@1.0.4: {}
+
normalize-package-data@6.0.2:
dependencies:
hosted-git-info: 7.0.2
@@ -4777,12 +7048,32 @@ snapshots:
normalize-path@3.0.0: {}
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
obug@2.1.1: {}
+ ofetch@1.5.1:
+ dependencies:
+ destr: 2.0.5
+ node-fetch-native: 1.6.7
+ ufo: 1.6.3
+
+ ohash@2.0.11: {}
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
+ oniguruma-parser@0.12.1: {}
+
+ oniguruma-to-es@4.3.5:
+ dependencies:
+ oniguruma-parser: 0.12.1
+ regex: 6.1.0
+ regex-recursion: 6.0.2
+
open@10.2.0:
dependencies:
default-browser: 5.5.0
@@ -4790,10 +7081,23 @@ snapshots:
is-inside-container: 1.0.0
wsl-utils: 0.1.0
+ p-limit@6.2.0:
+ dependencies:
+ yocto-queue: 1.2.2
+
p-map@7.0.4: {}
+ p-queue@8.1.1:
+ dependencies:
+ eventemitter3: 5.0.4
+ p-timeout: 6.1.4
+
+ p-timeout@6.1.4: {}
+
package-json-from-dist@1.0.1: {}
+ package-manager-detector@1.6.0: {}
+
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@@ -4811,6 +7115,19 @@ snapshots:
index-to-position: 1.2.0
type-fest: 4.41.0
+ parse-latin@7.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ '@types/unist': 3.0.3
+ nlcst-to-string: 4.0.0
+ unist-util-modify-children: 4.0.0
+ unist-util-visit-children: 3.0.0
+ vfile: 6.0.3
+
+ parse5@7.3.0:
+ dependencies:
+ entities: 6.0.1
+
path-expression-matcher@1.2.0: {}
path-key@3.1.1: {}
@@ -4829,6 +7146,8 @@ snapshots:
pathe@2.0.3: {}
+ piccolore@0.1.3: {}
+
picocolors@1.1.1: {}
picomatch@2.3.2: {}
@@ -4845,10 +7164,17 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
+ prismjs@1.30.0: {}
+
process-nextick-args@2.0.1: {}
process@0.11.10: {}
+ prompts@2.4.2:
+ dependencies:
+ kleur: 3.0.3
+ sisteransi: 1.0.5
+
proper-lockfile@4.1.2:
dependencies:
graceful-fs: 4.2.11
@@ -4862,6 +7188,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ property-information@7.1.0: {}
+
protobufjs@7.5.4:
dependencies:
'@protobufjs/aspromise': 1.1.2
@@ -4884,6 +7212,8 @@ snapshots:
queue-microtask@1.2.3: {}
+ radix3@1.1.2: {}
+
rc-config-loader@4.1.4:
dependencies:
debug: 4.4.3
@@ -4929,8 +7259,86 @@ snapshots:
dependencies:
minimatch: 10.2.4
+ readdirp@5.0.0: {}
+
reflect-metadata@0.2.2: {}
+ regex-recursion@6.0.2:
+ dependencies:
+ regex-utilities: 2.3.0
+
+ regex-utilities@2.3.0: {}
+
+ regex@6.1.0:
+ dependencies:
+ regex-utilities: 2.3.0
+
+ rehype-parse@9.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-from-html: 2.0.3
+ unified: 11.0.5
+
+ rehype-raw@7.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-raw: 9.1.0
+ vfile: 6.0.3
+
+ rehype-stringify@10.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-to-html: 9.0.5
+ unified: 11.0.5
+
+ rehype@13.0.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ rehype-parse: 9.0.1
+ rehype-stringify: 10.0.1
+ unified: 11.0.5
+
+ remark-gfm@4.0.1:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-gfm: 3.1.0
+ micromark-extension-gfm: 3.0.0
+ remark-parse: 11.0.0
+ remark-stringify: 11.0.0
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ remark-parse@11.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-from-markdown: 2.0.3
+ micromark-util-types: 2.0.2
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+
+ remark-rehype@11.1.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ mdast-util-to-hast: 13.2.1
+ unified: 11.0.5
+ vfile: 6.0.3
+
+ remark-smartypants@3.0.2:
+ dependencies:
+ retext: 9.0.0
+ retext-smartypants: 6.2.0
+ unified: 11.0.5
+ unist-util-visit: 5.1.0
+
+ remark-stringify@11.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-to-markdown: 2.1.2
+ unified: 11.0.5
+
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
@@ -4941,6 +7349,31 @@ snapshots:
resolve-pkg-maps@1.0.0: {}
+ retext-latin@4.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ parse-latin: 7.0.0
+ unified: 11.0.5
+
+ retext-smartypants@6.2.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ nlcst-to-string: 4.0.0
+ unist-util-visit: 5.1.0
+
+ retext-stringify@4.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ nlcst-to-string: 4.0.0
+ unified: 11.0.5
+
+ retext@9.0.0:
+ dependencies:
+ '@types/nlcst': 2.0.3
+ retext-latin: 4.0.0
+ retext-stringify: 4.0.0
+ unified: 11.0.5
+
retry@0.12.0: {}
reusify@1.1.0: {}
@@ -4988,6 +7421,8 @@ snapshots:
safer-buffer@2.1.2: {}
+ sax@1.6.0: {}
+
secretlint@11.3.1:
dependencies:
'@secretlint/config-creator': 11.3.1
@@ -5003,18 +7438,70 @@ snapshots:
semver@7.7.4: {}
+ sharp@0.34.5:
+ dependencies:
+ '@img/colour': 1.1.0
+ detect-libc: 2.1.2
+ semver: 7.7.4
+ optionalDependencies:
+ '@img/sharp-darwin-arm64': 0.34.5
+ '@img/sharp-darwin-x64': 0.34.5
+ '@img/sharp-libvips-darwin-arm64': 1.2.4
+ '@img/sharp-libvips-darwin-x64': 1.2.4
+ '@img/sharp-libvips-linux-arm': 1.2.4
+ '@img/sharp-libvips-linux-arm64': 1.2.4
+ '@img/sharp-libvips-linux-ppc64': 1.2.4
+ '@img/sharp-libvips-linux-riscv64': 1.2.4
+ '@img/sharp-libvips-linux-s390x': 1.2.4
+ '@img/sharp-libvips-linux-x64': 1.2.4
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.4
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.4
+ '@img/sharp-linux-arm': 0.34.5
+ '@img/sharp-linux-arm64': 0.34.5
+ '@img/sharp-linux-ppc64': 0.34.5
+ '@img/sharp-linux-riscv64': 0.34.5
+ '@img/sharp-linux-s390x': 0.34.5
+ '@img/sharp-linux-x64': 0.34.5
+ '@img/sharp-linuxmusl-arm64': 0.34.5
+ '@img/sharp-linuxmusl-x64': 0.34.5
+ '@img/sharp-wasm32': 0.34.5
+ '@img/sharp-win32-arm64': 0.34.5
+ '@img/sharp-win32-ia32': 0.34.5
+ '@img/sharp-win32-x64': 0.34.5
+ optional: true
+
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
shebang-regex@3.0.0: {}
+ shiki@3.23.0:
+ dependencies:
+ '@shikijs/core': 3.23.0
+ '@shikijs/engine-javascript': 3.23.0
+ '@shikijs/engine-oniguruma': 3.23.0
+ '@shikijs/langs': 3.23.0
+ '@shikijs/themes': 3.23.0
+ '@shikijs/types': 3.23.0
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
siginfo@2.0.0: {}
signal-exit@3.0.7: {}
signal-exit@4.1.0: {}
+ sisteransi@1.0.5: {}
+
+ sitemap@9.0.1:
+ dependencies:
+ '@types/node': 24.12.0
+ '@types/sax': 1.2.7
+ arg: 5.0.2
+ sax: 1.6.0
+
slash@5.1.0: {}
slice-ansi@4.0.0:
@@ -5023,8 +7510,12 @@ snapshots:
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
+ smol-toml@1.6.1: {}
+
source-map-js@1.2.1: {}
+ space-separated-tokens@2.0.2: {}
+
spdx-correct@3.2.0:
dependencies:
spdx-expression-parse: 3.0.1
@@ -5060,6 +7551,8 @@ snapshots:
std-env@3.10.0: {}
+ stream-replace-string@2.0.0: {}
+
streamx@2.23.0:
dependencies:
events-universal: 1.0.1
@@ -5081,6 +7574,12 @@ snapshots:
emoji-regex: 9.2.2
strip-ansi: 7.2.0
+ string-width@7.2.0:
+ dependencies:
+ emoji-regex: 10.6.0
+ get-east-asian-width: 1.5.0
+ strip-ansi: 7.2.0
+
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
@@ -5089,6 +7588,11 @@ snapshots:
dependencies:
safe-buffer: 5.2.1
+ stringify-entities@4.0.4:
+ dependencies:
+ character-entities-html4: 2.1.0
+ character-entities-legacy: 3.0.0
+
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
@@ -5112,6 +7616,16 @@ snapshots:
has-flag: 4.0.0
supports-color: 7.2.0
+ svgo@4.0.1:
+ dependencies:
+ commander: 11.1.0
+ css-select: 5.2.2
+ css-tree: 3.2.1
+ css-what: 6.2.2
+ csso: 5.0.5
+ picocolors: 1.1.1
+ sax: 1.6.0
+
table@6.9.0:
dependencies:
ajv: 8.18.0
@@ -5205,6 +7719,8 @@ snapshots:
dependencies:
editions: 6.22.0
+ tiny-inflate@1.0.3: {}
+
tinybench@2.9.0: {}
tinyexec@1.0.2: {}
@@ -5222,6 +7738,10 @@ snapshots:
dependencies:
is-number: 7.0.0
+ trim-lines@3.0.1: {}
+
+ trough@2.2.0: {}
+
ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
@@ -5240,6 +7760,10 @@ snapshots:
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
+ tsconfck@3.1.6(typescript@5.9.3):
+ optionalDependencies:
+ typescript: 5.9.3
+
tslib@2.8.1: {}
tsx@4.21.0:
@@ -5255,8 +7779,16 @@ snapshots:
typescript@5.9.3: {}
+ ufo@1.6.3: {}
+
+ ultrahtml@1.6.0: {}
+
+ uncrypto@0.1.3: {}
+
undici-types@5.26.5: {}
+ undici-types@7.16.0: {}
+
undici-types@7.18.2: {}
undici@7.24.1: {}
@@ -5265,6 +7797,78 @@ snapshots:
unicorn-magic@0.3.0: {}
+ unified@11.0.5:
+ dependencies:
+ '@types/unist': 3.0.3
+ bail: 2.0.2
+ devlop: 1.1.0
+ extend: 3.0.2
+ is-plain-obj: 4.1.0
+ trough: 2.2.0
+ vfile: 6.0.3
+
+ unifont@0.7.4:
+ dependencies:
+ css-tree: 3.2.1
+ ofetch: 1.5.1
+ ohash: 2.0.11
+
+ unist-util-find-after@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+
+ unist-util-is@6.0.1:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-modify-children@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ array-iterate: 2.0.1
+
+ unist-util-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-remove-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-visit: 5.1.0
+
+ unist-util-stringify-position@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-children@3.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-parents@6.0.2:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+
+ unist-util-visit@5.1.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.1
+ unist-util-visit-parents: 6.0.2
+
+ unstorage@1.17.5(@azure/identity@4.13.0)(@azure/keyvault-secrets@4.10.0(@azure/core-client@1.10.1)):
+ dependencies:
+ anymatch: 3.1.3
+ chokidar: 5.0.0
+ destr: 2.0.5
+ h3: 1.15.10
+ lru-cache: 11.2.7
+ node-fetch-native: 1.6.7
+ ofetch: 1.5.1
+ ufo: 1.6.3
+ optionalDependencies:
+ '@azure/identity': 4.13.0
+ '@azure/keyvault-secrets': 4.10.0(@azure/core-client@1.10.1)
+
util-deprecate@1.0.2: {}
uuid@10.0.0: {}
@@ -5280,6 +7884,36 @@ snapshots:
version-range@4.15.0: {}
+ vfile-location@5.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile: 6.0.3
+
+ vfile-message@4.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-stringify-position: 4.0.0
+
+ vfile@6.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile-message: 4.0.3
+
+ vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3):
+ dependencies:
+ esbuild: 0.25.12
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
+ postcss: 8.5.6
+ rollup: 4.59.0
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ '@types/node': 25.3.3
+ fsevents: 2.3.3
+ jiti: 2.6.1
+ tsx: 4.21.0
+ yaml: 2.8.3
+
vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3):
dependencies:
esbuild: 0.27.3
@@ -5295,6 +7929,10 @@ snapshots:
tsx: 4.21.0
yaml: 2.8.3
+ vitefu@1.1.2(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)):
+ optionalDependencies:
+ vite: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)
+
vitest@4.0.18(@types/node@25.3.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3):
dependencies:
'@vitest/expect': 4.0.18
@@ -5332,6 +7970,10 @@ snapshots:
- tsx
- yaml
+ web-namespaces@2.0.1: {}
+
+ which-pm-runs@1.1.0: {}
+
which@2.0.2:
dependencies:
isexe: 2.0.0
@@ -5341,6 +7983,10 @@ snapshots:
siginfo: 2.0.0
stackback: 0.0.2
+ widest-line@5.0.0:
+ dependencies:
+ string-width: 7.2.0
+
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
@@ -5353,12 +7999,20 @@ snapshots:
string-width: 5.1.2
strip-ansi: 7.2.0
+ wrap-ansi@9.0.2:
+ dependencies:
+ ansi-styles: 6.2.3
+ string-width: 7.2.0
+ strip-ansi: 7.2.0
+
wrappy@1.0.2: {}
wsl-utils@0.1.0:
dependencies:
is-wsl: 3.1.1
+ xxhash-wasm@1.1.0: {}
+
y18n@5.0.8: {}
yaml@2.8.3: {}
@@ -5377,8 +8031,31 @@ snapshots:
yn@3.1.1: {}
+ yocto-queue@1.2.2: {}
+
+ yocto-spinner@0.2.3:
+ dependencies:
+ yoctocolors: 2.1.2
+
+ yoctocolors@2.1.2: {}
+
zip-stream@6.0.1:
dependencies:
archiver-utils: 5.0.2
compress-commons: 6.0.2
readable-stream: 4.7.0
+
+ zod-to-json-schema@3.25.1(zod@3.25.76):
+ dependencies:
+ zod: 3.25.76
+
+ zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ typescript: 5.9.3
+ zod: 3.25.76
+
+ zod@3.25.76: {}
+
+ zod@4.3.6: {}
+
+ zwitch@2.0.4: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 6382ee1f..db6dd9d2 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,5 +1,6 @@
packages:
- "."
+ - "src/apps/website"
onlyBuiltDependencies:
- cpu-features
diff --git a/src/apps/website/astro.config.mjs b/src/apps/website/astro.config.mjs
new file mode 100644
index 00000000..e8eea203
--- /dev/null
+++ b/src/apps/website/astro.config.mjs
@@ -0,0 +1,18 @@
+import { defineConfig } from 'astro/config';
+import sitemap from '@astrojs/sitemap';
+
+export default defineConfig({
+ site: 'https://envilder.com',
+ output: 'static',
+ integrations: [sitemap()],
+ i18n: {
+ defaultLocale: 'en',
+ locales: ['en', 'ca', 'es'],
+ routing: {
+ prefixDefaultLocale: false,
+ },
+ },
+ build: {
+ assets: '_assets',
+ },
+});
diff --git a/src/apps/website/package.json b/src/apps/website/package.json
new file mode 100644
index 00000000..7a7e781e
--- /dev/null
+++ b/src/apps/website/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "@envilder/website",
+ "type": "module",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "dev": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "astro": "astro"
+ },
+ "dependencies": {
+ "astro": "^5.8.0",
+ "@astrojs/sitemap": "^3.3.1"
+ }
+}
\ No newline at end of file
diff --git a/src/apps/website/public/AWS.svg b/src/apps/website/public/AWS.svg
new file mode 100644
index 00000000..39f9762a
--- /dev/null
+++ b/src/apps/website/public/AWS.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/apps/website/public/Azure.svg b/src/apps/website/public/Azure.svg
new file mode 100644
index 00000000..6c0d5a7a
--- /dev/null
+++ b/src/apps/website/public/Azure.svg
@@ -0,0 +1 @@
+
diff --git a/src/apps/website/public/GitHubActions.svg b/src/apps/website/public/GitHubActions.svg
new file mode 100644
index 00000000..2929e024
--- /dev/null
+++ b/src/apps/website/public/GitHubActions.svg
@@ -0,0 +1 @@
+
diff --git a/src/apps/website/public/NPM.svg b/src/apps/website/public/NPM.svg
new file mode 100644
index 00000000..2ee0f35b
--- /dev/null
+++ b/src/apps/website/public/NPM.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/apps/website/public/favicon.svg b/src/apps/website/public/favicon.svg
new file mode 100644
index 00000000..fb6d3167
--- /dev/null
+++ b/src/apps/website/public/favicon.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/Changelog.astro b/src/apps/website/src/components/Changelog.astro
new file mode 100644
index 00000000..ddadaed1
--- /dev/null
+++ b/src/apps/website/src/components/Changelog.astro
@@ -0,0 +1,139 @@
+---
+import { useTranslations, localizedPath } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.changelog.title}{t.changelog.titleAccent}
+
+ {t.changelog.subtitle}
+
+
+
+
+
+
+
+ {t.changelog.highlights.map((h) => (
+
+ {h.icon}
+ {h.text}
+
+ ))}
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/CodeBlock.astro b/src/apps/website/src/components/CodeBlock.astro
new file mode 100644
index 00000000..a3807cec
--- /dev/null
+++ b/src/apps/website/src/components/CodeBlock.astro
@@ -0,0 +1,61 @@
+---
+export interface Props {
+ lang?: string;
+ filename?: string;
+}
+
+const { lang = 'json', filename } = Astro.props;
+---
+
+
+ {filename && (
+
+ )}
+
+
+
+
diff --git a/src/apps/website/src/components/DemoVideo.astro b/src/apps/website/src/components/DemoVideo.astro
new file mode 100644
index 00000000..35f0eaa0
--- /dev/null
+++ b/src/apps/website/src/components/DemoVideo.astro
@@ -0,0 +1,109 @@
+---
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.demo.title}{t.demo.titleAccent}
+
+ {t.demo.subtitle}
+
+
+
+
+
+
+
▶
+
{t.demo.cliDemo}
+
{t.demo.comingSoon}
+
+
+
+
+
+
▶
+
{t.demo.ghaWorkflow}
+
{t.demo.comingSoon}
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/DocsContent.astro b/src/apps/website/src/components/DocsContent.astro
new file mode 100644
index 00000000..a83a5c83
--- /dev/null
+++ b/src/apps/website/src/components/DocsContent.astro
@@ -0,0 +1,930 @@
+---
+import CodeBlock from './CodeBlock.astro';
+import Footer from './Footer.astro';
+import { useTranslations, localizedPath } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t.docs.installTitle}
+
+
+ pnpm
+ pnpm add -g envilder
+
+
+ npm
+ npm install -g envilder
+
+
+ npx
+ npx envilder --help
+
+
+
+
+
+ {t.docs.credTitle}
+
+ {t.docs.credAwsTitle}
+ {t.docs.credAwsDesc}
+ aws configure
+ {t.docs.credAwsProfile}
+ {`aws configure --profile dev-account
+
+# Then pass it to envilder
+envilder --map=param-map.json --envfile=.env --profile=dev-account`}
+
+ {t.docs.credAzureTitle}
+ {t.docs.credAzureDesc}
+ az login
+ {t.docs.credAzureVault}
+
+
+
+ {t.docs.permTitle}
+
+ {t.docs.permAwsTitle}
+ {t.docs.permAwsDesc}
+
+
+ {t.docs.permOperation} {t.docs.permPermission}
+
+
+ {t.docs.permPull} ssm:GetParameter
+ {t.docs.permPush} ssm:PutParameter
+
+
+ {t.docs.permPolicyExample}
+ {`{
+ "Version": "2012-10-17",
+ "Statement": [{
+ "Effect": "Allow",
+ "Action": ["ssm:GetParameter", "ssm:PutParameter"],
+ "Resource": "arn:aws:ssm:us-east-1:123456789:parameter/myapp/*"
+ }]
+}`}
+
+ {t.docs.permAzureTitle}
+
+
+ {t.docs.permOperation} {t.docs.permPermission}
+
+
+ {t.docs.permPull} Get
+ {t.docs.permPush} Set
+
+
+ {t.docs.permAzureRbac}
+ {`az role assignment create \\
+ --role "Key Vault Secrets Officer" \\
+ --assignee \\
+ --scope /subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/`}
+ {t.docs.permAzurePullNote}
+
+
+
+
+
+ {t.docs.mapTitle}
+ {t.docs.mapIntro}
+
+
+
📄
+
+ {t.docs.mapCalloutStructure} {t.docs.mapCalloutKey}
+ {t.docs.mapCalloutValue}
+
+
+
+ {t.docs.mapBasicTitle}
+ {t.docs.mapBasicDesc}
+ {`{
+ "API_KEY": "/myapp/prod/api-key",
+ "DB_PASSWORD": "/myapp/prod/db-password",
+ "SECRET_TOKEN": "/myapp/prod/secret-token"
+}`}
+ {t.docs.mapBasicGenerates}
+ {`API_KEY=
+DB_PASSWORD=
+SECRET_TOKEN=`}
+
+ {t.docs.mapConfigTitle}
+ {t.docs.mapConfigDesc}
+
+ {t.docs.mapConfigOptionsTitle}
+
+
+ {t.docs.mapThKey} {t.docs.mapThType} {t.docs.mapThDefault} {t.docs.mapThDescription}
+
+
+
+ provider
+ "aws" | "azure"
+ "aws"
+ {t.docs.mapProviderDesc}
+
+
+ vaultUrl
+ string
+ —
+ {t.docs.mapVaultUrlDesc}
+
+
+ profile
+ string
+ —
+ {t.docs.mapProfileDesc}
+
+
+
+
+ {t.docs.mapAwsProfileTitle}
+ {t.docs.mapAwsProfileDesc}
+ {`{
+ "$config": {
+ "provider": "aws",
+ "profile": "prod-account"
+ },
+ "API_KEY": "/myapp/prod/api-key",
+ "DB_PASSWORD": "/myapp/prod/db-password"
+}`}
+ {t.docs.mapAwsProfileExplain}
+
+ {t.docs.mapAzureTitle}
+ {t.docs.mapAzureDesc}
+ {`{
+ "$config": {
+ "provider": "azure",
+ "vaultUrl": "https://my-vault.vault.azure.net"
+ },
+ "API_KEY": "myapp-prod-api-key",
+ "DB_PASSWORD": "myapp-prod-db-password"
+}`}
+
+
+
⚠️
+
+ {t.docs.mapAzureWarningTitle} {t.docs.mapAzureWarningDesc}
+
+
+
+ {t.docs.mapDifferencesTitle}
+
+
+ {t.docs.mapThEmpty} {t.docs.mapThAwsSsm} {t.docs.mapThAzureKv}
+
+
+
+ {t.docs.mapSecretPathFormat}
+ {t.docs.mapAwsPathFormat}/myapp/prod/api-key
+ {t.docs.mapAzurePathFormat}myapp-prod-api-key
+
+
+ {t.docs.mapRequiredConfig}
+ {t.docs.mapAwsRequiredConfig}
+ {t.docs.mapAzureRequiredConfig}
+
+
+ {t.docs.mapOptionalConfig}
+ profile
+ —
+
+
+ {t.docs.mapAuthentication}
+ {t.docs.mapAwsAuth}
+ {t.docs.mapAzureAuth}
+
+
+
+
+ {t.docs.mapMultiEnvTitle}
+ {t.docs.mapMultiEnvDesc}
+
+ {`{
+ "$config": {
+ "provider": "aws",
+ "profile": "dev-account"
+ },
+ "API_KEY": "/myapp/dev/api-key",
+ "DB_PASSWORD": "/myapp/dev/db-password"
+}`}
+ {`{
+ "$config": {
+ "provider": "aws",
+ "profile": "prod-account"
+ },
+ "API_KEY": "/myapp/prod/api-key",
+ "DB_PASSWORD": "/myapp/prod/db-password"
+}`}
+
+ {t.docs.mapMultiEnvThenPull}
+ {`# Development
+envilder --map=config/dev/param-map.json --envfile=.env.dev
+
+# Production
+envilder --map=config/prod/param-map.json --envfile=.env.prod`}
+
+ {t.docs.mapOverrideTitle}
+ {t.docs.mapOverrideDesc}
+ {`# Uses $config from the map file as-is
+envilder --map=param-map.json --envfile=.env
+
+# Overrides provider and vault URL, ignoring $config
+envilder --provider=azure \\
+ --vault-url=https://other-vault.vault.azure.net \\
+ --map=param-map.json --envfile=.env
+
+# Overrides just the AWS profile
+envilder --map=param-map.json --envfile=.env --profile=staging-account`}
+
+ {t.docs.mapPriorityNote}
+
+
+
+ {t.docs.pullTitle}
+ {t.docs.pullDesc}
+
+ envilder --map=param-map.json --envfile=.env
+
+ {t.docs.pullOptions}
+
+
+ Option {t.docs.mapThDescription}
+
+
+ --map{t.docs.pullOptMap}
+ --envfile{t.docs.pullOptEnv}
+ --provider{t.docs.pullOptProvider}
+ --vault-url{t.docs.pullOptVault}
+ --profile{t.docs.pullOptProfile}
+
+
+
+ {t.docs.pullExamples}
+ {`# Default (AWS SSM)
+envilder --map=param-map.json --envfile=.env
+
+# With AWS profile
+envilder --map=param-map.json --envfile=.env --profile=prod-account
+
+# Azure via $config in map file
+envilder --map=azure-param-map.json --envfile=.env
+
+# Azure via CLI flags
+envilder --provider=azure \\
+ --vault-url=https://my-vault.vault.azure.net \\
+ --map=param-map.json --envfile=.env`}
+
+ Output
+ {`# Generated by Envilder
+API_KEY=abc123
+DB_PASSWORD=secret456`}
+
+
+
+ {t.docs.pushTitle}
+ {t.docs.pushDesc}
+
+ envilder --push --envfile=.env --map=param-map.json
+
+ {t.docs.pushOptions}
+
+
+ Option {t.docs.mapThDescription}
+
+
+ --push{t.docs.pushOptPush}
+ --envfile{t.docs.pushOptEnv}
+ --map{t.docs.pushOptMap}
+ --provider{t.docs.pushOptProvider}
+ --vault-url{t.docs.pushOptVault}
+ --profile{t.docs.pushOptProfile}
+
+
+
+ {t.docs.pushExamples}
+ {`# Push to AWS SSM
+envilder --push --envfile=.env --map=param-map.json
+
+# With AWS profile
+envilder --push --envfile=.env.prod --map=param-map.json --profile=prod-account
+
+# Azure via $config in map file
+envilder --push --envfile=.env --map=azure-param-map.json
+
+# Azure via CLI flags
+envilder --push --provider=azure \\
+ --vault-url=https://my-vault.vault.azure.net \\
+ --envfile=.env --map=param-map.json`}
+
+
+
+ {t.docs.pushSingleTitle}
+ {t.docs.pushSingleDesc}
+
+ {`envilder --push --key=API_KEY --value=abc123 --secret-path=/myapp/api/key`}
+
+ {t.docs.pushSingleOptions}
+
+
+ Option {t.docs.mapThDescription}
+
+
+ --push{t.docs.pushSingleOptPush}
+ --key{t.docs.pushSingleOptKey}
+ --value{t.docs.pushSingleOptValue}
+ --secret-path{t.docs.pushSingleOptPath}
+ --provider{t.docs.pushSingleOptProvider}
+ --vault-url{t.docs.pushSingleOptVault}
+ --profile{t.docs.pushSingleOptProfile}
+
+
+
+
+
+
+
+ {t.docs.ghaSetupTitle}
+ {t.docs.ghaSetupDesc}
+
+ {t.docs.ghaPrerequisites}
+
+ AWS: {t.docs.ghaPrereqAws}
+ Azure: {t.docs.ghaPrereqAzure}
+ {t.docs.ghaPrereqMap}
+
+
+ {t.docs.ghaPullOnly}
+
+
+
+ {t.docs.ghaBasicTitle}
+ {`name: Deploy Application
+
+on:
+ push:
+ branches: [main]
+
+permissions:
+ id-token: write
+ contents: read
+
+jobs:
+ deploy:
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Configure AWS Credentials
+ uses: aws-actions/configure-aws-credentials@v6
+ with:
+ role-to-assume: \${{ secrets.AWS_ROLE_TO_ASSUME }}
+ aws-region: us-east-1
+
+ - name: Pull Secrets from AWS SSM
+ uses: macalbert/envilder/github-action@v0
+ with:
+ map-file: config/param-map.json
+ env-file: .env
+
+ - uses: actions/setup-node@v6
+ with:
+ node-version: "20.x"
+
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm build
+ - run: pnpm deploy`}
+
+
+
+ {t.docs.ghaMultiEnvTitle}
+ {`name: Deploy to Environment
+
+on:
+ workflow_dispatch:
+ inputs:
+ environment:
+ description: 'Target environment'
+ required: true
+ type: choice
+ options: [dev, staging, production]
+
+permissions:
+ id-token: write
+ contents: read
+
+jobs:
+ deploy:
+ runs-on: ubuntu-24.04
+ environment: \${{ inputs.environment }}
+ steps:
+ - uses: actions/checkout@v5
+
+ - uses: aws-actions/configure-aws-credentials@v6
+ with:
+ role-to-assume: \${{ secrets.AWS_ROLE_TO_ASSUME }}
+ aws-region: us-east-1
+
+ - name: Pull \${{ inputs.environment }} secrets
+ uses: macalbert/envilder/github-action@v0
+ with:
+ map-file: config/\${{ inputs.environment }}/param-map.json
+ env-file: .env
+
+ - uses: actions/setup-node@v6
+ with:
+ node-version: "20.x"
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm build
+ - run: pnpm deploy`}
+
+
+
+ {t.docs.ghaAzureTitle}
+ {`name: Deploy with Azure Key Vault
+
+on:
+ push:
+ branches: [main]
+
+permissions:
+ id-token: write
+ contents: read
+
+jobs:
+ deploy:
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Azure Login
+ uses: azure/login@v2
+ with:
+ client-id: \${{ secrets.AZURE_CLIENT_ID }}
+ tenant-id: \${{ secrets.AZURE_TENANT_ID }}
+ subscription-id: \${{ secrets.AZURE_SUBSCRIPTION_ID }}
+
+ - name: Pull Secrets from Azure Key Vault
+ uses: macalbert/envilder/github-action@v0
+ with:
+ map-file: config/param-map.json
+ env-file: .env
+ provider: azure
+ vault-url: https://my-vault.vault.azure.net
+
+ - uses: actions/setup-node@v6
+ with:
+ node-version: "20.x"
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm build
+ - run: pnpm deploy`}
+
+
+
+
+
+
+
+ {t.docs.configPriorityTitle}
+ {t.docs.configPriorityDesc}
+
+
1. {t.docs.configPriority1}
+
2. {t.docs.configPriority2}
+
3. {t.docs.configPriority3}
+
+ {t.docs.configPriorityExplain}
+
+
+
+ {t.docs.azureSetupTitle}
+ {t.docs.azureSetupCheck}
+ {`az keyvault show --name \\
+ --query properties.enableRbacAuthorization`}
+
+ true → {t.docs.azureRbacTrue}
+ false / null → {t.docs.azureRbacFalse}
+
+
+ {t.docs.azureOptionA}
+ {`az role assignment create \\
+ --role "Key Vault Secrets Officer" \\
+ --assignee \\
+ --scope /subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/`}
+
+ {t.docs.azureOptionB}
+ {`az keyvault set-policy \\
+ --name \\
+ --object-id \\
+ --secret-permissions get set list`}
+ {t.docs.azureAccessNote}
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/FeaturesGrid.astro b/src/apps/website/src/components/FeaturesGrid.astro
new file mode 100644
index 00000000..9806b791
--- /dev/null
+++ b/src/apps/website/src/components/FeaturesGrid.astro
@@ -0,0 +1,47 @@
+---
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.features.title}{t.features.titleAccent}
+
+ {t.features.subtitle}
+
+
+
+
+ {t.features.features.map((f) => (
+
+
{f.icon}
+
{f.title}
+
{f.description}
+
+ ))}
+
+
+
+
+
diff --git a/src/apps/website/src/components/Footer.astro b/src/apps/website/src/components/Footer.astro
new file mode 100644
index 00000000..a5559d8e
--- /dev/null
+++ b/src/apps/website/src/components/Footer.astro
@@ -0,0 +1,260 @@
+---
+import { useTranslations, localizedPath, languages } from '../i18n/utils';
+import ThemeSwitcher from './ThemeSwitcher.astro';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+const currentYear = new Date().getFullYear();
+const currentPath = Astro.url.pathname;
+
+const links = {
+ project: [
+ { label: t.footer.linkGithub, href: 'https://github.com/macalbert/envilder' },
+ { label: t.footer.linkNpm, href: 'https://www.npmjs.com/package/envilder' },
+ { label: t.footer.linkChangelog, href: localizedPath(lang, '/changelog') },
+ { label: t.footer.linkRoadmap, href: '#roadmap' },
+ ],
+ docs: [
+ { label: t.footer.linkGettingStarted, href: '#get-started' },
+ { label: t.footer.linkPullCommand, href: 'https://github.com/macalbert/envilder/blob/main/docs/pull-command.md' },
+ { label: t.footer.linkPushCommand, href: 'https://github.com/macalbert/envilder/blob/main/docs/push-command.md' },
+ { label: t.footer.linkGithubAction, href: 'https://github.com/macalbert/envilder/blob/main/docs/github-action.md' },
+ ],
+ community: [
+ { label: t.footer.linkIssues, href: 'https://github.com/macalbert/envilder/issues' },
+ { label: t.footer.linkDiscussions, href: 'https://github.com/macalbert/envilder/discussions' },
+ { label: t.footer.linkSecurity, href: 'https://github.com/macalbert/envilder/blob/main/docs/SECURITY.md' },
+ { label: t.footer.linkSponsor, href: 'https://github.com/sponsors/macalbert' },
+ ],
+};
+---
+
+
+
+
diff --git a/src/apps/website/src/components/GetStarted.astro b/src/apps/website/src/components/GetStarted.astro
new file mode 100644
index 00000000..fd845c93
--- /dev/null
+++ b/src/apps/website/src/components/GetStarted.astro
@@ -0,0 +1,228 @@
+---
+import TerminalMockup from './TerminalMockup.astro';
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.getStarted.title}{t.getStarted.titleAccent}
+
+ {t.getStarted.subtitle}
+
+
+
+
+
+
+
{t.getStarted.prerequisites}
+
+ {t.getStarted.prereqNode}
+ {t.getStarted.prereqAws} (for AWS SSM)
+ {t.getStarted.prereqAzure} (for Azure Key Vault)
+ {t.getStarted.prereqIam} ssm:GetParameter / ssm:PutParameter
+
+
+
+
+
{t.getStarted.install}
+
+
+ pnpm
+ pnpm add -g envilder
+
+
+ npm
+ npm install -g envilder
+
+
+ npx
+ npx envilder --help
+
+
+
+
+
+
{t.getStarted.quickStart}
+
+ {t.getStarted.step1}
+ {t.getStarted.step2}
+ {t.getStarted.step3}
+
+
+
+
+
+
+
+
+
+
+ $
+ npm install -g envilder
+
+
+
+
+
+
+ $
+ echo
+ {`'{"API_KEY": "/app/api-key"}' `}
+ > param-map.json
+
+
+
+
+
+
+ $
+ envilder
+ --map
+ =param-map.json
+ --envfile
+ =.env
+
+
+
+ ✔
+ {t.getStarted.doneMessage}
+
+
+
+
+
+
+ $
+ envilder
+ --push
+ --key
+ =API_KEY
+ --value
+ =sk_live_abc123
+ --secret-path
+ =/app/api-key
+
+
+
+ ✔
+ {t.getStarted.pushSuccess}
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/GitHubAction.astro b/src/apps/website/src/components/GitHubAction.astro
new file mode 100644
index 00000000..838acc5e
--- /dev/null
+++ b/src/apps/website/src/components/GitHubAction.astro
@@ -0,0 +1,182 @@
+---
+import CodeBlock from './CodeBlock.astro';
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.gha.title}
+
+ {t.gha.subtitle}
+
+
+
+
+
+
{t.gha.awsSsm}
+
+{`- name: 🪙 Configure AWS Credentials
+ uses: aws-actions/configure-aws-credentials@v6
+ with:
+ role-to-assume: \${{ secrets.AWS_ROLE_TO_ASSUME }}
+ aws-region: us-east-1
+
+- name: 🔐 Pull Secrets from AWS SSM
+ uses: macalbert/envilder/github-action@v0
+ with:
+ map-file: param-map.json
+ env-file: .env`}
+
+
+
+
+
{t.gha.azureKeyVault}
+
+{`- name: 🔑 Azure Login
+ uses: azure/login@v2
+ with:
+ client-id: \${{ secrets.AZURE_CLIENT_ID }}
+ tenant-id: \${{ secrets.AZURE_TENANT_ID }}
+ subscription-id: \${{ secrets.AZURE_SUBSCRIPTION_ID }}
+
+- name: 🔐 Pull Secrets from Azure Key Vault
+ uses: macalbert/envilder/github-action@v0
+ with:
+ map-file: param-map.json
+ env-file: .env
+ provider: azure
+ vault-url: \${{ secrets.AZURE_KEY_VAULT_URL }}`}
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/Hero.astro b/src/apps/website/src/components/Hero.astro
new file mode 100644
index 00000000..30218e57
--- /dev/null
+++ b/src/apps/website/src/components/Hero.astro
@@ -0,0 +1,209 @@
+---
+import TerminalMockup from './TerminalMockup.astro';
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
+ {t.hero.version}
+ {t.hero.openSource}
+
+
+
+ {t.hero.title1}
+ {t.hero.title2}
+ {t.hero.titleAccent}
+
+
+
+ {t.hero.description}{' '}
+ {t.hero.descAws} or {t.hero.descAzure}
+ {' '}as a single source of truth. No more copy-pasting secrets.
+
+
+
+
+
+
+ $ npm install -g envilder
+
+
+
+
+
+
+
+
+
+
+ $
+ cat
+ param-map.json
+
+
+ {'{'}
+
+
+ "DB_PASSWORD": "/app/prod/db-pass",
+
+
+ "API_KEY": "/app/prod/api-key"
+
+
+ {'}'}
+
+
+
+
+
+
+ $
+ envilder
+ --map
+ =param-map.json
+ --envfile
+ =.env
+
+
+
+ ✔
+ Fetched DB_PASSWORD → ···pass
+
+
+ ✔
+ Fetched API_KEY → ···key
+
+
+ ✔
+ Environment file written to .env
+
+
+
+ $
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/HowItWorks.astro b/src/apps/website/src/components/HowItWorks.astro
new file mode 100644
index 00000000..4dba2b8d
--- /dev/null
+++ b/src/apps/website/src/components/HowItWorks.astro
@@ -0,0 +1,187 @@
+---
+import CodeBlock from './CodeBlock.astro';
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.howItWorks.title}{t.howItWorks.titleAccent}
+
+ {t.howItWorks.subtitle}
+
+
+
+
+
+
+ 01
+
+
+
{t.howItWorks.steps[0].title}
+
+ {t.howItWorks.steps[0].description}
+
+
+{`{
+ "DB_PASSWORD": "/my-app/prod/db-password",
+ "API_KEY": "/my-app/prod/api-key",
+ "SECRET_TOKEN": "/my-app/prod/secret-token"
+}`}
+
+
+
+
+
+
+ ▼
+
+
+
+
+
+ 02
+
+
+
{t.howItWorks.steps[1].title}
+
+ {t.howItWorks.steps[1].description}
+
+
+{`$ envilder --map=param-map.json --envfile=.env
+
+✔ Fetched DB_PASSWORD → ···word
+✔ Fetched API_KEY → ···key
+✔ Fetched SECRET_TOKEN → ···oken
+✔ Environment file written to .env`}
+
+
+
+
+
+
+ ▼
+
+
+
+
+
+ 03
+
+
+
{t.howItWorks.steps[2].title}
+
+ {t.howItWorks.steps[2].description}
+
+
+{`DB_PASSWORD=my-super-secret-password
+API_KEY=sk_live_abc123def456
+SECRET_TOKEN=tok_prod_xyz789`}
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/Navbar.astro b/src/apps/website/src/components/Navbar.astro
new file mode 100644
index 00000000..b5985892
--- /dev/null
+++ b/src/apps/website/src/components/Navbar.astro
@@ -0,0 +1,222 @@
+---
+import { useTranslations, localizedPath } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+
+const navLinks = [
+ { label: t.nav.features, href: localizedPath(lang, '/#features') },
+ { label: t.nav.howItWorks, href: localizedPath(lang, '/#how-it-works') },
+ { label: t.nav.providers, href: localizedPath(lang, '/#providers') },
+ { label: t.nav.githubAction, href: localizedPath(lang, '/#github-action') },
+ { label: t.nav.changelog, href: localizedPath(lang, '/#changelog') },
+ { label: t.nav.docs, href: localizedPath(lang, '/docs') },
+];
+---
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/ProblemSolution.astro b/src/apps/website/src/components/ProblemSolution.astro
new file mode 100644
index 00000000..bf8976be
--- /dev/null
+++ b/src/apps/website/src/components/ProblemSolution.astro
@@ -0,0 +1,103 @@
+---
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.problemSolution.title}{t.problemSolution.titleAccent} with .env files
+
+ {t.problemSolution.subtitle}
+
+
+
+
+ {t.problemSolution.problems.map((p) => (
+
+
{p.icon}
+
{p.title}
+
{p.description}
+
+ ))}
+
+
+
+ {t.problemSolution.arrowText}
+
+
+
+ {t.problemSolution.solutions.map((s) => (
+
+
{s.icon}
+
{s.title}
+
{s.description}
+
+ ))}
+
+
+
+
+
diff --git a/src/apps/website/src/components/Providers.astro b/src/apps/website/src/components/Providers.astro
new file mode 100644
index 00000000..315243d2
--- /dev/null
+++ b/src/apps/website/src/components/Providers.astro
@@ -0,0 +1,234 @@
+---
+import CodeBlock from './CodeBlock.astro';
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.providers.title}{t.providers.titleAccent}
+
+ {t.providers.subtitle}
+
+
+
+
+
+
+
+
+{`{
+ "$config": {
+ "provider": "aws",
+ "profile": "prod-account"
+ },
+ "DB_PASSWORD": "/my-app/prod/db-password",
+ "API_KEY": "/my-app/prod/api-key"
+}`}
+
+
+
+
+ $ envilder --map=param-map.json --envfile=.env
+
+
+
+
+ {t.providers.awsFeatures.map((f) => (
+ ✔ {f}
+ ))}
+
+
+
+
+
+
+
+{`{
+ "$config": {
+ "provider": "azure",
+ "vaultUrl": "https://my-vault.vault.azure.net"
+ },
+ "DB_PASSWORD": "my-app-prod-db-password",
+ "API_KEY": "my-app-prod-api-key"
+}`}
+
+
+
+
+ $ envilder --provider=azure --vault-url=https://my-vault.vault.azure.net --map=param-map.json --envfile=.env
+
+
+
+
+ {t.providers.azureFeatures.map((f) => (
+ ✔ {f}
+ ))}
+
+
+
+
+
+
{t.providers.configPriorityTitle}
+
+ {t.providers.priorityHigh}
+ →
+ {t.providers.priorityMid}
+ →
+ {t.providers.priorityLow}
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/Roadmap.astro b/src/apps/website/src/components/Roadmap.astro
new file mode 100644
index 00000000..2d200697
--- /dev/null
+++ b/src/apps/website/src/components/Roadmap.astro
@@ -0,0 +1,144 @@
+---
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
{t.roadmap.title}{t.roadmap.titleAccent}
+
+ {t.roadmap.subtitle}
+
+
+
+
+ {t.roadmap.items.map((item) => (
+
+ ))}
+
+
+
+
+
diff --git a/src/apps/website/src/components/TerminalMockup.astro b/src/apps/website/src/components/TerminalMockup.astro
new file mode 100644
index 00000000..ffe87ce6
--- /dev/null
+++ b/src/apps/website/src/components/TerminalMockup.astro
@@ -0,0 +1,115 @@
+---
+export interface Props {
+ title?: string;
+}
+
+const { title = 'bash' } = Astro.props;
+---
+
+
+
+
diff --git a/src/apps/website/src/components/ThemeSwitcher.astro b/src/apps/website/src/components/ThemeSwitcher.astro
new file mode 100644
index 00000000..cd938ecd
--- /dev/null
+++ b/src/apps/website/src/components/ThemeSwitcher.astro
@@ -0,0 +1,109 @@
+---
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/components/TrustBadges.astro b/src/apps/website/src/components/TrustBadges.astro
new file mode 100644
index 00000000..3f7ccad4
--- /dev/null
+++ b/src/apps/website/src/components/TrustBadges.astro
@@ -0,0 +1,117 @@
+---
+import { useTranslations } from '../i18n/utils';
+
+interface Props {
+ lang?: string;
+}
+
+const { lang = 'en' } = Astro.props;
+const t = useTranslations(lang);
+---
+
+
+
+
{t.trust.label}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Azure Key Vault
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
GitHub Actions
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/i18n/ca.ts b/src/apps/website/src/i18n/ca.ts
new file mode 100644
index 00000000..60f528c4
--- /dev/null
+++ b/src/apps/website/src/i18n/ca.ts
@@ -0,0 +1,567 @@
+import type { Translations } from './types';
+
+export const ca: Translations = {
+ nav: {
+ features: 'Funcionalitats',
+ howItWorks: 'Com funciona',
+ providers: 'Proveïdors',
+ githubAction: 'GitHub Action',
+ changelog: 'Canvis',
+ docs: 'Docs',
+ getStarted: 'Comença',
+ },
+ theme: {
+ retro: 'Retro',
+ light: 'Clar',
+ },
+ hero: {
+ version: 'v0.8.0',
+ openSource: 'Codi obert · MIT',
+ title1: 'Els teus secrets.',
+ title2: 'Una comanda.',
+ titleAccent: 'Cada entorn.',
+ description:
+ 'Una eina CLI i GitHub Action que centralitza de forma segura les teves variables d\'entorn des de',
+ descAws: 'AWS SSM',
+ descAzure: 'Azure Key Vault',
+ getStarted: '▶ Comença',
+ viewOnGithub: '★ Veure a GitHub',
+ },
+ trust: {
+ label: 'COMPATIBLE AMB',
+ },
+ problemSolution: {
+ title: 'El ',
+ titleAccent: 'problema',
+ subtitle:
+ 'Gestionar secrets manualment no escala. És insegur, propens a errors i crea fricció per a tot l\'equip.',
+ problems: [
+ {
+ icon: '💀',
+ title: 'Desincronització entre entorns',
+ description:
+ 'Dev, staging i prod tenen secrets diferents. Els desplegaments fallen. Ningú sap quin .env és el correcte.',
+ },
+ {
+ icon: '📨',
+ title: 'Secrets compartits per Slack/email',
+ description:
+ 'Claus API enviades en text pla per xat. Sense traçabilitat. Sense rotació. Un incident de seguretat esperant a passar.',
+ },
+ {
+ icon: '🐌',
+ title: 'Onboarding i rotacions lentes',
+ description:
+ 'Un nou membre s\'uneix a l\'equip? Copia i enganxa un .env de la màquina d\'algú. Algú rota? Espera que tothom actualitzi manualment.',
+ },
+ ],
+ arrowText: '▼ envilder ho soluciona ▼',
+ solutions: [
+ {
+ icon: '🛡️',
+ title: 'Font de veritat al núvol',
+ description:
+ 'Tots els secrets viuen a AWS SSM o Azure Key Vault. IAM/RBAC controla qui pot llegir què. Cada accés queda registrat.',
+ },
+ {
+ icon: '⚡',
+ title: 'Una comanda, sempre sincronitzat',
+ description:
+ 'Executa envilder i el teu .env es regenera des de la font de veritat. Idempotent. Instantani. Sense marge per al desfasament.',
+ },
+ {
+ icon: '🤖',
+ title: 'Automatitzat en CI/CD',
+ description:
+ 'Utilitza la GitHub Action per obtenir secrets en el moment del desplegament. Sense secrets als repos. Sense passos manuals als pipelines.',
+ },
+ ],
+ },
+ howItWorks: {
+ title: 'Com ',
+ titleAccent: 'funciona',
+ subtitle:
+ 'Tres passos. De secrets dispersos a una única font de veritat.',
+ steps: [
+ {
+ title: 'Crea un fitxer de mapeig',
+ description:
+ 'Mapeja els noms de les teves variables d\'entorn a les seves rutes de secrets a AWS SSM o Azure Key Vault.',
+ },
+ {
+ title: 'Executa una comanda',
+ description:
+ 'Envilder obté cada secret del teu proveïdor al núvol i els escriu en un fitxer .env local. Idempotent i instantani.',
+ },
+ {
+ title: 'El teu .env està llest',
+ description:
+ 'Un fitxer d\'entorn net i actualitzat — generat des de la font de veritat. Utilitza\'l localment o injecta\'l en CI/CD amb la GitHub Action.',
+ },
+ ],
+ },
+ features: {
+ title: 'Fet per a ',
+ titleAccent: 'equips reals',
+ subtitle:
+ 'Tot el que necessites per gestionar secrets d\'entorn de forma segura i a escala.',
+ features: [
+ {
+ icon: '☁️',
+ title: 'Multi-Proveïdor',
+ description:
+ 'AWS SSM Parameter Store i Azure Key Vault. Tria amb --provider o $config al fitxer de mapeig.',
+ },
+ {
+ icon: '🔄',
+ title: 'Sincronització bidireccional',
+ description:
+ 'Obté secrets a fitxers .env o puja valors .env al teu proveïdor al núvol. Suport complet d\'anada i tornada.',
+ },
+ {
+ icon: '⚙️',
+ title: 'GitHub Action',
+ description:
+ 'Action per als teus workflows CI/CD. Obté secrets en el moment del desplegament sense intervenció manual.',
+ },
+ {
+ icon: '🔒',
+ title: 'Accés IAM i RBAC',
+ description:
+ 'Aprofita el control d\'accés natiu del núvol. Les polítiques IAM d\'AWS o RBAC d\'Azure defineixen qui llegeix què, per entorn.',
+ },
+ {
+ icon: '📊',
+ title: 'Totalment auditable',
+ description:
+ 'Cada lectura i escriptura queda registrada a AWS CloudTrail o Azure Monitor. Traçabilitat completa de qui ha accedit a què i quan.',
+ },
+ {
+ icon: '🔁',
+ title: 'Sincronització idempotent',
+ description:
+ 'Només s\'actualitza el que hi ha al teu mapeig. Res més es toca. Executa\'l deu vegades — mateix resultat, zero efectes secundaris.',
+ },
+ {
+ icon: '🧱',
+ title: 'Zero infraestructura',
+ description:
+ 'Construït sobre serveis natius del núvol. Sense Lambdas, sense servidors, sense infraestructura extra per gestionar o pagar.',
+ },
+ {
+ icon: '👤',
+ title: 'Suport de perfils AWS',
+ description:
+ 'Configuració multi-compte? Utilitza --profile per canviar entre perfils AWS CLI. Perfecte per a entorns multi-etapa.',
+ },
+ ],
+ },
+ demo: {
+ title: 'Mira\'l en ',
+ titleAccent: 'acció',
+ subtitle:
+ 'Mira com Envilder simplifica la gestió de secrets en menys de 2 minuts.',
+ cliDemo: 'Demo CLI — Obtenir Secrets',
+ ghaWorkflow: 'Workflow de GitHub Action',
+ comingSoon: 'Properament',
+ },
+ providers: {
+ title: 'El teu núvol. ',
+ titleAccent: 'La teva elecció.',
+ subtitle:
+ 'Envilder funciona amb AWS SSM Parameter Store i Azure Key Vault. Configura en línia o amb flags CLI.',
+ awsTitle: 'AWS SSM Parameter Store',
+ awsDefault: 'Proveïdor per defecte',
+ awsFeatures: [
+ 'Suport de GetParameter amb WithDecryption',
+ 'Suport de perfil AWS per a multi-compte',
+ 'Control d\'accés basat en polítiques IAM',
+ 'Registre d\'auditoria CloudTrail',
+ ],
+ azureTitle: 'Azure Key Vault',
+ azureFeatures: [
+ 'Auto-normalitza noms de secrets (barres → guions)',
+ 'Autenticació DefaultAzureCredential',
+ 'Control d\'accés Azure RBAC',
+ 'Registre d\'auditoria Azure Monitor',
+ ],
+ configPriorityTitle: 'Prioritat de configuració',
+ priorityHigh: 'Flags CLI / Inputs GHA',
+ priorityMid: '$config al fitxer de mapeig',
+ priorityLow: 'Per defecte (AWS)',
+ },
+ gha: {
+ title: 'GitHub Action',
+ subtitle:
+ 'Obté secrets en el moment del desplegament. Afegeix-lo a qualsevol workflow en minuts.',
+ awsSsm: '☁️ AWS SSM',
+ azureKeyVault: '🔑 Azure Key Vault',
+ actionInputs: 'Inputs de l\'Action',
+ thInput: 'Input',
+ thRequired: 'Requerit',
+ thDefault: 'Per defecte',
+ thDescription: 'Descripció',
+ inputMapDesc:
+ 'Ruta al fitxer JSON que mapeja variables d\'entorn a rutes de secrets',
+ inputEnvDesc: 'Ruta al fitxer .env a generar',
+ inputProviderDesc: 'Proveïdor al núvol: aws o azure',
+ inputVaultDesc: 'URL d\'Azure Key Vault',
+ output: 'Output:',
+ outputDesc: 'Ruta al fitxer .env generat',
+ },
+ changelog: {
+ title: 'Què hi ha de ',
+ titleAccent: 'nou',
+ subtitle:
+ 'Novetats de l\'última versió. El suport multi-proveïdor ja és aquí.',
+ releaseTitle: 'Suport Multi-Proveïdor',
+ highlights: [
+ {
+ icon: '✨',
+ text: 'Secció $config als fitxers de mapeig — declara proveïdor i detalls de connexió en línia',
+ },
+ {
+ icon: '✨',
+ text: 'Suport d\'Azure Key Vault — paritat completa amb AWS SSM',
+ },
+ { icon: '✨', text: 'Flags CLI --vault-url i --provider' },
+ {
+ icon: '✨',
+ text: 'Normalització automàtica de noms de secrets per Azure (barres → guions)',
+ },
+ {
+ icon: '⚠️',
+ text: 'Canvi incompatible: --ssm-path reanomenat a --secret-path (l\'antic flag encara funciona com a àlies obsolet)',
+ },
+ ],
+ fullChangelog: '📋 Historial complet',
+ viewReleases: 'Veure totes les versions a GitHub →',
+ },
+ roadmap: {
+ title: 'Què ve ',
+ titleAccent: 'ara',
+ subtitle:
+ 'Envilder es desenvolupa activament. Aquí és cap on anem.',
+ upNext: 'Pròximament',
+ items: [
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Resolució basada en mapeig',
+ description:
+ 'Mapeja noms de variables d\'entorn a rutes de secrets al núvol via JSON',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Generació de fitxers .env',
+ description:
+ 'Genera fitxers .env des de secrets del proveïdor al núvol',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Mode push (--push)',
+ description:
+ 'Puja valors .env o secrets individuals al proveïdor al núvol',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'GitHub Action',
+ description:
+ 'Utilitza Envilder en workflows CI/CD de forma nativa',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Multi-proveïdor (AWS + Azure)',
+ description:
+ 'Suport d\'AWS SSM Parameter Store i Azure Key Vault',
+ },
+ {
+ status: 'next',
+ label: '⚡',
+ title: 'Mode exec (--exec)',
+ description:
+ 'Injecta secrets en un procés fill sense escriure a disc',
+ },
+ {
+ status: 'next',
+ label: '🔍',
+ title: 'Mode check/sync (--check)',
+ description:
+ 'Valida SSM vs .env, falla CI si estan desincronitzats',
+ },
+ {
+ status: 'planned',
+ label: '📖',
+ title: 'Web de documentació',
+ description:
+ 'Web de docs dedicada amb guies, exemples i referència API',
+ },
+ {
+ status: 'planned',
+ label: '🤖',
+ title: 'Mode auto-descobriment (--auto)',
+ description:
+ 'Obté tots els paràmetres amb un prefix donat automàticament',
+ },
+ ],
+ },
+ getStarted: {
+ title: 'Comença ',
+ titleAccent: 'ara',
+ subtitle: 'En funcionament en menys d\'un minut.',
+ prerequisites: 'Prerequisits',
+ prereqNode: 'Node.js v20+',
+ prereqAws: 'AWS CLI configurat',
+ prereqAzure: 'Azure CLI configurat',
+ prereqIam: 'Permisos IAM:',
+ install: 'Instal·lar',
+ quickStart: 'Inici ràpid',
+ step1: 'Crea un param-map.json que mapegi variables d\'entorn a rutes de secrets',
+ step2: 'Executa envilder --map=param-map.json --envfile=.env',
+ step3: 'El teu fitxer .env està llest ✔',
+ terminalTitle: 'Inici ràpid',
+ commentInstall: '# Instal·lar globalment',
+ commentCreate: '# Crear fitxer de mapeig',
+ commentPull: '# Obtenir secrets',
+ commentPush: '# Pujar un secret',
+ doneMessage: ' Fet! Fitxer .env generat.',
+ pushSuccess: ' Secret pujat correctament.',
+ },
+ footer: {
+ tagline:
+ 'Centralitza de forma segura les teves variables d\'entorn des d\'AWS SSM o Azure Key Vault.',
+ project: 'Projecte',
+ documentation: 'Documentació',
+ community: 'Comunitat',
+ linkGithub: 'GitHub',
+ linkNpm: 'npm',
+ linkChangelog: 'Canvis',
+ linkRoadmap: 'Full de ruta',
+ linkGettingStarted: 'Comença',
+ linkPullCommand: 'Comanda Pull',
+ linkPushCommand: 'Comanda Push',
+ linkGithubAction: 'GitHub Action',
+ linkIssues: 'Incidències',
+ linkDiscussions: 'Discussions',
+ linkSecurity: 'Seguretat',
+ linkSponsor: 'Patrocina',
+ copyright: 'Fet amb Astro. Codi obert a GitHub.',
+ builtWith: 'Fet amb Astro. Codi obert a GitHub.',
+ },
+ changelogPage: {
+ title: 'Historial de canvis — Envilder',
+ backToHome: '← Tornar a l\'inici',
+ fullChangelog: 'Historial de ',
+ changelogAccent: 'canvis',
+ intro: 'Historial complet de versions. Vegeu també',
+ githubReleases: 'Versions a GitHub',
+ },
+ docs: {
+ title: 'Documentació — Envilder',
+ backToHome: '← Tornar a l\'inici',
+ pageTitle: 'Documentació',
+ intro: 'Tot el que necessites per començar amb Envilder.',
+ sidebarGettingStarted: 'Primers passos',
+ sidebarRequirements: 'Requisits',
+ sidebarInstallation: 'Instal·lació',
+ sidebarCredentials: 'Credencials del núvol',
+ sidebarPermissions: 'Permisos IAM',
+ sidebarCli: 'CLI',
+ sidebarMappingFile: 'Fitxer de mapeig',
+ sidebarPullCommand: 'Comanda pull',
+ sidebarPushCommand: 'Comanda push',
+ sidebarPushSingle: 'Push individual',
+ sidebarGha: 'GitHub Action',
+ sidebarGhaSetup: 'Configuració',
+ sidebarGhaBasic: 'Exemple bàsic',
+ sidebarGhaMultiEnv: 'Multi-entorn',
+ sidebarGhaAzure: 'Exemple Azure',
+ sidebarGhaInputs: 'Inputs i outputs',
+ sidebarReference: 'Referència',
+ sidebarConfigPriority: 'Prioritat de config',
+ sidebarAzureSetup: 'Configuració Azure',
+ reqTitle: 'Requisits',
+ reqNode: 'Node.js v20+',
+ reqAws: 'AWS CLI',
+ reqAzure: 'Azure CLI',
+ reqDownload: 'Descarregar',
+ reqInstallGuide: 'Guia d\'instal·lació',
+ installTitle: 'Instal·lació',
+ credTitle: 'Credencials del núvol',
+ credAwsTitle: 'AWS (per defecte)',
+ credAwsDesc:
+ 'Envilder utilitza les teves credencials AWS CLI. Configura el perfil per defecte:',
+ credAwsProfile: 'O utilitza un perfil amb nom:',
+ credAzureTitle: 'Azure Key Vault',
+ credAzureDesc:
+ 'Envilder utilitza Azure Default Credentials. Inicia sessió amb:',
+ credAzureVault:
+ 'Proporciona l\'URL del vault via $config al fitxer de mapeig o el flag --vault-url.',
+ permTitle: 'Permisos IAM',
+ permAwsTitle: 'AWS',
+ permAwsDesc: 'El teu usuari o rol IAM necessita:',
+ permOperation: 'Operació',
+ permPermission: 'Permís',
+ permPull: 'Pull',
+ permPush: 'Push',
+ permPolicyExample: 'Exemple de política IAM:',
+ permAzureTitle: 'Azure',
+ permAzureRbac:
+ 'Recomanat — assigna Key Vault Secrets Officer via RBAC:',
+ permAzurePullNote:
+ 'Per accés només de lectura, Key Vault Secrets User és suficient.',
+ mapTitle: 'Fitxer de mapeig',
+ mapIntro:
+ 'El fitxer de mapeig (param-map.json) és el nucli d\'Envilder. És un fitxer JSON que mapeja noms de variables d\'entorn (claus) a rutes de secrets (valors) al teu proveïdor al núvol.',
+ mapCalloutStructure: 'Estructura:',
+ mapCalloutKey:
+ 'Cada clau es converteix en un nom de variable d\'entorn al teu fitxer .env.',
+ mapCalloutValue:
+ 'Cada valor és la ruta on viu el secret al teu proveïdor al núvol.',
+ mapBasicTitle: 'Format bàsic (AWS SSM — per defecte)',
+ mapBasicDesc:
+ 'Quan no hi ha secció $config, Envilder utilitza AWS SSM Parameter Store per defecte. Els valors han de ser rutes de paràmetres SSM vàlides (normalment començant amb /):',
+ mapBasicGenerates: 'Això genera:',
+ mapConfigTitle: 'La secció $config',
+ mapConfigDesc:
+ 'Afegeix una clau $config al teu fitxer de mapeig per declarar quin proveïdor al núvol utilitzar i la seva configuració. Envilder llegeix $config per la configuració i tracta totes les altres claus com a mapeigs de secrets.',
+ mapConfigOptionsTitle: 'Opcions de $config',
+ mapThKey: 'Clau',
+ mapThType: 'Tipus',
+ mapThDefault: 'Per defecte',
+ mapThDescription: 'Descripció',
+ mapProviderDesc: 'Proveïdor al núvol a utilitzar',
+ mapVaultUrlDesc:
+ 'URL d\'Azure Key Vault (requerit quan el proveïdor és "azure")',
+ mapProfileDesc:
+ 'Perfil AWS CLI per a configuracions multi-compte (només AWS)',
+ mapAwsProfileTitle: 'AWS SSM amb perfil',
+ mapAwsProfileDesc:
+ 'Per utilitzar un perfil AWS CLI específic (útil per a configuracions multi-compte), afegeix profile a $config:',
+ mapAwsProfileExplain:
+ 'Això indica a Envilder que utilitzi el perfil prod-account del teu fitxer ~/.aws/credentials en lloc del perfil per defecte.',
+ mapAzureTitle: 'Azure Key Vault',
+ mapAzureDesc:
+ 'Per Azure Key Vault, estableix provider a "azure" i proporciona el vaultUrl:',
+ mapAzureWarningTitle: 'Convenció de noms Azure:',
+ mapAzureWarningDesc:
+ 'Els noms de secrets de Key Vault només permeten caràcters alfanumèrics i guions. Envilder normalitza automàticament els noms — barres i guions baixos es converteixen en guions (p. ex., /myapp/db/password → myapp-db-password).',
+ mapDifferencesTitle: 'Diferències clau per proveïdor',
+ mapThEmpty: '',
+ mapThAwsSsm: 'AWS SSM',
+ mapThAzureKv: 'Azure Key Vault',
+ mapSecretPathFormat: 'Format de ruta de secret',
+ mapAwsPathFormat: 'Rutes de paràmetres amb barres',
+ mapAzurePathFormat: 'Noms amb guions',
+ mapRequiredConfig: '$config requerit',
+ mapAwsRequiredConfig: 'Cap (AWS és per defecte)',
+ mapAzureRequiredConfig: 'provider + vaultUrl',
+ mapOptionalConfig: '$config opcional',
+ mapAuthentication: 'Autenticació',
+ mapAwsAuth: 'Credencials AWS CLI',
+ mapAzureAuth: 'Azure Default Credentials',
+ mapMultiEnvTitle: 'Múltiples entorns',
+ mapMultiEnvDesc:
+ 'Un patró comú és tenir un fitxer de mapeig per entorn. L\'estructura és la mateixa, només canvien les rutes dels secrets:',
+ mapMultiEnvThenPull: 'Després obté el correcte:',
+ mapOverrideTitle: 'Sobreescriure $config amb flags CLI',
+ mapOverrideDesc:
+ 'Els flags CLI sempre tenen prioritat sobre els valors de $config. Això et permet establir valors per defecte al fitxer i sobreescriure\'ls per invocació:',
+ mapOverrideComment1: '# Utilitza $config del fitxer de mapeig tal qual',
+ mapOverrideComment2:
+ '# Sobreescriu proveïdor i URL del vault, ignorant $config',
+ mapOverrideComment3: '# Sobreescriu només el perfil AWS',
+ mapPriorityNote:
+ 'Ordre de prioritat: flags CLI / inputs GHA → $config al fitxer de mapeig → per defecte (AWS).',
+ pullTitle: 'Comanda pull',
+ pullDesc:
+ 'Descarrega secrets del teu proveïdor al núvol i genera un fitxer .env local.',
+ pullOptions: 'Opcions',
+ pullExamples: 'Exemples',
+ pullOutput: 'Sortida',
+ pullOptMap: 'Ruta al fitxer JSON de mapeig',
+ pullOptEnv: 'Ruta on escriure el .env',
+ pullOptProvider: 'aws (per defecte) o azure',
+ pullOptVault: 'URL d\'Azure Key Vault',
+ pullOptProfile: 'Perfil AWS CLI a utilitzar',
+ pullCommentDefault: '# Per defecte (AWS SSM)',
+ pullCommentProfile: '# Amb perfil AWS',
+ pullCommentAzureConfig: '# Azure via $config al fitxer de mapeig',
+ pullCommentAzureFlags: '# Azure via flags CLI',
+ pushTitle: 'Comanda push',
+ pushDesc:
+ 'Puja variables d\'entorn d\'un fitxer .env local al teu proveïdor al núvol utilitzant un fitxer de mapeig.',
+ pushOptions: 'Opcions',
+ pushExamples: 'Exemples',
+ pushOptPush: 'Activa el mode push (requerit)',
+ pushOptEnv: 'Ruta al teu fitxer .env local',
+ pushOptMap: 'Ruta al JSON de mapeig de paràmetres',
+ pushOptProvider: 'aws (per defecte) o azure',
+ pushOptVault: 'URL d\'Azure Key Vault',
+ pushOptProfile: 'Perfil AWS CLI (només AWS)',
+ pushCommentAws: '# Pujar a AWS SSM',
+ pushCommentProfile: '# Amb perfil AWS',
+ pushCommentAzureConfig: '# Azure via $config al fitxer de mapeig',
+ pushCommentAzureFlags: '# Azure via flags CLI',
+ pushSingleTitle: 'Pujar variable individual',
+ pushSingleDesc:
+ 'Puja una variable d\'entorn individual directament sense cap fitxer.',
+ pushSingleOptions: 'Opcions',
+ pushSingleOptPush: 'Activa el mode push (requerit)',
+ pushSingleOptKey: 'Nom de la variable d\'entorn',
+ pushSingleOptValue: 'Valor a emmagatzemar',
+ pushSingleOptPath: 'Ruta completa del secret al teu proveïdor al núvol',
+ pushSingleOptProvider: 'aws (per defecte) o azure',
+ pushSingleOptVault: 'URL d\'Azure Key Vault',
+ pushSingleOptProfile: 'Perfil AWS CLI (només AWS)',
+ ghaSetupTitle: 'Configuració de GitHub Action',
+ ghaSetupDesc:
+ 'La GitHub Action d\'Envilder obté secrets d\'AWS SSM o Azure Key Vault en fitxers .env durant el teu workflow CI/CD. No cal compilar — l\'action està pre-construïda i llesta per utilitzar des de GitHub Marketplace.',
+ ghaPrerequisites: 'Prerequisits',
+ ghaPrereqAws:
+ 'AWS: Configura credencials amb aws-actions/configure-aws-credentials',
+ ghaPrereqAzure: 'Azure: Configura credencials amb azure/login',
+ ghaPrereqMap: 'Un param-map.json al teu repositori',
+ ghaPullOnly:
+ 'La GitHub Action només suporta el mode pull (sense push).',
+ ghaBasicTitle: 'Exemple bàsic de workflow',
+ ghaMultiEnvTitle: 'Workflow multi-entorn',
+ ghaAzureTitle: 'Workflow d\'Azure Key Vault',
+ ghaInputsTitle: 'Inputs i outputs de l\'Action',
+ ghaInputsSubtitle: 'Inputs',
+ ghaOutputsSubtitle: 'Outputs',
+ ghaInputRequired: 'Requerit',
+ ghaInputDefault: 'Per defecte',
+ ghaInputDesc: 'Descripció',
+ ghaOutputEnvPath: 'Ruta al fitxer .env generat',
+ ghaThInput: 'Input',
+ ghaThRequired: 'Requerit',
+ ghaThOutput: 'Output',
+ ghaYes: 'Sí',
+ ghaNo: 'No',
+ ghaInputMap: 'Ruta al fitxer JSON de mapatge',
+ ghaInputEnv: 'Ruta al fitxer .env a generar',
+ ghaInputProvider: 'aws o azure',
+ ghaInputVault: 'URL d\'Azure Key Vault',
+ configPriorityTitle: 'Prioritat de configuració',
+ configPriorityDesc:
+ 'Quan hi ha múltiples fonts de configuració, Envilder les resol en aquest ordre (el més alt guanya):',
+ configPriority1: 'Flags CLI / inputs GHA',
+ configPriority2: '$config al fitxer de mapatge',
+ configPriority3: 'Per defecte (AWS)',
+ configPriorityExplain:
+ 'Això vol dir que --provider=azure a la CLI sobreescriurà "provider": "aws" a $config.',
+ azureSetupTitle: 'Configuració d\'Azure Key Vault',
+ azureSetupCheck: 'Comprova quin model d\'accés utilitza el teu vault:',
+ azureRbacTrue: 'true → Azure RBAC (recomanat)',
+ azureRbacFalse: 'false / null → Vault Access Policy (clàssic)',
+ azureOptionA: 'Opció A — Azure RBAC (recomanat)',
+ azureOptionB: 'Opció B — Vault Access Policy',
+ azureAccessNote:
+ 'Per accés només de lectura, get list és suficient. Afegeix set per push.',
+ },
+};
diff --git a/src/apps/website/src/i18n/en.ts b/src/apps/website/src/i18n/en.ts
new file mode 100644
index 00000000..d92644fd
--- /dev/null
+++ b/src/apps/website/src/i18n/en.ts
@@ -0,0 +1,558 @@
+import type { Translations } from './types';
+
+export const en: Translations = {
+ nav: {
+ features: 'Features',
+ howItWorks: 'How it works',
+ providers: 'Providers',
+ githubAction: 'GitHub Action',
+ changelog: 'Changelog',
+ docs: 'Docs',
+ getStarted: 'Get Started',
+ },
+ theme: {
+ retro: 'Retro',
+ light: 'Light',
+ },
+ hero: {
+ version: 'v0.8.0',
+ openSource: 'Open Source · MIT',
+ title1: 'Your secrets.',
+ title2: 'One command.',
+ titleAccent: 'Every environment.',
+ description:
+ 'A CLI tool and GitHub Action that securely centralizes your environment variables from',
+ descAws: 'AWS SSM',
+ descAzure: 'Azure Key Vault',
+ getStarted: '▶ Get Started',
+ viewOnGithub: '★ View on GitHub',
+ },
+ trust: {
+ label: 'WORKS WITH',
+ },
+ problemSolution: {
+ title: 'The ',
+ titleAccent: 'problem',
+ subtitle:
+ "Managing secrets manually doesn't scale. It's insecure, error-prone, and creates friction for your entire team.",
+ problems: [
+ {
+ icon: '💀',
+ title: 'Desync between environments',
+ description:
+ 'Dev, staging, and prod have different secrets. Deployments fail. Nobody knows which .env is correct.',
+ },
+ {
+ icon: '📨',
+ title: 'Secrets shared via Slack/email',
+ description:
+ 'API keys sent in plain text over chat. No audit trail. No rotation. A security incident waiting to happen.',
+ },
+ {
+ icon: '🐌',
+ title: 'Slow onboarding & rotations',
+ description:
+ "New team member joins? Copy-paste a .env from somebody's machine. Someone rotates? Hope everyone updates manually.",
+ },
+ ],
+ arrowText: '▼ envilder fixes this ▼',
+ solutions: [
+ {
+ icon: '🛡️',
+ title: 'Cloud-native source of truth',
+ description:
+ 'All secrets live in AWS SSM or Azure Key Vault. IAM/RBAC controls who can read what. Every access is logged.',
+ },
+ {
+ icon: '⚡',
+ title: 'One command, always in sync',
+ description:
+ 'Run envilder and your .env is regenerated from the source of truth. Idempotent. Instant. No room for drift.',
+ },
+ {
+ icon: '🤖',
+ title: 'Automated in CI/CD',
+ description:
+ 'Use the GitHub Action to pull secrets at deploy time. No secrets stored in repos. No manual steps in pipelines.',
+ },
+ ],
+ },
+ howItWorks: {
+ title: 'How it ',
+ titleAccent: 'works',
+ subtitle:
+ 'Three steps. From scattered secrets to a single source of truth.',
+ steps: [
+ {
+ title: 'Create a mapping file',
+ description:
+ 'Map your environment variable names to their secret paths in AWS SSM or Azure Key Vault.',
+ },
+ {
+ title: 'Run one command',
+ description:
+ 'Envilder pulls each secret from your cloud provider and writes them to a local .env file. Idempotent and instant.',
+ },
+ {
+ title: 'Your .env is ready',
+ description:
+ 'A clean, up-to-date environment file — generated from the source of truth. Use it locally or inject it in CI/CD with the GitHub Action.',
+ },
+ ],
+ },
+ features: {
+ title: 'Built for ',
+ titleAccent: 'real teams',
+ subtitle:
+ 'Everything you need to manage environment secrets securely and at scale.',
+ features: [
+ {
+ icon: '☁️',
+ title: 'Multi-Provider',
+ description:
+ 'AWS SSM Parameter Store and Azure Key Vault. Choose with --provider or $config in your map file.',
+ },
+ {
+ icon: '🔄',
+ title: 'Bidirectional Sync',
+ description:
+ 'Pull secrets to .env files or push .env values back to your cloud provider. Full round-trip support.',
+ },
+ {
+ icon: '⚙️',
+ title: 'GitHub Action',
+ description:
+ 'Drop-in Action for your CI/CD workflows. Pull secrets at deploy time with zero manual intervention.',
+ },
+ {
+ icon: '🔒',
+ title: 'IAM & RBAC Access',
+ description:
+ 'Leverage native cloud access control. AWS IAM policies or Azure RBAC define who reads what, per environment.',
+ },
+ {
+ icon: '📊',
+ title: 'Fully Auditable',
+ description:
+ 'Every read and write is logged in AWS CloudTrail or Azure Monitor. Complete trace of who accessed what and when.',
+ },
+ {
+ icon: '🔁',
+ title: 'Idempotent Sync',
+ description:
+ "Only what's in your mapping gets updated. Nothing else is touched. Run it ten times — same result, zero side effects.",
+ },
+ {
+ icon: '🧱',
+ title: 'Zero Infrastructure',
+ description:
+ 'Built on native cloud services. No Lambdas, no servers, no extra infrastructure to manage or pay for.',
+ },
+ {
+ icon: '👤',
+ title: 'AWS Profile Support',
+ description:
+ 'Multi-account setups? Use --profile to switch between AWS CLI profiles. Perfect for multi-stage environments.',
+ },
+ ],
+ },
+ demo: {
+ title: 'See it in ',
+ titleAccent: 'action',
+ subtitle:
+ 'Watch how Envilder simplifies secret management in under 2 minutes.',
+ cliDemo: 'CLI Demo — Pull Secrets',
+ ghaWorkflow: 'GitHub Action Workflow',
+ comingSoon: 'Coming soon',
+ },
+ providers: {
+ title: 'Your cloud. ',
+ titleAccent: 'Your choice.',
+ subtitle:
+ 'Envilder works with AWS SSM Parameter Store and Azure Key Vault. Configure inline or via CLI flags.',
+ awsTitle: 'AWS SSM Parameter Store',
+ awsDefault: 'Default provider',
+ awsFeatures: [
+ 'Supports GetParameter with WithDecryption',
+ 'AWS Profile support for multi-account',
+ 'IAM policy-based access control',
+ 'CloudTrail audit logging',
+ ],
+ azureTitle: 'Azure Key Vault',
+ azureFeatures: [
+ 'Auto-normalizes secret names (slashes → hyphens)',
+ 'DefaultAzureCredential authentication',
+ 'Azure RBAC access control',
+ 'Azure Monitor audit logging',
+ ],
+ configPriorityTitle: 'Configuration priority',
+ priorityHigh: 'CLI flags / GHA inputs',
+ priorityMid: '$config in map file',
+ priorityLow: 'Defaults (AWS)',
+ },
+ gha: {
+ title: 'GitHub Action',
+ subtitle:
+ 'Pull secrets at deploy time. Drop it into any workflow in minutes.',
+ awsSsm: '☁️ AWS SSM',
+ azureKeyVault: '🔑 Azure Key Vault',
+ actionInputs: 'Action inputs',
+ thInput: 'Input',
+ thRequired: 'Required',
+ thDefault: 'Default',
+ thDescription: 'Description',
+ inputMapDesc: 'Path to JSON file mapping env vars to secret paths',
+ inputEnvDesc: 'Path to .env file to generate',
+ inputProviderDesc: 'Cloud provider: aws or azure',
+ inputVaultDesc: 'Azure Key Vault URL',
+ output: 'Output:',
+ outputDesc: 'Path to the generated .env file',
+ },
+ changelog: {
+ title: "What's ",
+ titleAccent: 'new',
+ subtitle: 'Latest release highlights. Multi-provider support is here.',
+ releaseTitle: 'Multi-Provider Support',
+ highlights: [
+ {
+ icon: '✨',
+ text: '$config section in map files — declare provider and connection details inline',
+ },
+ {
+ icon: '✨',
+ text: 'Azure Key Vault support — full parity with AWS SSM',
+ },
+ { icon: '✨', text: '--vault-url and --provider CLI flags' },
+ {
+ icon: '✨',
+ text: 'Automatic secret name normalization for Azure (slashes → hyphens)',
+ },
+ {
+ icon: '⚠️',
+ text: 'Breaking: --ssm-path renamed to --secret-path (old flag still works as deprecated alias)',
+ },
+ ],
+ fullChangelog: '📋 Full Changelog',
+ viewReleases: 'View all releases on GitHub →',
+ },
+ roadmap: {
+ title: "What's ",
+ titleAccent: 'next',
+ subtitle: "Envilder is actively developed. Here's where we're headed.",
+ upNext: 'Up next',
+ items: [
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Mapping-based resolution',
+ description: 'Map env var names to cloud secret paths via JSON',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: '.env file generation',
+ description: 'Generate .env files from cloud provider secrets',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Push mode (--push)',
+ description:
+ 'Upload .env values or single secrets to cloud provider',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'GitHub Action',
+ description: 'Use Envilder in CI/CD workflows natively',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Multi-provider (AWS + Azure)',
+ description: 'AWS SSM Parameter Store and Azure Key Vault support',
+ },
+ {
+ status: 'next',
+ label: '⚡',
+ title: 'Exec mode (--exec)',
+ description:
+ 'Inject secrets into child process without writing to disk',
+ },
+ {
+ status: 'next',
+ label: '🔍',
+ title: 'Check/sync mode (--check)',
+ description: 'Validate SSM vs .env, fail CI if out-of-sync',
+ },
+ {
+ status: 'planned',
+ label: '📖',
+ title: 'Documentation website',
+ description:
+ 'Dedicated docs site with guides, examples, API reference',
+ },
+ {
+ status: 'planned',
+ label: '🤖',
+ title: 'Auto-discovery mode (--auto)',
+ description:
+ 'Fetch all parameters with a given prefix automatically',
+ },
+ ],
+ },
+ getStarted: {
+ title: 'Get ',
+ titleAccent: 'started',
+ subtitle: 'Up and running in under a minute.',
+ prerequisites: 'Prerequisites',
+ prereqNode: 'Node.js v20+',
+ prereqAws: 'AWS CLI configured',
+ prereqAzure: 'Azure CLI configured',
+ prereqIam: 'IAM permissions:',
+ install: 'Install',
+ quickStart: 'Quick start',
+ step1: 'Create a param-map.json mapping env vars to secret paths',
+ step2: 'Run envilder --map=param-map.json --envfile=.env',
+ step3: 'Your .env file is ready ✔',
+ terminalTitle: 'Quick start',
+ commentInstall: '# Install globally',
+ commentCreate: '# Create mapping file',
+ commentPull: '# Pull secrets',
+ commentPush: '# Push a secret',
+ doneMessage: ' Done! .env file generated.',
+ pushSuccess: ' Secret pushed successfully.',
+ },
+ footer: {
+ tagline:
+ 'Securely centralize your environment variables from AWS SSM or Azure Key Vault.',
+ project: 'Project',
+ documentation: 'Documentation',
+ community: 'Community',
+ linkGithub: 'GitHub',
+ linkNpm: 'npm',
+ linkChangelog: 'Changelog',
+ linkRoadmap: 'Roadmap',
+ linkGettingStarted: 'Getting Started',
+ linkPullCommand: 'Pull Command',
+ linkPushCommand: 'Push Command',
+ linkGithubAction: 'GitHub Action',
+ linkIssues: 'Issues',
+ linkDiscussions: 'Discussions',
+ linkSecurity: 'Security',
+ linkSponsor: 'Sponsor',
+ copyright: 'Built with Astro. Open source on GitHub.',
+ builtWith: 'Built with Astro. Open source on GitHub.',
+ },
+ changelogPage: {
+ title: 'Changelog — Envilder',
+ backToHome: '← Back to home',
+ fullChangelog: 'Full ',
+ changelogAccent: 'Changelog',
+ intro: 'Complete release history. See also',
+ githubReleases: 'GitHub Releases',
+ },
+ docs: {
+ title: 'Documentation — Envilder',
+ backToHome: '← Back to home',
+ pageTitle: 'Documentation',
+ intro: 'Everything you need to get started with Envilder.',
+ sidebarGettingStarted: 'Getting started',
+ sidebarRequirements: 'Requirements',
+ sidebarInstallation: 'Installation',
+ sidebarCredentials: 'Cloud credentials',
+ sidebarPermissions: 'IAM permissions',
+ sidebarCli: 'CLI',
+ sidebarMappingFile: 'Mapping file',
+ sidebarPullCommand: 'Pull command',
+ sidebarPushCommand: 'Push command',
+ sidebarPushSingle: 'Push single',
+ sidebarGha: 'GitHub Action',
+ sidebarGhaSetup: 'Setup',
+ sidebarGhaBasic: 'Basic example',
+ sidebarGhaMultiEnv: 'Multi-environment',
+ sidebarGhaAzure: 'Azure example',
+ sidebarGhaInputs: 'Inputs & outputs',
+ sidebarReference: 'Reference',
+ sidebarConfigPriority: 'Config priority',
+ sidebarAzureSetup: 'Azure setup',
+ reqTitle: 'Requirements',
+ reqNode: 'Node.js v20+',
+ reqAws: 'AWS CLI',
+ reqAzure: 'Azure CLI',
+ reqDownload: 'Download',
+ reqInstallGuide: 'Install guide',
+ installTitle: 'Installation',
+ credTitle: 'Cloud credentials',
+ credAwsTitle: 'AWS (default)',
+ credAwsDesc:
+ 'Envilder uses your AWS CLI credentials. Set up the default profile:',
+ credAwsProfile: 'Or use a named profile:',
+ credAzureTitle: 'Azure Key Vault',
+ credAzureDesc:
+ 'Envilder uses Azure Default Credentials. Log in with:',
+ credAzureVault:
+ 'Provide the vault URL via $config in your map file or the --vault-url flag.',
+ permTitle: 'IAM permissions',
+ permAwsTitle: 'AWS',
+ permAwsDesc: 'Your IAM user or role needs:',
+ permOperation: 'Operation',
+ permPermission: 'Permission',
+ permPull: 'Pull',
+ permPush: 'Push',
+ permPolicyExample: 'Example IAM policy:',
+ permAzureTitle: 'Azure',
+ permAzureRbac:
+ 'Recommended — assign Key Vault Secrets Officer via RBAC:',
+ permAzurePullNote:
+ 'For pull-only access, Key Vault Secrets User is sufficient.',
+ mapTitle: 'Mapping file',
+ mapIntro:
+ "The mapping file (param-map.json) is the core of Envilder. It's a JSON file that maps environment variable names (keys) to secret paths (values) in your cloud provider.",
+ mapCalloutStructure: 'Structure:',
+ mapCalloutKey:
+ 'Each key becomes an env var name in your .env file.',
+ mapCalloutValue:
+ 'Each value is the path where the secret lives in your cloud provider.',
+ mapBasicTitle: 'Basic format (AWS SSM — default)',
+ mapBasicDesc:
+ 'When no $config section is present, Envilder defaults to AWS SSM Parameter Store. Values must be valid SSM parameter paths (typically starting with /):',
+ mapBasicGenerates: 'This generates:',
+ mapConfigTitle: 'The $config section',
+ mapConfigDesc:
+ 'Add a $config key to your mapping file to declare which cloud provider to use and its settings. Envilder reads $config for configuration, and treats all other keys as secret mappings.',
+ mapConfigOptionsTitle: '$config options',
+ mapThKey: 'Key',
+ mapThType: 'Type',
+ mapThDefault: 'Default',
+ mapThDescription: 'Description',
+ mapProviderDesc: 'Cloud provider to use',
+ mapVaultUrlDesc:
+ 'Azure Key Vault URL (required when provider is "azure")',
+ mapProfileDesc: 'AWS CLI profile for multi-account setups (AWS only)',
+ mapAwsProfileTitle: 'AWS SSM with profile',
+ mapAwsProfileDesc:
+ 'To use a specific AWS CLI profile (useful for multi-account setups), add profile to $config:',
+ mapAwsProfileExplain:
+ 'This tells Envilder to use the prod-account profile from your ~/.aws/credentials file instead of the default profile.',
+ mapAzureTitle: 'Azure Key Vault',
+ mapAzureDesc:
+ 'For Azure Key Vault, set provider to "azure" and provide the vaultUrl:',
+ mapAzureWarningTitle: 'Azure naming convention:',
+ mapAzureWarningDesc:
+ 'Key Vault secret names only allow alphanumeric characters and hyphens. Envilder automatically normalizes names — slashes and underscores become hyphens (e.g., /myapp/db/password → myapp-db-password).',
+ mapDifferencesTitle: 'Key differences by provider',
+ mapThEmpty: '',
+ mapThAwsSsm: 'AWS SSM',
+ mapThAzureKv: 'Azure Key Vault',
+ mapSecretPathFormat: 'Secret path format',
+ mapAwsPathFormat: 'Parameter paths with slashes',
+ mapAzurePathFormat: 'Hyphenated names',
+ mapRequiredConfig: 'Required $config',
+ mapAwsRequiredConfig: 'None (AWS is the default)',
+ mapAzureRequiredConfig: 'provider + vaultUrl',
+ mapOptionalConfig: 'Optional $config',
+ mapAuthentication: 'Authentication',
+ mapAwsAuth: 'AWS CLI credentials',
+ mapAzureAuth: 'Azure Default Credentials',
+ mapMultiEnvTitle: 'Multiple environments',
+ mapMultiEnvDesc:
+ 'A common pattern is having one mapping file per environment. The structure is the same, only the secret paths change:',
+ mapMultiEnvThenPull: 'Then pull the right one:',
+ mapOverrideTitle: 'Overriding $config with CLI flags',
+ mapOverrideDesc:
+ 'CLI flags always take priority over $config values. This lets you set defaults in the file and override per invocation:',
+ mapOverrideComment1: '# Uses $config from the map file as-is',
+ mapOverrideComment2:
+ '# Overrides provider and vault URL, ignoring $config',
+ mapOverrideComment3: '# Overrides just the AWS profile',
+ mapPriorityNote:
+ 'Priority order: CLI flags / GHA inputs → $config in map file → defaults (AWS).',
+ pullTitle: 'Pull command',
+ pullDesc:
+ 'Download secrets from your cloud provider and generate a local .env file.',
+ pullOptions: 'Options',
+ pullExamples: 'Examples',
+ pullOutput: 'Output',
+ pullOptMap: 'Path to JSON mapping file',
+ pullOptEnv: 'Path to write .env',
+ pullOptProvider: 'aws (default) or azure',
+ pullOptVault: 'Azure Key Vault URL',
+ pullOptProfile: 'AWS CLI profile to use',
+ pullCommentDefault: '# Default (AWS SSM)',
+ pullCommentProfile: '# With AWS profile',
+ pullCommentAzureConfig: '# Azure via $config in map file',
+ pullCommentAzureFlags: '# Azure via CLI flags',
+ pushTitle: 'Push command',
+ pushDesc:
+ 'Upload environment variables from a local .env file to your cloud provider using a mapping file.',
+ pushOptions: 'Options',
+ pushExamples: 'Examples',
+ pushOptPush: 'Enable push mode (required)',
+ pushOptEnv: 'Path to your local .env file',
+ pushOptMap: 'Path to parameter mapping JSON',
+ pushOptProvider: 'aws (default) or azure',
+ pushOptVault: 'Azure Key Vault URL',
+ pushOptProfile: 'AWS CLI profile (AWS only)',
+ pushCommentAws: '# Push to AWS SSM',
+ pushCommentProfile: '# With AWS profile',
+ pushCommentAzureConfig: '# Azure via $config in map file',
+ pushCommentAzureFlags: '# Azure via CLI flags',
+ pushSingleTitle: 'Push single variable',
+ pushSingleDesc:
+ 'Push a single environment variable directly without any files.',
+ pushSingleOptions: 'Options',
+ pushSingleOptPush: 'Enable push mode (required)',
+ pushSingleOptKey: 'Environment variable name',
+ pushSingleOptValue: 'Value to store',
+ pushSingleOptPath: 'Full secret path in your cloud provider',
+ pushSingleOptProvider: 'aws (default) or azure',
+ pushSingleOptVault: 'Azure Key Vault URL',
+ pushSingleOptProfile: 'AWS CLI profile (AWS only)',
+ ghaSetupTitle: 'GitHub Action setup',
+ ghaSetupDesc:
+ 'The Envilder GitHub Action pulls secrets from AWS SSM or Azure Key Vault into .env files during your CI/CD workflow. No build step needed — the action is pre-built and ready to use from GitHub Marketplace.',
+ ghaPrerequisites: 'Prerequisites',
+ ghaPrereqAws:
+ 'AWS: Configure credentials with aws-actions/configure-aws-credentials',
+ ghaPrereqAzure: 'Azure: Configure credentials with azure/login',
+ ghaPrereqMap: 'A param-map.json committed to your repository',
+ ghaPullOnly:
+ 'The GitHub Action only supports pull mode (no push).',
+ ghaBasicTitle: 'Basic workflow example',
+ ghaMultiEnvTitle: 'Multi-environment workflow',
+ ghaAzureTitle: 'Azure Key Vault workflow',
+ ghaInputsTitle: 'Action inputs & outputs',
+ ghaInputsSubtitle: 'Inputs',
+ ghaOutputsSubtitle: 'Outputs',
+ ghaInputRequired: 'Required',
+ ghaInputDefault: 'Default',
+ ghaInputDesc: 'Description',
+ ghaOutputEnvPath: 'Path to the generated .env file',
+ ghaThInput: 'Input',
+ ghaThRequired: 'Required',
+ ghaThOutput: 'Output',
+ ghaYes: 'Yes',
+ ghaNo: 'No',
+ ghaInputMap: 'Path to JSON mapping file',
+ ghaInputEnv: 'Path to the .env file to generate',
+ ghaInputProvider: 'aws or azure',
+ ghaInputVault: 'Azure Key Vault URL',
+ configPriorityTitle: 'Configuration priority',
+ configPriorityDesc:
+ 'When multiple configuration sources are present, Envilder resolves them in this order (highest wins):',
+ configPriority1: 'CLI flags / GHA inputs',
+ configPriority2: '$config in map file',
+ configPriority3: 'Defaults (AWS)',
+ configPriorityExplain:
+ 'This means --provider=azure on the CLI will override "provider": "aws" in $config.',
+ azureSetupTitle: 'Azure Key Vault setup',
+ azureSetupCheck: 'Check which access model your vault uses:',
+ azureRbacTrue: 'true → Azure RBAC (recommended)',
+ azureRbacFalse: 'false / null → Vault Access Policy (classic)',
+ azureOptionA: 'Option A — Azure RBAC (recommended)',
+ azureOptionB: 'Option B — Vault Access Policy',
+ azureAccessNote:
+ 'For pull-only access, get list is enough. Add set for push.',
+ },
+};
diff --git a/src/apps/website/src/i18n/es.ts b/src/apps/website/src/i18n/es.ts
new file mode 100644
index 00000000..683f5959
--- /dev/null
+++ b/src/apps/website/src/i18n/es.ts
@@ -0,0 +1,567 @@
+import type { Translations } from './types';
+
+export const es: Translations = {
+ nav: {
+ features: 'Funcionalidades',
+ howItWorks: 'Cómo funciona',
+ providers: 'Proveedores',
+ githubAction: 'GitHub Action',
+ changelog: 'Cambios',
+ docs: 'Docs',
+ getStarted: 'Empezar',
+ },
+ theme: {
+ retro: 'Retro',
+ light: 'Claro',
+ },
+ hero: {
+ version: 'v0.8.0',
+ openSource: 'Código abierto · MIT',
+ title1: 'Tus secretos.',
+ title2: 'Un comando.',
+ titleAccent: 'Cada entorno.',
+ description:
+ 'Una herramienta CLI y GitHub Action que centraliza de forma segura tus variables de entorno desde',
+ descAws: 'AWS SSM',
+ descAzure: 'Azure Key Vault',
+ getStarted: '▶ Empezar',
+ viewOnGithub: '★ Ver en GitHub',
+ },
+ trust: {
+ label: 'COMPATIBLE CON',
+ },
+ problemSolution: {
+ title: 'El ',
+ titleAccent: 'problema',
+ subtitle:
+ 'Gestionar secretos manualmente no escala. Es inseguro, propenso a errores y crea fricción para todo el equipo.',
+ problems: [
+ {
+ icon: '💀',
+ title: 'Desincronización entre entornos',
+ description:
+ 'Dev, staging y prod tienen secretos diferentes. Los despliegues fallan. Nadie sabe qué .env es el correcto.',
+ },
+ {
+ icon: '📨',
+ title: 'Secretos compartidos por Slack/email',
+ description:
+ 'Claves API enviadas en texto plano por chat. Sin trazabilidad. Sin rotación. Un incidente de seguridad esperando a ocurrir.',
+ },
+ {
+ icon: '🐌',
+ title: 'Onboarding y rotaciones lentas',
+ description:
+ '¿Un nuevo miembro se une al equipo? Copia y pega un .env de la máquina de alguien. ¿Alguien rota? Espera que todos actualicen manualmente.',
+ },
+ ],
+ arrowText: '▼ envilder lo soluciona ▼',
+ solutions: [
+ {
+ icon: '🛡️',
+ title: 'Fuente de verdad en la nube',
+ description:
+ 'Todos los secretos viven en AWS SSM o Azure Key Vault. IAM/RBAC controla quién puede leer qué. Cada acceso queda registrado.',
+ },
+ {
+ icon: '⚡',
+ title: 'Un comando, siempre sincronizado',
+ description:
+ 'Ejecuta envilder y tu .env se regenera desde la fuente de verdad. Idempotente. Instantáneo. Sin margen para el desfase.',
+ },
+ {
+ icon: '🤖',
+ title: 'Automatizado en CI/CD',
+ description:
+ 'Usa la GitHub Action para obtener secretos en el momento del despliegue. Sin secretos en los repos. Sin pasos manuales en los pipelines.',
+ },
+ ],
+ },
+ howItWorks: {
+ title: 'Cómo ',
+ titleAccent: 'funciona',
+ subtitle:
+ 'Tres pasos. De secretos dispersos a una única fuente de verdad.',
+ steps: [
+ {
+ title: 'Crea un archivo de mapeo',
+ description:
+ 'Mapea los nombres de tus variables de entorno a sus rutas de secretos en AWS SSM o Azure Key Vault.',
+ },
+ {
+ title: 'Ejecuta un comando',
+ description:
+ 'Envilder obtiene cada secreto de tu proveedor en la nube y los escribe en un archivo .env local. Idempotente e instantáneo.',
+ },
+ {
+ title: 'Tu .env está listo',
+ description:
+ 'Un archivo de entorno limpio y actualizado — generado desde la fuente de verdad. Úsalo localmente o inyéctalo en CI/CD con la GitHub Action.',
+ },
+ ],
+ },
+ features: {
+ title: 'Hecho para ',
+ titleAccent: 'equipos reales',
+ subtitle:
+ 'Todo lo que necesitas para gestionar secretos de entorno de forma segura y a escala.',
+ features: [
+ {
+ icon: '☁️',
+ title: 'Multi-Proveedor',
+ description:
+ 'AWS SSM Parameter Store y Azure Key Vault. Elige con --provider o $config en tu archivo de mapeo.',
+ },
+ {
+ icon: '🔄',
+ title: 'Sincronización bidireccional',
+ description:
+ 'Obtén secretos en archivos .env o sube valores .env a tu proveedor en la nube. Soporte completo de ida y vuelta.',
+ },
+ {
+ icon: '⚙️',
+ title: 'GitHub Action',
+ description:
+ 'Action para tus workflows CI/CD. Obtén secretos en el momento del despliegue sin intervención manual.',
+ },
+ {
+ icon: '🔒',
+ title: 'Acceso IAM y RBAC',
+ description:
+ 'Aprovecha el control de acceso nativo de la nube. Las políticas IAM de AWS o RBAC de Azure definen quién lee qué, por entorno.',
+ },
+ {
+ icon: '📊',
+ title: 'Totalmente auditable',
+ description:
+ 'Cada lectura y escritura queda registrada en AWS CloudTrail o Azure Monitor. Trazabilidad completa de quién accedió a qué y cuándo.',
+ },
+ {
+ icon: '🔁',
+ title: 'Sincronización idempotente',
+ description:
+ 'Solo se actualiza lo que hay en tu mapeo. Nada más se toca. Ejecútalo diez veces — mismo resultado, cero efectos secundarios.',
+ },
+ {
+ icon: '🧱',
+ title: 'Cero infraestructura',
+ description:
+ 'Construido sobre servicios nativos de la nube. Sin Lambdas, sin servidores, sin infraestructura extra que gestionar o pagar.',
+ },
+ {
+ icon: '👤',
+ title: 'Soporte de perfiles AWS',
+ description:
+ '¿Configuración multi-cuenta? Usa --profile para cambiar entre perfiles AWS CLI. Perfecto para entornos multi-etapa.',
+ },
+ ],
+ },
+ demo: {
+ title: 'Míralo en ',
+ titleAccent: 'acción',
+ subtitle:
+ 'Mira cómo Envilder simplifica la gestión de secretos en menos de 2 minutos.',
+ cliDemo: 'Demo CLI — Obtener Secretos',
+ ghaWorkflow: 'Workflow de GitHub Action',
+ comingSoon: 'Próximamente',
+ },
+ providers: {
+ title: 'Tu nube. ',
+ titleAccent: 'Tu elección.',
+ subtitle:
+ 'Envilder funciona con AWS SSM Parameter Store y Azure Key Vault. Configura en línea o con flags CLI.',
+ awsTitle: 'AWS SSM Parameter Store',
+ awsDefault: 'Proveedor por defecto',
+ awsFeatures: [
+ 'Soporte de GetParameter con WithDecryption',
+ 'Soporte de perfil AWS para multi-cuenta',
+ 'Control de acceso basado en políticas IAM',
+ 'Registro de auditoría CloudTrail',
+ ],
+ azureTitle: 'Azure Key Vault',
+ azureFeatures: [
+ 'Auto-normaliza nombres de secretos (barras → guiones)',
+ 'Autenticación DefaultAzureCredential',
+ 'Control de acceso Azure RBAC',
+ 'Registro de auditoría Azure Monitor',
+ ],
+ configPriorityTitle: 'Prioridad de configuración',
+ priorityHigh: 'Flags CLI / Inputs GHA',
+ priorityMid: '$config en archivo de mapeo',
+ priorityLow: 'Por defecto (AWS)',
+ },
+ gha: {
+ title: 'GitHub Action',
+ subtitle:
+ 'Obtén secretos en el momento del despliegue. Añádelo a cualquier workflow en minutos.',
+ awsSsm: '☁️ AWS SSM',
+ azureKeyVault: '🔑 Azure Key Vault',
+ actionInputs: 'Inputs de la Action',
+ thInput: 'Input',
+ thRequired: 'Requerido',
+ thDefault: 'Por defecto',
+ thDescription: 'Descripción',
+ inputMapDesc:
+ 'Ruta al archivo JSON que mapea variables de entorno a rutas de secretos',
+ inputEnvDesc: 'Ruta al archivo .env a generar',
+ inputProviderDesc: 'Proveedor en la nube: aws o azure',
+ inputVaultDesc: 'URL de Azure Key Vault',
+ output: 'Output:',
+ outputDesc: 'Ruta al archivo .env generado',
+ },
+ changelog: {
+ title: 'Qué hay de ',
+ titleAccent: 'nuevo',
+ subtitle:
+ 'Novedades de la última versión. El soporte multi-proveedor ya está aquí.',
+ releaseTitle: 'Soporte Multi-Proveedor',
+ highlights: [
+ {
+ icon: '✨',
+ text: 'Sección $config en archivos de mapeo — declara proveedor y detalles de conexión en línea',
+ },
+ {
+ icon: '✨',
+ text: 'Soporte de Azure Key Vault — paridad completa con AWS SSM',
+ },
+ { icon: '✨', text: 'Flags CLI --vault-url y --provider' },
+ {
+ icon: '✨',
+ text: 'Normalización automática de nombres de secretos para Azure (barras → guiones)',
+ },
+ {
+ icon: '⚠️',
+ text: 'Cambio incompatible: --ssm-path renombrado a --secret-path (el antiguo flag sigue funcionando como alias obsoleto)',
+ },
+ ],
+ fullChangelog: '📋 Historial completo',
+ viewReleases: 'Ver todas las versiones en GitHub →',
+ },
+ roadmap: {
+ title: 'Qué viene ',
+ titleAccent: 'ahora',
+ subtitle:
+ 'Envilder se desarrolla activamente. Aquí es adónde vamos.',
+ upNext: 'Próximamente',
+ items: [
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Resolución basada en mapeo',
+ description:
+ 'Mapea nombres de variables de entorno a rutas de secretos en la nube vía JSON',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Generación de archivos .env',
+ description:
+ 'Genera archivos .env desde secretos del proveedor en la nube',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Modo push (--push)',
+ description:
+ 'Sube valores .env o secretos individuales al proveedor en la nube',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'GitHub Action',
+ description:
+ 'Usa Envilder en workflows CI/CD de forma nativa',
+ },
+ {
+ status: 'done',
+ label: '✅',
+ title: 'Multi-proveedor (AWS + Azure)',
+ description:
+ 'Soporte de AWS SSM Parameter Store y Azure Key Vault',
+ },
+ {
+ status: 'next',
+ label: '⚡',
+ title: 'Modo exec (--exec)',
+ description:
+ 'Inyecta secretos en un proceso hijo sin escribir a disco',
+ },
+ {
+ status: 'next',
+ label: '🔍',
+ title: 'Modo check/sync (--check)',
+ description:
+ 'Valida SSM vs .env, falla CI si están desincronizados',
+ },
+ {
+ status: 'planned',
+ label: '📖',
+ title: 'Web de documentación',
+ description:
+ 'Web de docs dedicada con guías, ejemplos y referencia API',
+ },
+ {
+ status: 'planned',
+ label: '🤖',
+ title: 'Modo auto-descubrimiento (--auto)',
+ description:
+ 'Obtén todos los parámetros con un prefijo dado automáticamente',
+ },
+ ],
+ },
+ getStarted: {
+ title: 'Empieza ',
+ titleAccent: 'ahora',
+ subtitle: 'En funcionamiento en menos de un minuto.',
+ prerequisites: 'Prerequisitos',
+ prereqNode: 'Node.js v20+',
+ prereqAws: 'AWS CLI configurado',
+ prereqAzure: 'Azure CLI configurado',
+ prereqIam: 'Permisos IAM:',
+ install: 'Instalar',
+ quickStart: 'Inicio rápido',
+ step1: 'Crea un param-map.json que mapee variables de entorno a rutas de secretos',
+ step2: 'Ejecuta envilder --map=param-map.json --envfile=.env',
+ step3: 'Tu archivo .env está listo ✔',
+ terminalTitle: 'Inicio rápido',
+ commentInstall: '# Instalar globalmente',
+ commentCreate: '# Crear archivo de mapeo',
+ commentPull: '# Obtener secretos',
+ commentPush: '# Subir un secreto',
+ doneMessage: ' ¡Hecho! Archivo .env generado.',
+ pushSuccess: ' Secreto subido correctamente.',
+ },
+ footer: {
+ tagline:
+ 'Centraliza de forma segura tus variables de entorno desde AWS SSM o Azure Key Vault.',
+ project: 'Proyecto',
+ documentation: 'Documentación',
+ community: 'Comunidad',
+ linkGithub: 'GitHub',
+ linkNpm: 'npm',
+ linkChangelog: 'Cambios',
+ linkRoadmap: 'Hoja de ruta',
+ linkGettingStarted: 'Empezar',
+ linkPullCommand: 'Comando Pull',
+ linkPushCommand: 'Comando Push',
+ linkGithubAction: 'GitHub Action',
+ linkIssues: 'Incidencias',
+ linkDiscussions: 'Discusiones',
+ linkSecurity: 'Seguridad',
+ linkSponsor: 'Patrocinar',
+ copyright: 'Hecho con Astro. Código abierto en GitHub.',
+ builtWith: 'Hecho con Astro. Código abierto en GitHub.',
+ },
+ changelogPage: {
+ title: 'Historial de cambios — Envilder',
+ backToHome: '← Volver al inicio',
+ fullChangelog: 'Historial de ',
+ changelogAccent: 'cambios',
+ intro: 'Historial completo de versiones. Ver también',
+ githubReleases: 'Versiones en GitHub',
+ },
+ docs: {
+ title: 'Documentación — Envilder',
+ backToHome: '← Volver al inicio',
+ pageTitle: 'Documentación',
+ intro: 'Todo lo que necesitas para empezar con Envilder.',
+ sidebarGettingStarted: 'Primeros pasos',
+ sidebarRequirements: 'Requisitos',
+ sidebarInstallation: 'Instalación',
+ sidebarCredentials: 'Credenciales de nube',
+ sidebarPermissions: 'Permisos IAM',
+ sidebarCli: 'CLI',
+ sidebarMappingFile: 'Archivo de mapeo',
+ sidebarPullCommand: 'Comando pull',
+ sidebarPushCommand: 'Comando push',
+ sidebarPushSingle: 'Push individual',
+ sidebarGha: 'GitHub Action',
+ sidebarGhaSetup: 'Configuración',
+ sidebarGhaBasic: 'Ejemplo básico',
+ sidebarGhaMultiEnv: 'Multi-entorno',
+ sidebarGhaAzure: 'Ejemplo Azure',
+ sidebarGhaInputs: 'Inputs y outputs',
+ sidebarReference: 'Referencia',
+ sidebarConfigPriority: 'Prioridad de config',
+ sidebarAzureSetup: 'Configuración Azure',
+ reqTitle: 'Requisitos',
+ reqNode: 'Node.js v20+',
+ reqAws: 'AWS CLI',
+ reqAzure: 'Azure CLI',
+ reqDownload: 'Descargar',
+ reqInstallGuide: 'Guía de instalación',
+ installTitle: 'Instalación',
+ credTitle: 'Credenciales de nube',
+ credAwsTitle: 'AWS (por defecto)',
+ credAwsDesc:
+ 'Envilder usa tus credenciales AWS CLI. Configura el perfil por defecto:',
+ credAwsProfile: 'O usa un perfil con nombre:',
+ credAzureTitle: 'Azure Key Vault',
+ credAzureDesc:
+ 'Envilder usa Azure Default Credentials. Inicia sesión con:',
+ credAzureVault:
+ 'Proporciona la URL del vault vía $config en tu archivo de mapeo o el flag --vault-url.',
+ permTitle: 'Permisos IAM',
+ permAwsTitle: 'AWS',
+ permAwsDesc: 'Tu usuario o rol IAM necesita:',
+ permOperation: 'Operación',
+ permPermission: 'Permiso',
+ permPull: 'Pull',
+ permPush: 'Push',
+ permPolicyExample: 'Ejemplo de política IAM:',
+ permAzureTitle: 'Azure',
+ permAzureRbac:
+ 'Recomendado — asigna Key Vault Secrets Officer vía RBAC:',
+ permAzurePullNote:
+ 'Para acceso solo de lectura, Key Vault Secrets User es suficiente.',
+ mapTitle: 'Archivo de mapeo',
+ mapIntro:
+ 'El archivo de mapeo (param-map.json) es el núcleo de Envilder. Es un archivo JSON que mapea nombres de variables de entorno (claves) a rutas de secretos (valores) en tu proveedor en la nube.',
+ mapCalloutStructure: 'Estructura:',
+ mapCalloutKey:
+ 'Cada clave se convierte en un nombre de variable de entorno en tu archivo .env.',
+ mapCalloutValue:
+ 'Cada valor es la ruta donde vive el secreto en tu proveedor en la nube.',
+ mapBasicTitle: 'Formato básico (AWS SSM — por defecto)',
+ mapBasicDesc:
+ 'Cuando no hay sección $config, Envilder usa AWS SSM Parameter Store por defecto. Los valores deben ser rutas de parámetros SSM válidas (normalmente comenzando con /):',
+ mapBasicGenerates: 'Esto genera:',
+ mapConfigTitle: 'La sección $config',
+ mapConfigDesc:
+ 'Añade una clave $config a tu archivo de mapeo para declarar qué proveedor en la nube usar y su configuración. Envilder lee $config para la configuración y trata todas las demás claves como mapeos de secretos.',
+ mapConfigOptionsTitle: 'Opciones de $config',
+ mapThKey: 'Clave',
+ mapThType: 'Tipo',
+ mapThDefault: 'Por defecto',
+ mapThDescription: 'Descripción',
+ mapProviderDesc: 'Proveedor en la nube a usar',
+ mapVaultUrlDesc:
+ 'URL de Azure Key Vault (requerido cuando el proveedor es "azure")',
+ mapProfileDesc:
+ 'Perfil AWS CLI para configuraciones multi-cuenta (solo AWS)',
+ mapAwsProfileTitle: 'AWS SSM con perfil',
+ mapAwsProfileDesc:
+ 'Para usar un perfil AWS CLI específico (útil para configuraciones multi-cuenta), añade profile a $config:',
+ mapAwsProfileExplain:
+ 'Esto indica a Envilder que use el perfil prod-account de tu archivo ~/.aws/credentials en lugar del perfil por defecto.',
+ mapAzureTitle: 'Azure Key Vault',
+ mapAzureDesc:
+ 'Para Azure Key Vault, establece provider a "azure" y proporciona el vaultUrl:',
+ mapAzureWarningTitle: 'Convención de nombres Azure:',
+ mapAzureWarningDesc:
+ 'Los nombres de secretos de Key Vault solo permiten caracteres alfanuméricos y guiones. Envilder normaliza automáticamente los nombres — barras y guiones bajos se convierten en guiones (ej., /myapp/db/password → myapp-db-password).',
+ mapDifferencesTitle: 'Diferencias clave por proveedor',
+ mapThEmpty: '',
+ mapThAwsSsm: 'AWS SSM',
+ mapThAzureKv: 'Azure Key Vault',
+ mapSecretPathFormat: 'Formato de ruta de secreto',
+ mapAwsPathFormat: 'Rutas de parámetros con barras',
+ mapAzurePathFormat: 'Nombres con guiones',
+ mapRequiredConfig: '$config requerido',
+ mapAwsRequiredConfig: 'Ninguno (AWS es por defecto)',
+ mapAzureRequiredConfig: 'provider + vaultUrl',
+ mapOptionalConfig: '$config opcional',
+ mapAuthentication: 'Autenticación',
+ mapAwsAuth: 'Credenciales AWS CLI',
+ mapAzureAuth: 'Azure Default Credentials',
+ mapMultiEnvTitle: 'Múltiples entornos',
+ mapMultiEnvDesc:
+ 'Un patrón común es tener un archivo de mapeo por entorno. La estructura es la misma, solo cambian las rutas de los secretos:',
+ mapMultiEnvThenPull: 'Luego obtén el correcto:',
+ mapOverrideTitle: 'Sobreescribir $config con flags CLI',
+ mapOverrideDesc:
+ 'Los flags CLI siempre tienen prioridad sobre los valores de $config. Esto te permite establecer valores por defecto en el archivo y sobreescribirlos por invocación:',
+ mapOverrideComment1: '# Usa $config del archivo de mapeo tal cual',
+ mapOverrideComment2:
+ '# Sobreescribe proveedor y URL del vault, ignorando $config',
+ mapOverrideComment3: '# Sobreescribe solo el perfil AWS',
+ mapPriorityNote:
+ 'Orden de prioridad: flags CLI / inputs GHA → $config en archivo de mapeo → por defecto (AWS).',
+ pullTitle: 'Comando pull',
+ pullDesc:
+ 'Descarga secretos de tu proveedor en la nube y genera un archivo .env local.',
+ pullOptions: 'Opciones',
+ pullExamples: 'Ejemplos',
+ pullOutput: 'Salida',
+ pullOptMap: 'Ruta al archivo JSON de mapeo',
+ pullOptEnv: 'Ruta donde escribir el .env',
+ pullOptProvider: 'aws (por defecto) o azure',
+ pullOptVault: 'URL de Azure Key Vault',
+ pullOptProfile: 'Perfil AWS CLI a usar',
+ pullCommentDefault: '# Por defecto (AWS SSM)',
+ pullCommentProfile: '# Con perfil AWS',
+ pullCommentAzureConfig: '# Azure vía $config en archivo de mapeo',
+ pullCommentAzureFlags: '# Azure vía flags CLI',
+ pushTitle: 'Comando push',
+ pushDesc:
+ 'Sube variables de entorno de un archivo .env local a tu proveedor en la nube usando un archivo de mapeo.',
+ pushOptions: 'Opciones',
+ pushExamples: 'Ejemplos',
+ pushOptPush: 'Activa el modo push (requerido)',
+ pushOptEnv: 'Ruta a tu archivo .env local',
+ pushOptMap: 'Ruta al JSON de mapeo de parámetros',
+ pushOptProvider: 'aws (por defecto) o azure',
+ pushOptVault: 'URL de Azure Key Vault',
+ pushOptProfile: 'Perfil AWS CLI (solo AWS)',
+ pushCommentAws: '# Subir a AWS SSM',
+ pushCommentProfile: '# Con perfil AWS',
+ pushCommentAzureConfig: '# Azure vía $config en archivo de mapeo',
+ pushCommentAzureFlags: '# Azure vía flags CLI',
+ pushSingleTitle: 'Subir variable individual',
+ pushSingleDesc:
+ 'Sube una variable de entorno individual directamente sin ningún archivo.',
+ pushSingleOptions: 'Opciones',
+ pushSingleOptPush: 'Activa el modo push (requerido)',
+ pushSingleOptKey: 'Nombre de la variable de entorno',
+ pushSingleOptValue: 'Valor a almacenar',
+ pushSingleOptPath: 'Ruta completa del secreto en tu proveedor en la nube',
+ pushSingleOptProvider: 'aws (por defecto) o azure',
+ pushSingleOptVault: 'URL de Azure Key Vault',
+ pushSingleOptProfile: 'Perfil AWS CLI (solo AWS)',
+ ghaSetupTitle: 'Configuración de GitHub Action',
+ ghaSetupDesc:
+ 'La GitHub Action de Envilder obtiene secretos de AWS SSM o Azure Key Vault en archivos .env durante tu workflow CI/CD. No hace falta compilar — la action está pre-construida y lista para usar desde GitHub Marketplace.',
+ ghaPrerequisites: 'Prerequisitos',
+ ghaPrereqAws:
+ 'AWS: Configura credenciales con aws-actions/configure-aws-credentials',
+ ghaPrereqAzure: 'Azure: Configura credenciales con azure/login',
+ ghaPrereqMap: 'Un param-map.json en tu repositorio',
+ ghaPullOnly:
+ 'La GitHub Action solo soporta el modo pull (sin push).',
+ ghaBasicTitle: 'Ejemplo básico de workflow',
+ ghaMultiEnvTitle: 'Workflow multi-entorno',
+ ghaAzureTitle: 'Workflow de Azure Key Vault',
+ ghaInputsTitle: 'Inputs y outputs de la Action',
+ ghaInputsSubtitle: 'Inputs',
+ ghaOutputsSubtitle: 'Outputs',
+ ghaInputRequired: 'Requerido',
+ ghaInputDefault: 'Por defecto',
+ ghaInputDesc: 'Descripción',
+ ghaOutputEnvPath: 'Ruta al archivo .env generado',
+ ghaThInput: 'Input',
+ ghaThRequired: 'Requerido',
+ ghaThOutput: 'Output',
+ ghaYes: 'Sí',
+ ghaNo: 'No',
+ ghaInputMap: 'Ruta al archivo JSON de mapeo',
+ ghaInputEnv: 'Ruta al archivo .env a generar',
+ ghaInputProvider: 'aws o azure',
+ ghaInputVault: 'URL de Azure Key Vault',
+ configPriorityTitle: 'Prioridad de configuración',
+ configPriorityDesc:
+ 'Cuando hay múltiples fuentes de configuración, Envilder las resuelve en este orden (el más alto gana):',
+ configPriority1: 'Flags CLI / inputs GHA',
+ configPriority2: '$config en el archivo de mapeo',
+ configPriority3: 'Por defecto (AWS)',
+ configPriorityExplain:
+ 'Esto significa que --provider=azure en la CLI sobreescribirá "provider": "aws" en $config.',
+ azureSetupTitle: 'Configuración de Azure Key Vault',
+ azureSetupCheck: 'Comprueba qué modelo de acceso usa tu vault:',
+ azureRbacTrue: 'true → Azure RBAC (recomendado)',
+ azureRbacFalse: 'false / null → Vault Access Policy (clásico)',
+ azureOptionA: 'Opción A — Azure RBAC (recomendado)',
+ azureOptionB: 'Opción B — Vault Access Policy',
+ azureAccessNote:
+ 'Para acceso solo de lectura, get list es suficiente. Añade set para push.',
+ },
+};
diff --git a/src/apps/website/src/i18n/types.ts b/src/apps/website/src/i18n/types.ts
new file mode 100644
index 00000000..dd5cbf35
--- /dev/null
+++ b/src/apps/website/src/i18n/types.ts
@@ -0,0 +1,402 @@
+export interface NavLinks {
+ features: string;
+ howItWorks: string;
+ providers: string;
+ githubAction: string;
+ changelog: string;
+ docs: string;
+ getStarted: string;
+}
+
+export interface ThemeTranslations {
+ retro: string;
+ light: string;
+}
+
+export interface HeroTranslations {
+ version: string;
+ openSource: string;
+ title1: string;
+ title2: string;
+ titleAccent: string;
+ description: string;
+ descAws: string;
+ descAzure: string;
+ getStarted: string;
+ viewOnGithub: string;
+}
+
+export interface TrustTranslations {
+ label: string;
+}
+
+export interface ProblemItem {
+ icon: string;
+ title: string;
+ description: string;
+}
+
+export interface ProblemSolutionTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ problems: ProblemItem[];
+ arrowText: string;
+ solutions: ProblemItem[];
+}
+
+export interface StepItem {
+ title: string;
+ description: string;
+}
+
+export interface HowItWorksTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ steps: StepItem[];
+}
+
+export interface FeatureItem {
+ icon: string;
+ title: string;
+ description: string;
+}
+
+export interface FeaturesTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ features: FeatureItem[];
+}
+
+export interface DemoTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ cliDemo: string;
+ ghaWorkflow: string;
+ comingSoon: string;
+}
+
+export interface ProvidersTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ awsTitle: string;
+ awsDefault: string;
+ awsFeatures: string[];
+ azureTitle: string;
+ azureFeatures: string[];
+ configPriorityTitle: string;
+ priorityHigh: string;
+ priorityMid: string;
+ priorityLow: string;
+}
+
+export interface GhaTranslations {
+ title: string;
+ subtitle: string;
+ awsSsm: string;
+ azureKeyVault: string;
+ actionInputs: string;
+ thInput: string;
+ thRequired: string;
+ thDefault: string;
+ thDescription: string;
+ inputMapDesc: string;
+ inputEnvDesc: string;
+ inputProviderDesc: string;
+ inputVaultDesc: string;
+ output: string;
+ outputDesc: string;
+}
+
+export interface ChangelogHighlight {
+ icon: string;
+ text: string;
+}
+
+export interface ChangelogTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ releaseTitle: string;
+ highlights: ChangelogHighlight[];
+ fullChangelog: string;
+ viewReleases: string;
+}
+
+export interface RoadmapItem {
+ status: string;
+ label: string;
+ title: string;
+ description: string;
+}
+
+export interface RoadmapTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ upNext: string;
+ items: RoadmapItem[];
+}
+
+export interface GetStartedTranslations {
+ title: string;
+ titleAccent: string;
+ subtitle: string;
+ prerequisites: string;
+ prereqNode: string;
+ prereqAws: string;
+ prereqAzure: string;
+ prereqIam: string;
+ install: string;
+ quickStart: string;
+ step1: string;
+ step2: string;
+ step3: string;
+ terminalTitle: string;
+ commentInstall: string;
+ commentCreate: string;
+ commentPull: string;
+ commentPush: string;
+ doneMessage: string;
+ pushSuccess: string;
+}
+
+export interface FooterTranslations {
+ tagline: string;
+ project: string;
+ documentation: string;
+ community: string;
+ linkGithub: string;
+ linkNpm: string;
+ linkChangelog: string;
+ linkRoadmap: string;
+ linkGettingStarted: string;
+ linkPullCommand: string;
+ linkPushCommand: string;
+ linkGithubAction: string;
+ linkIssues: string;
+ linkDiscussions: string;
+ linkSecurity: string;
+ linkSponsor: string;
+ copyright: string;
+ builtWith: string;
+}
+
+export interface ChangelogPageTranslations {
+ title: string;
+ backToHome: string;
+ fullChangelog: string;
+ changelogAccent: string;
+ intro: string;
+ githubReleases: string;
+}
+
+export interface DocsTranslations {
+ title: string;
+ backToHome: string;
+ pageTitle: string;
+ intro: string;
+ // Sidebar
+ sidebarGettingStarted: string;
+ sidebarRequirements: string;
+ sidebarInstallation: string;
+ sidebarCredentials: string;
+ sidebarPermissions: string;
+ sidebarCli: string;
+ sidebarMappingFile: string;
+ sidebarPullCommand: string;
+ sidebarPushCommand: string;
+ sidebarPushSingle: string;
+ sidebarGha: string;
+ sidebarGhaSetup: string;
+ sidebarGhaBasic: string;
+ sidebarGhaMultiEnv: string;
+ sidebarGhaAzure: string;
+ sidebarGhaInputs: string;
+ sidebarReference: string;
+ sidebarConfigPriority: string;
+ sidebarAzureSetup: string;
+ // Requirements
+ reqTitle: string;
+ reqNode: string;
+ reqAws: string;
+ reqAzure: string;
+ reqDownload: string;
+ reqInstallGuide: string;
+ // Installation
+ installTitle: string;
+ // Credentials
+ credTitle: string;
+ credAwsTitle: string;
+ credAwsDesc: string;
+ credAwsProfile: string;
+ credAzureTitle: string;
+ credAzureDesc: string;
+ credAzureVault: string;
+ // Permissions
+ permTitle: string;
+ permAwsTitle: string;
+ permAwsDesc: string;
+ permOperation: string;
+ permPermission: string;
+ permPull: string;
+ permPush: string;
+ permPolicyExample: string;
+ permAzureTitle: string;
+ permAzureRbac: string;
+ permAzurePullNote: string;
+ // Mapping file
+ mapTitle: string;
+ mapIntro: string;
+ mapCalloutStructure: string;
+ mapCalloutKey: string;
+ mapCalloutValue: string;
+ mapBasicTitle: string;
+ mapBasicDesc: string;
+ mapBasicGenerates: string;
+ mapConfigTitle: string;
+ mapConfigDesc: string;
+ mapConfigOptionsTitle: string;
+ mapThKey: string;
+ mapThType: string;
+ mapThDefault: string;
+ mapThDescription: string;
+ mapProviderDesc: string;
+ mapVaultUrlDesc: string;
+ mapProfileDesc: string;
+ mapAwsProfileTitle: string;
+ mapAwsProfileDesc: string;
+ mapAwsProfileExplain: string;
+ mapAzureTitle: string;
+ mapAzureDesc: string;
+ mapAzureWarningTitle: string;
+ mapAzureWarningDesc: string;
+ mapDifferencesTitle: string;
+ mapThEmpty: string;
+ mapThAwsSsm: string;
+ mapThAzureKv: string;
+ mapSecretPathFormat: string;
+ mapAwsPathFormat: string;
+ mapAzurePathFormat: string;
+ mapRequiredConfig: string;
+ mapAwsRequiredConfig: string;
+ mapAzureRequiredConfig: string;
+ mapOptionalConfig: string;
+ mapAuthentication: string;
+ mapAwsAuth: string;
+ mapAzureAuth: string;
+ mapMultiEnvTitle: string;
+ mapMultiEnvDesc: string;
+ mapMultiEnvThenPull: string;
+ mapOverrideTitle: string;
+ mapOverrideDesc: string;
+ mapOverrideComment1: string;
+ mapOverrideComment2: string;
+ mapOverrideComment3: string;
+ mapPriorityNote: string;
+ // Pull command
+ pullTitle: string;
+ pullDesc: string;
+ pullOptions: string;
+ pullExamples: string;
+ pullOutput: string;
+ pullOptMap: string;
+ pullOptEnv: string;
+ pullOptProvider: string;
+ pullOptVault: string;
+ pullOptProfile: string;
+ pullCommentDefault: string;
+ pullCommentProfile: string;
+ pullCommentAzureConfig: string;
+ pullCommentAzureFlags: string;
+ // Push command
+ pushTitle: string;
+ pushDesc: string;
+ pushOptions: string;
+ pushExamples: string;
+ pushOptPush: string;
+ pushOptEnv: string;
+ pushOptMap: string;
+ pushOptProvider: string;
+ pushOptVault: string;
+ pushOptProfile: string;
+ pushCommentAws: string;
+ pushCommentProfile: string;
+ pushCommentAzureConfig: string;
+ pushCommentAzureFlags: string;
+ // Push single
+ pushSingleTitle: string;
+ pushSingleDesc: string;
+ pushSingleOptions: string;
+ pushSingleOptPush: string;
+ pushSingleOptKey: string;
+ pushSingleOptValue: string;
+ pushSingleOptPath: string;
+ pushSingleOptProvider: string;
+ pushSingleOptVault: string;
+ pushSingleOptProfile: string;
+ // GHA
+ ghaSetupTitle: string;
+ ghaSetupDesc: string;
+ ghaPrerequisites: string;
+ ghaPrereqAws: string;
+ ghaPrereqAzure: string;
+ ghaPrereqMap: string;
+ ghaPullOnly: string;
+ ghaBasicTitle: string;
+ ghaMultiEnvTitle: string;
+ ghaAzureTitle: string;
+ ghaInputsTitle: string;
+ ghaInputsSubtitle: string;
+ ghaOutputsSubtitle: string;
+ ghaInputRequired: string;
+ ghaInputDefault: string;
+ ghaInputDesc: string;
+ ghaThInput: string;
+ ghaThRequired: string;
+ ghaThOutput: string;
+ ghaYes: string;
+ ghaNo: string;
+ ghaInputMap: string;
+ ghaInputEnv: string;
+ ghaInputProvider: string;
+ ghaInputVault: string;
+ ghaOutputEnvPath: string;
+ // Reference
+ configPriorityTitle: string;
+ configPriorityDesc: string;
+ configPriority1: string;
+ configPriority2: string;
+ configPriority3: string;
+ configPriorityExplain: string;
+ azureSetupTitle: string;
+ azureSetupCheck: string;
+ azureRbacTrue: string;
+ azureRbacFalse: string;
+ azureOptionA: string;
+ azureOptionB: string;
+ azureAccessNote: string;
+}
+
+export interface Translations {
+ nav: NavLinks;
+ theme: ThemeTranslations;
+ hero: HeroTranslations;
+ trust: TrustTranslations;
+ problemSolution: ProblemSolutionTranslations;
+ howItWorks: HowItWorksTranslations;
+ features: FeaturesTranslations;
+ demo: DemoTranslations;
+ providers: ProvidersTranslations;
+ gha: GhaTranslations;
+ changelog: ChangelogTranslations;
+ roadmap: RoadmapTranslations;
+ getStarted: GetStartedTranslations;
+ footer: FooterTranslations;
+ changelogPage: ChangelogPageTranslations;
+ docs: DocsTranslations;
+}
diff --git a/src/apps/website/src/i18n/utils.ts b/src/apps/website/src/i18n/utils.ts
new file mode 100644
index 00000000..24dd8e80
--- /dev/null
+++ b/src/apps/website/src/i18n/utils.ts
@@ -0,0 +1,26 @@
+import { en } from './en';
+import { ca } from './ca';
+import { es } from './es';
+import type { Translations } from './types';
+
+const translations: Record = { en, ca, es };
+
+export const languages = {
+ en: 'English',
+ ca: 'Català',
+ es: 'Español',
+};
+
+export const defaultLang = 'en';
+
+export type Lang = keyof typeof languages;
+
+export function useTranslations(lang: string) {
+ const dict = translations[lang] || translations[defaultLang];
+ return dict;
+}
+
+export function localizedPath(lang: string, path: string) {
+ if (lang === defaultLang) return path;
+ return `/${lang}${path}`;
+}
diff --git a/src/apps/website/src/layouts/BaseLayout.astro b/src/apps/website/src/layouts/BaseLayout.astro
new file mode 100644
index 00000000..276b8817
--- /dev/null
+++ b/src/apps/website/src/layouts/BaseLayout.astro
@@ -0,0 +1,68 @@
+---
+export interface Props {
+ title?: string;
+ description?: string;
+ lang?: string;
+}
+
+const {
+ title = 'Envilder — Centralize your secrets. One command.',
+ description = 'A CLI tool and GitHub Action that securely centralizes environment variables from AWS SSM Parameter Store or Azure Key Vault as a single source of truth.',
+ lang = 'en',
+} = Astro.props;
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {title}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/pages/ca/changelog.astro b/src/apps/website/src/pages/ca/changelog.astro
new file mode 100644
index 00000000..93ff5978
--- /dev/null
+++ b/src/apps/website/src/pages/ca/changelog.astro
@@ -0,0 +1,95 @@
+---
+import BaseLayout from '../../layouts/BaseLayout.astro';
+import Navbar from '../../components/Navbar.astro';
+import Footer from '../../components/Footer.astro';
+import { useTranslations, localizedPath } from '../../i18n/utils';
+import { readFile } from 'node:fs/promises';
+import { resolve } from 'node:path';
+
+const lang = 'ca';
+const t = useTranslations(lang);
+
+const changelogPath = resolve(process.cwd(), '../../../docs/CHANGELOG.md');
+let changelogContent = '';
+try {
+ changelogContent = await readFile(changelogPath, 'utf-8');
+} catch {
+ changelogContent = '# Changelog\n\nChangelog file not found. See [GitHub Releases](https://github.com/macalbert/envilder/releases).';
+}
+
+function simpleMarkdownToHtml(md: string): string {
+ return md
+ .replace(/^#### (.+)$/gm, '$1 ')
+ .replace(/^### (.+)$/gm, '$1 ')
+ .replace(/^## (.+)$/gm, '$1 ')
+ .replace(/^# (.+)$/gm, '$1 ')
+ .replace(/\*\*(.+?)\*\*/g, '$1 ')
+ .replace(/`([^`]+)`/g, '$1')
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ')
+ .replace(/^- (.+)$/gm, '$1 ')
+ .replace(/((?:.*<\/li>\n?)+)/g, '')
+ .replace(/^(?!<[hul]| $1
')
+ .replace(/\n{2,}/g, '\n');
+}
+
+const changelogHtml = simpleMarkdownToHtml(changelogContent);
+---
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/pages/ca/docs.astro b/src/apps/website/src/pages/ca/docs.astro
new file mode 100644
index 00000000..d4971b54
--- /dev/null
+++ b/src/apps/website/src/pages/ca/docs.astro
@@ -0,0 +1,17 @@
+---
+import BaseLayout from '../../layouts/BaseLayout.astro';
+import Navbar from '../../components/Navbar.astro';
+import DocsContent from '../../components/DocsContent.astro';
+import { useTranslations } from '../../i18n/utils';
+
+const lang = 'ca';
+const t = useTranslations(lang);
+---
+
+
+
+
+
diff --git a/src/apps/website/src/pages/ca/index.astro b/src/apps/website/src/pages/ca/index.astro
new file mode 100644
index 00000000..2347a74f
--- /dev/null
+++ b/src/apps/website/src/pages/ca/index.astro
@@ -0,0 +1,36 @@
+---
+import BaseLayout from '../../layouts/BaseLayout.astro';
+import Navbar from '../../components/Navbar.astro';
+import Hero from '../../components/Hero.astro';
+import TrustBadges from '../../components/TrustBadges.astro';
+import ProblemSolution from '../../components/ProblemSolution.astro';
+import HowItWorks from '../../components/HowItWorks.astro';
+import FeaturesGrid from '../../components/FeaturesGrid.astro';
+import DemoVideo from '../../components/DemoVideo.astro';
+import Providers from '../../components/Providers.astro';
+import GitHubAction from '../../components/GitHubAction.astro';
+import Changelog from '../../components/Changelog.astro';
+import Roadmap from '../../components/Roadmap.astro';
+import GetStarted from '../../components/GetStarted.astro';
+import Footer from '../../components/Footer.astro';
+
+const lang = 'ca';
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/pages/changelog.astro b/src/apps/website/src/pages/changelog.astro
new file mode 100644
index 00000000..457ec7e3
--- /dev/null
+++ b/src/apps/website/src/pages/changelog.astro
@@ -0,0 +1,180 @@
+---
+import BaseLayout from '../layouts/BaseLayout.astro';
+import Navbar from '../components/Navbar.astro';
+import Footer from '../components/Footer.astro';
+import { useTranslations, localizedPath } from '../i18n/utils';
+import { readFile } from 'node:fs/promises';
+import { resolve } from 'node:path';
+
+const lang = 'en';
+const t = useTranslations(lang);
+
+// Read the changelog from the project root
+const changelogPath = resolve(process.cwd(), '../../../docs/CHANGELOG.md');
+let changelogContent = '';
+try {
+ changelogContent = await readFile(changelogPath, 'utf-8');
+} catch {
+ changelogContent = '# Changelog\n\nChangelog file not found. See [GitHub Releases](https://github.com/macalbert/envilder/releases).';
+}
+
+// Simple markdown-to-HTML conversion for the changelog
+function simpleMarkdownToHtml(md: string): string {
+ return md
+ .replace(/^#### (.+)$/gm, '$1 ')
+ .replace(/^### (.+)$/gm, '$1 ')
+ .replace(/^## (.+)$/gm, '$1 ')
+ .replace(/^# (.+)$/gm, '$1 ')
+ .replace(/\*\*(.+?)\*\*/g, '$1 ')
+ .replace(/`([^`]+)`/g, '$1')
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ')
+ .replace(/^- (.+)$/gm, '$1 ')
+ .replace(/((?:.*<\/li>\n?)+)/g, '')
+ .replace(/^(?!<[hul]| $1')
+ .replace(/\n{2,}/g, '\n');
+}
+
+const changelogHtml = simpleMarkdownToHtml(changelogContent);
+---
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/pages/docs.astro b/src/apps/website/src/pages/docs.astro
new file mode 100644
index 00000000..4e0b810a
--- /dev/null
+++ b/src/apps/website/src/pages/docs.astro
@@ -0,0 +1,17 @@
+---
+import BaseLayout from '../layouts/BaseLayout.astro';
+import Navbar from '../components/Navbar.astro';
+import DocsContent from '../components/DocsContent.astro';
+import { useTranslations } from '../i18n/utils';
+
+const lang = 'en';
+const t = useTranslations(lang);
+---
+
+
+
+
+
diff --git a/src/apps/website/src/pages/es/changelog.astro b/src/apps/website/src/pages/es/changelog.astro
new file mode 100644
index 00000000..1687c015
--- /dev/null
+++ b/src/apps/website/src/pages/es/changelog.astro
@@ -0,0 +1,95 @@
+---
+import BaseLayout from '../../layouts/BaseLayout.astro';
+import Navbar from '../../components/Navbar.astro';
+import Footer from '../../components/Footer.astro';
+import { useTranslations, localizedPath } from '../../i18n/utils';
+import { readFile } from 'node:fs/promises';
+import { resolve } from 'node:path';
+
+const lang = 'es';
+const t = useTranslations(lang);
+
+const changelogPath = resolve(process.cwd(), '../../../docs/CHANGELOG.md');
+let changelogContent = '';
+try {
+ changelogContent = await readFile(changelogPath, 'utf-8');
+} catch {
+ changelogContent = '# Changelog\n\nChangelog file not found. See [GitHub Releases](https://github.com/macalbert/envilder/releases).';
+}
+
+function simpleMarkdownToHtml(md: string): string {
+ return md
+ .replace(/^#### (.+)$/gm, '$1 ')
+ .replace(/^### (.+)$/gm, '$1 ')
+ .replace(/^## (.+)$/gm, '$1 ')
+ .replace(/^# (.+)$/gm, '$1 ')
+ .replace(/\*\*(.+?)\*\*/g, '$1 ')
+ .replace(/`([^`]+)`/g, '$1')
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ')
+ .replace(/^- (.+)$/gm, ' $1 ')
+ .replace(/((?:.*<\/li>\n?)+)/g, '')
+ .replace(/^(?!<[hul]| $1')
+ .replace(/\n{2,}/g, '\n');
+}
+
+const changelogHtml = simpleMarkdownToHtml(changelogContent);
+---
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/pages/es/docs.astro b/src/apps/website/src/pages/es/docs.astro
new file mode 100644
index 00000000..352aaaa4
--- /dev/null
+++ b/src/apps/website/src/pages/es/docs.astro
@@ -0,0 +1,17 @@
+---
+import BaseLayout from '../../layouts/BaseLayout.astro';
+import Navbar from '../../components/Navbar.astro';
+import DocsContent from '../../components/DocsContent.astro';
+import { useTranslations } from '../../i18n/utils';
+
+const lang = 'es';
+const t = useTranslations(lang);
+---
+
+
+
+
+
diff --git a/src/apps/website/src/pages/es/index.astro b/src/apps/website/src/pages/es/index.astro
new file mode 100644
index 00000000..9319ea43
--- /dev/null
+++ b/src/apps/website/src/pages/es/index.astro
@@ -0,0 +1,36 @@
+---
+import BaseLayout from '../../layouts/BaseLayout.astro';
+import Navbar from '../../components/Navbar.astro';
+import Hero from '../../components/Hero.astro';
+import TrustBadges from '../../components/TrustBadges.astro';
+import ProblemSolution from '../../components/ProblemSolution.astro';
+import HowItWorks from '../../components/HowItWorks.astro';
+import FeaturesGrid from '../../components/FeaturesGrid.astro';
+import DemoVideo from '../../components/DemoVideo.astro';
+import Providers from '../../components/Providers.astro';
+import GitHubAction from '../../components/GitHubAction.astro';
+import Changelog from '../../components/Changelog.astro';
+import Roadmap from '../../components/Roadmap.astro';
+import GetStarted from '../../components/GetStarted.astro';
+import Footer from '../../components/Footer.astro';
+
+const lang = 'es';
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/pages/index.astro b/src/apps/website/src/pages/index.astro
new file mode 100644
index 00000000..bb083e18
--- /dev/null
+++ b/src/apps/website/src/pages/index.astro
@@ -0,0 +1,36 @@
+---
+import BaseLayout from '../layouts/BaseLayout.astro';
+import Navbar from '../components/Navbar.astro';
+import Hero from '../components/Hero.astro';
+import TrustBadges from '../components/TrustBadges.astro';
+import ProblemSolution from '../components/ProblemSolution.astro';
+import HowItWorks from '../components/HowItWorks.astro';
+import FeaturesGrid from '../components/FeaturesGrid.astro';
+import DemoVideo from '../components/DemoVideo.astro';
+import Providers from '../components/Providers.astro';
+import GitHubAction from '../components/GitHubAction.astro';
+import Changelog from '../components/Changelog.astro';
+import Roadmap from '../components/Roadmap.astro';
+import GetStarted from '../components/GetStarted.astro';
+import Footer from '../components/Footer.astro';
+
+const lang = 'en';
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/website/src/styles/global.css b/src/apps/website/src/styles/global.css
new file mode 100644
index 00000000..b4ff3bb1
--- /dev/null
+++ b/src/apps/website/src/styles/global.css
@@ -0,0 +1,452 @@
+/* ── Envilder Design System ─────────────────────────────── */
+/* Retro Game Boy · Pixel accents · Professional */
+
+/* ── Reset ────────────────────────────────────────────── */
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+html {
+ scroll-behavior: smooth;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+/* ── CSS Custom Properties ────────────────────────────── */
+:root {
+ /* Colors — Game Boy LCD neutral palette (retro / dark default) */
+ --color-bg: #111311;
+ --color-bg-alt: #151815;
+ --color-surface: #1c1f1c;
+ --color-surface-alt: #242824;
+ --color-border: #343834;
+ --color-border-light:#454a45;
+
+ --color-primary: #8a9a6c;
+ --color-primary-dim: #6b7a52;
+ --color-secondary: #a0ac8e;
+ --color-secondary-dim:#7a8868;
+ --color-accent: #c8ceb8;
+
+ --color-text: #c5c8c0;
+ --color-text-muted: #8a8e86;
+ --color-text-dim: #5c605a;
+
+ --color-success: #8a9a6c;
+ --color-warning: #b8b090;
+ --color-error: #a05050;
+
+ --color-nav-bg: rgba(17, 19, 17, 0.92);
+ --color-nav-mobile: rgba(17, 19, 17, 0.98);
+ --color-btn-text: #111311;
+
+ /* Typography */
+ --font-pixel: 'Press Start 2P', monospace;
+ --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
+
+ /* Spacing */
+ --space-xs: 0.25rem;
+ --space-sm: 0.5rem;
+ --space-md: 1rem;
+ --space-lg: 1.5rem;
+ --space-xl: 2rem;
+ --space-2xl: 3rem;
+ --space-3xl: 4rem;
+ --space-4xl: 6rem;
+
+ /* Layout */
+ --max-width: 1200px;
+ --nav-height: 64px;
+
+ /* Effects */
+ --pixel-shadow: 4px 4px 0 var(--color-border);
+ --pixel-shadow-primary: 4px 4px 0 var(--color-primary-dim);
+ --glow-primary: 0 0 20px rgba(138, 154, 108, 0.3);
+ --glow-secondary: 0 0 15px rgba(160, 172, 142, 0.2);
+
+ /* Transitions */
+ --transition-fast: 150ms ease;
+ --transition-base: 250ms ease;
+}
+
+/* ── Theme: light (clean white) ───────────────────────── */
+[data-theme="light"] {
+ --color-bg: #f5f4f1;
+ --color-bg-alt: #eceae6;
+ --color-surface: #ffffff;
+ --color-surface-alt: #f0eeea;
+ --color-border: #d5d3cf;
+ --color-border-light:#c2c0bb;
+
+ --color-primary: #6b6860;
+ --color-primary-dim: #565450;
+ --color-secondary: #7e7b74;
+ --color-secondary-dim:#686660;
+ --color-accent: #4a4844;
+
+ --color-text: #2c2b28;
+ --color-text-muted: #6b6862;
+ --color-text-dim: #9a9890;
+
+ --color-success: #6b7a5c;
+ --color-warning: #a09040;
+ --color-error: #a04848;
+
+ --color-nav-bg: rgba(245, 244, 241, 0.92);
+ --color-nav-mobile: rgba(245, 244, 241, 0.98);
+ --color-btn-text: #f5f4f1;
+
+ --pixel-shadow: 4px 4px 0 var(--color-border);
+ --pixel-shadow-primary: 4px 4px 0 var(--color-primary-dim);
+ --glow-primary: 0 0 20px rgba(107, 104, 96, 0.12);
+ --glow-secondary: 0 0 15px rgba(126, 123, 116, 0.08);
+}
+
+/* ── Auto system preference (no saved preference) ─────── */
+@media (prefers-color-scheme: light) {
+ [data-theme="auto"] {
+ --color-bg: #f5f5f0;
+ --color-bg-alt: #eceee8;
+ --color-surface: #ffffff;
+ --color-surface-alt: #f0f2ec;
+ --color-border: #d4d6d0;
+ --color-border-light:#c0c4bc;
+
+ --color-primary: #5a7040;
+ --color-primary-dim: #486032;
+ --color-secondary: #6e8858;
+ --color-secondary-dim:#5a7248;
+ --color-accent: #3d5228;
+
+ --color-text: #2a2e28;
+ --color-text-muted: #5c605a;
+ --color-text-dim: #8a8e88;
+
+ --color-success: #5a7040;
+ --color-warning: #a08420;
+ --color-error: #b04040;
+
+ --color-nav-bg: rgba(245, 245, 240, 0.92);
+ --color-nav-mobile: rgba(245, 245, 240, 0.98);
+ --color-btn-text: #f5f5f0;
+
+ --pixel-shadow: 4px 4px 0 var(--color-border);
+ --pixel-shadow-primary: 4px 4px 0 var(--color-primary-dim);
+ --glow-primary: 0 0 20px rgba(90, 112, 64, 0.15);
+ --glow-secondary: 0 0 15px rgba(110, 136, 88, 0.1);
+ }
+}
+
+/* ── Theme transition ─────────────────────────────────── */
+html:not([data-no-transition]) body,
+html:not([data-no-transition]) .navbar {
+ transition: background-color 300ms ease, color 300ms ease,
+ border-color 300ms ease;
+}
+
+/* ── Base ─────────────────────────────────────────────── */
+body {
+ font-family: var(--font-body);
+ background: var(--color-bg);
+ color: var(--color-text);
+ line-height: 1.7;
+ font-size: 1rem;
+ overflow-x: hidden;
+}
+
+img, video {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+
+a {
+ color: var(--color-primary);
+ text-decoration: none;
+ transition: color var(--transition-fast);
+}
+
+a:hover {
+ color: var(--color-accent);
+}
+
+/* ── Typography ───────────────────────────────────────── */
+h1, h2, h3, h4 {
+ font-family: var(--font-pixel);
+ line-height: 1.3;
+ letter-spacing: -0.01em;
+}
+
+h1 {
+ font-size: clamp(1.1rem, 3vw, 1.6rem);
+ color: var(--color-text);
+}
+
+h2 {
+ font-size: clamp(0.85rem, 2vw, 1.1rem);
+ color: var(--color-text);
+ margin-bottom: var(--space-lg);
+}
+
+h3 {
+ font-size: clamp(0.65rem, 1.5vw, 0.8rem);
+ color: var(--color-text-muted);
+}
+
+p {
+ color: var(--color-text-muted);
+ max-width: 65ch;
+}
+
+code {
+ font-family: var(--font-mono);
+ font-size: 0.9em;
+ background: var(--color-surface);
+ padding: 0.15em 0.4em;
+ border-radius: 3px;
+ border: 1px solid var(--color-border);
+}
+
+/* ── Layout Utilities ─────────────────────────────────── */
+.container {
+ width: 100%;
+ max-width: var(--max-width);
+ margin: 0 auto;
+ padding: 0 var(--space-lg);
+}
+
+.section {
+ padding: var(--space-4xl) 0;
+}
+
+.section-alt {
+ background: var(--color-bg-alt);
+}
+
+.section-title {
+ text-align: center;
+ margin-bottom: var(--space-3xl);
+}
+
+.section-title span {
+ color: var(--color-primary);
+}
+
+.section-subtitle {
+ font-family: var(--font-body);
+ font-size: 1.1rem;
+ color: var(--color-text-muted);
+ max-width: 600px;
+ margin: var(--space-md) auto 0;
+ text-align: center;
+ font-weight: 400;
+}
+
+/* ── Buttons ──────────────────────────────────────────── */
+.btn {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-sm);
+ font-family: var(--font-pixel);
+ font-size: 0.65rem;
+ padding: var(--space-md) var(--space-xl);
+ border: 2px solid transparent;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ text-decoration: none;
+ position: relative;
+}
+
+.btn-primary {
+ background: var(--color-primary);
+ color: var(--color-btn-text);
+ border-color: var(--color-primary);
+ box-shadow: var(--pixel-shadow-primary);
+}
+
+.btn-primary:hover {
+ background: transparent;
+ color: var(--color-primary);
+ transform: translate(2px, 2px);
+ box-shadow: none;
+}
+
+.btn-outline {
+ background: transparent;
+ color: var(--color-text);
+ border-color: var(--color-border-light);
+ box-shadow: var(--pixel-shadow);
+}
+
+.btn-outline:hover {
+ border-color: var(--color-primary);
+ color: var(--color-primary);
+ transform: translate(2px, 2px);
+ box-shadow: none;
+}
+
+/* ── Cards (pixel-bordered) ───────────────────────────── */
+.pixel-card {
+ background: var(--color-surface);
+ border: 2px solid var(--color-border);
+ padding: var(--space-xl);
+ position: relative;
+ transition: all var(--transition-base);
+}
+
+.pixel-card:hover {
+ border-color: var(--color-primary);
+ box-shadow: var(--pixel-shadow-primary);
+ transform: translate(-2px, -2px);
+}
+
+/* corner notch decoration */
+.pixel-card::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ right: -2px;
+ width: 12px;
+ height: 12px;
+ background: var(--color-bg);
+ border-left: 2px solid var(--color-border);
+ border-bottom: 2px solid var(--color-border);
+}
+
+.pixel-card:hover::before {
+ border-color: var(--color-primary);
+}
+
+/* ── Pixel icon (8-bit style emoji replacement) ───────── */
+.pixel-icon {
+ font-size: 1.8rem;
+ display: inline-block;
+ image-rendering: pixelated;
+ margin-bottom: var(--space-md);
+}
+
+/* ── Badge / Tag ──────────────────────────────────────── */
+.badge {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-xs);
+ font-family: var(--font-mono);
+ font-size: 0.75rem;
+ padding: var(--space-xs) var(--space-sm);
+ border: 1px solid var(--color-border);
+ background: var(--color-surface);
+ color: var(--color-text-muted);
+}
+
+.badge-primary {
+ border-color: var(--color-primary);
+ color: var(--color-primary);
+}
+
+.badge-success {
+ border-color: var(--color-success);
+ color: var(--color-success);
+}
+
+/* ── Scanline overlay ─────────────────────────────────── */
+.scanlines {
+ position: relative;
+}
+
+.scanlines::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: repeating-linear-gradient(
+ 0deg,
+ transparent,
+ transparent 2px,
+ rgba(0, 0, 0, 0.08) 2px,
+ rgba(0, 0, 0, 0.08) 4px
+ );
+ pointer-events: none;
+ z-index: 1;
+}
+
+/* ── Grid helpers ─────────────────────────────────────── */
+.grid-2 {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--space-xl);
+}
+
+.grid-3 {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--space-xl);
+}
+
+.grid-4 {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--space-lg);
+}
+
+@media (min-width: 640px) {
+ .grid-2 { grid-template-columns: repeat(2, 1fr); }
+ .grid-3 { grid-template-columns: repeat(2, 1fr); }
+ .grid-4 { grid-template-columns: repeat(2, 1fr); }
+}
+
+@media (min-width: 1024px) {
+ .grid-3 { grid-template-columns: repeat(3, 1fr); }
+ .grid-4 { grid-template-columns: repeat(4, 1fr); }
+}
+
+/* ── Divider (pixel style) ────────────────────────────── */
+.pixel-divider {
+ border: none;
+ height: 2px;
+ background: repeating-linear-gradient(
+ 90deg,
+ var(--color-border) 0px,
+ var(--color-border) 8px,
+ transparent 8px,
+ transparent 12px
+ );
+ margin: var(--space-3xl) 0;
+}
+
+/* ── Responsive ───────────────────────────────────────── */
+@media (max-width: 640px) {
+ .container {
+ padding: 0 var(--space-md);
+ }
+
+ .section {
+ padding: var(--space-3xl) 0;
+ }
+}
+
+/* ── Scrollbar ────────────────────────────────────────── */
+::-webkit-scrollbar {
+ width: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: var(--color-bg);
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--color-border);
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--color-border-light);
+}
+
+/* ── Selection ────────────────────────────────────────── */
+::selection {
+ background: var(--color-primary);
+ color: var(--color-btn-text);
+}
diff --git a/src/apps/website/tsconfig.json b/src/apps/website/tsconfig.json
new file mode 100644
index 00000000..77da9dd0
--- /dev/null
+++ b/src/apps/website/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "astro/tsconfigs/strict"
+}
\ No newline at end of file
From 086b61a4c165c427018d2b5a5b08175d16efb963 Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 14:55:59 +0100
Subject: [PATCH 02/49] feat(iac): add CDK infrastructure for static website
and CI/CD pipeline
Introduce the src/iac package with AWS CDK stacks for deploying
static websites (S3 + CloudFront + Route53) and CodePipeline CI/CD.
Includes hexagonal architecture with domain validation, stack builders,
console deployment logger, and comprehensive test coverage (19 suites,
157 tests, 9 snapshots).
---
package.json | 2 +-
pnpm-lock.yaml | 2152 +++-
src/iac/.gitignore | 19 +
src/iac/.instructions.md | 39 +
src/iac/.npmignore | 6 +
src/iac/README.md | 173 +
src/iac/biome.jsonc | 9 +
src/iac/cdk.json | 56 +
src/iac/jest.config.js | 18 +
src/iac/package.json | 30 +
src/iac/pnpm-lock.yaml | 2759 +++++
.../codepipeline/pipelineStack.ts | 579 ++
src/iac/src/aws/network/vpcLookupStack.ts | 24 +
src/iac/src/aws/network/vpcStack.ts | 112 +
.../website/S3CloudfrontUrlParametersFix.md | 258 +
.../src/aws/website/cloudfront-url-rewrite.js | 54 +
src/iac/src/aws/website/staticWebsiteStack.ts | 286 +
.../deployInfrastructureHandler.ts | 82 +
.../models/deploymentRequest.ts | 60 +
.../builders/factories/stackBuilderFactory.ts | 47 +
.../config/domain/builders/frontendBuilder.ts | 67 +
.../config/domain/builders/sharedBuilder.ts | 65 +
src/iac/src/config/domain/customStack.ts | 64 +
src/iac/src/config/domain/iStackBuilder.ts | 43 +
.../src/config/domain/model/appEnvironment.ts | 8 +
.../config/domain/model/deploymentConfig.ts | 21 +
.../src/config/domain/model/stackConfig.ts | 31 +
.../config/domain/ports/iFileOperations.ts | 36 +
src/iac/src/config/domain/ports/iLogger.ts | 45 +
.../src/config/domain/ports/iProjectPath.ts | 23 +
.../domain/services/stackBuilderService.ts | 82 +
.../domain/validation/configValidator.ts | 94 +
.../fileOperations/fileOperations.ts | 81 +
.../logging/consoleDeploymentLogger.ts | 140 +
.../projectPath/fileProjectPath.ts | 31 +
.../utilities/cloudFormationUtils.ts | 26 +
.../config/infrastructure/utilities/errors.ts | 72 +
.../infrastructure/utilities/stringUtils.ts | 12 +
.../infra/buildspecs/production/website.yml | 31 +
src/iac/src/infra/buildspecs/test/iac.yml | 28 +
src/iac/src/infra/buildspecs/test/website.yml | 28 +
src/iac/src/infra/config/frontendConfig.ts | 11 +
src/iac/src/infra/config/sharedConfig.ts | 16 +
src/iac/src/infra/iac.ts | 24 +
src/iac/src/infra/iacConfig.ts | 20 +
.../__snapshots__/pipelineStack.test.ts.snap | 8927 +++++++++++++++++
.../aws/developerTools/pipelineStack.test.ts | 181 +
.../__snapshots__/vpcStack.test.ts.snap | 612 ++
.../test/aws/network/vpcLookupStack.test.ts | 107 +
src/iac/test/aws/network/vpcStack.test.ts | 61 +
src/iac/test/aws/website/Dockerfile | 1 +
.../staticWebsiteStack.test.ts.snap | 948 ++
.../aws/website/cloudfrontUrlRewrite.test.ts | 159 +
.../aws/website/staticWebsiteStack.test.ts | 89 +
.../deployInfrastructureHandler.test.ts | 118 +
.../factories/stackBuilderFactory.test.ts | 124 +
.../domain/builders/frontendBuilder.test.ts | 87 +
.../domain/builders/sharedBuilder.test.ts | 83 +
.../test/config/domain/iStackBuilder.test.ts | 92 +
src/iac/test/config/domain/m47Stack.test.ts | 132 +
.../domain/model/appEnvironment.test.ts | 90 +
.../services/stackBuilderService.test.ts | 160 +
.../fileOperations/fileOperations.test.ts | 250 +
.../logging/consoleDeploymentLogger.test.ts | 99 +
.../projectPath/fileProjectPath.test.ts | 172 +
.../utilities/cloudFormationUtils.test.ts | 176 +
.../infrastructure/utilities/errors.test.ts | 298 +
.../utilities/templateNormalizer.ts | 160 +
.../validation/configValidator.test.ts | 288 +
src/iac/tsconfig.json | 55 +
70 files changed, 21299 insertions(+), 34 deletions(-)
create mode 100644 src/iac/.gitignore
create mode 100644 src/iac/.instructions.md
create mode 100644 src/iac/.npmignore
create mode 100644 src/iac/README.md
create mode 100644 src/iac/biome.jsonc
create mode 100644 src/iac/cdk.json
create mode 100644 src/iac/jest.config.js
create mode 100644 src/iac/package.json
create mode 100644 src/iac/pnpm-lock.yaml
create mode 100644 src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts
create mode 100644 src/iac/src/aws/network/vpcLookupStack.ts
create mode 100644 src/iac/src/aws/network/vpcStack.ts
create mode 100644 src/iac/src/aws/website/S3CloudfrontUrlParametersFix.md
create mode 100644 src/iac/src/aws/website/cloudfront-url-rewrite.js
create mode 100644 src/iac/src/aws/website/staticWebsiteStack.ts
create mode 100644 src/iac/src/config/application/deployInfrastructure/deployInfrastructureHandler.ts
create mode 100644 src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
create mode 100644 src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts
create mode 100644 src/iac/src/config/domain/builders/frontendBuilder.ts
create mode 100644 src/iac/src/config/domain/builders/sharedBuilder.ts
create mode 100644 src/iac/src/config/domain/customStack.ts
create mode 100644 src/iac/src/config/domain/iStackBuilder.ts
create mode 100644 src/iac/src/config/domain/model/appEnvironment.ts
create mode 100644 src/iac/src/config/domain/model/deploymentConfig.ts
create mode 100644 src/iac/src/config/domain/model/stackConfig.ts
create mode 100644 src/iac/src/config/domain/ports/iFileOperations.ts
create mode 100644 src/iac/src/config/domain/ports/iLogger.ts
create mode 100644 src/iac/src/config/domain/ports/iProjectPath.ts
create mode 100644 src/iac/src/config/domain/services/stackBuilderService.ts
create mode 100644 src/iac/src/config/domain/validation/configValidator.ts
create mode 100644 src/iac/src/config/infrastructure/fileOperations/fileOperations.ts
create mode 100644 src/iac/src/config/infrastructure/logging/consoleDeploymentLogger.ts
create mode 100644 src/iac/src/config/infrastructure/projectPath/fileProjectPath.ts
create mode 100644 src/iac/src/config/infrastructure/utilities/cloudFormationUtils.ts
create mode 100644 src/iac/src/config/infrastructure/utilities/errors.ts
create mode 100644 src/iac/src/config/infrastructure/utilities/stringUtils.ts
create mode 100644 src/iac/src/infra/buildspecs/production/website.yml
create mode 100644 src/iac/src/infra/buildspecs/test/iac.yml
create mode 100644 src/iac/src/infra/buildspecs/test/website.yml
create mode 100644 src/iac/src/infra/config/frontendConfig.ts
create mode 100644 src/iac/src/infra/config/sharedConfig.ts
create mode 100644 src/iac/src/infra/iac.ts
create mode 100644 src/iac/src/infra/iacConfig.ts
create mode 100644 src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap
create mode 100644 src/iac/test/aws/developerTools/pipelineStack.test.ts
create mode 100644 src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap
create mode 100644 src/iac/test/aws/network/vpcLookupStack.test.ts
create mode 100644 src/iac/test/aws/network/vpcStack.test.ts
create mode 100644 src/iac/test/aws/website/Dockerfile
create mode 100644 src/iac/test/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap
create mode 100644 src/iac/test/aws/website/cloudfrontUrlRewrite.test.ts
create mode 100644 src/iac/test/aws/website/staticWebsiteStack.test.ts
create mode 100644 src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
create mode 100644 src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
create mode 100644 src/iac/test/config/domain/builders/frontendBuilder.test.ts
create mode 100644 src/iac/test/config/domain/builders/sharedBuilder.test.ts
create mode 100644 src/iac/test/config/domain/iStackBuilder.test.ts
create mode 100644 src/iac/test/config/domain/m47Stack.test.ts
create mode 100644 src/iac/test/config/domain/model/appEnvironment.test.ts
create mode 100644 src/iac/test/config/domain/services/stackBuilderService.test.ts
create mode 100644 src/iac/test/config/infrastructure/fileOperations/fileOperations.test.ts
create mode 100644 src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
create mode 100644 src/iac/test/config/infrastructure/projectPath/fileProjectPath.test.ts
create mode 100644 src/iac/test/config/infrastructure/utilities/cloudFormationUtils.test.ts
create mode 100644 src/iac/test/config/infrastructure/utilities/errors.test.ts
create mode 100644 src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
create mode 100644 src/iac/test/config/infrastructure/validation/configValidator.test.ts
create mode 100644 src/iac/tsconfig.json
diff --git a/package.json b/package.json
index ef68cc4b..03226960 100644
--- a/package.json
+++ b/package.json
@@ -119,8 +119,8 @@
"onlyBuiltDependencies": [
"cpu-features",
"esbuild",
- "lefthook",
"protobufjs",
+ "sharp",
"ssh2"
]
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c2dfd091..0d932c4e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -100,6 +100,34 @@ importers:
specifier: ^5.8.0
version: 5.18.1(@azure/identity@4.13.0)(@azure/keyvault-secrets@4.10.0(@azure/core-client@1.10.1))(@types/node@25.3.3)(jiti@2.6.1)(rollup@4.59.0)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)
+ src/iac:
+ dependencies:
+ aws-cdk-lib:
+ specifier: ^2.200.0
+ version: 2.244.0(constructs@10.6.0)
+ constructs:
+ specifier: ^10.4.2
+ version: 10.6.0
+ devDependencies:
+ '@types/jest':
+ specifier: ^29.5.14
+ version: 29.5.14
+ aws-cdk:
+ specifier: ^2.200.0
+ version: 2.1114.1
+ jest:
+ specifier: ^29.7.0
+ version: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ ts-jest:
+ specifier: ^29.3.4
+ version: 29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3)))(typescript@5.9.3)
+ ts-node:
+ specifier: ^10.9.2
+ version: 10.9.2(@types/node@25.3.3)(typescript@5.9.3)
+ typescript:
+ specifier: ^5.9.3
+ version: 5.9.3
+
packages:
'@astrojs/compiler@2.13.1':
@@ -122,6 +150,19 @@ packages:
resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==}
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
+ '@aws-cdk/asset-awscli-v1@2.2.263':
+ resolution: {integrity: sha512-X9JvcJhYcb7PHs8R7m4zMablO5C9PGb/hYfLnxds9h/rKJu6l7MiXE/SabCibuehxPnuO/vk+sVVJiUWrccarQ==}
+
+ '@aws-cdk/asset-node-proxy-agent-v6@2.1.1':
+ resolution: {integrity: sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==}
+
+ '@aws-cdk/cloud-assembly-schema@52.2.0':
+ resolution: {integrity: sha512-ourZjixQ/UfsZc7gdk3vt1eHBODMUjQTYYYCY3ZX8fiXyHtWNDAYZPrXUK96jpCC2fLP+tfHTJrBjZ563pmcEw==}
+ engines: {node: '>= 18.0.0'}
+ bundledDependencies:
+ - jsonschema
+ - semver
+
'@aws-crypto/sha256-browser@5.2.0':
resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==}
@@ -328,6 +369,40 @@ packages:
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
+ '@babel/compat-data@7.29.0':
+ resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.0':
+ resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.1':
+ resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.28.6':
+ resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.28.6':
+ resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.6':
+ resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.28.6':
+ resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'}
@@ -336,11 +411,118 @@ packages:
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.29.2':
+ resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/parser@7.29.0':
resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
engines: {node: '>=6.0.0'}
hasBin: true
+ '@babel/plugin-syntax-async-generators@7.8.4':
+ resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-bigint@7.8.3':
+ resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-class-properties@7.12.13':
+ resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-class-static-block@7.14.5':
+ resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-import-attributes@7.28.6':
+ resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-import-meta@7.10.4':
+ resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-json-strings@7.8.3':
+ resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-jsx@7.28.6':
+ resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
+ resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
+ resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-numeric-separator@7.10.4':
+ resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-object-rest-spread@7.8.3':
+ resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3':
+ resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-optional-chaining@7.8.3':
+ resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-private-property-in-object@7.14.5':
+ resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-top-level-await@7.14.5':
+ resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-typescript@7.28.6':
+ resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.28.6':
+ resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.0':
+ resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/types@7.29.0':
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
engines: {node: '>=6.9.0'}
@@ -348,6 +530,9 @@ packages:
'@balena/dockerignore@1.0.2':
resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==}
+ '@bcoe/v8-coverage@0.2.3':
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+
'@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
@@ -994,6 +1179,86 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
+ '@istanbuljs/load-nyc-config@1.1.0':
+ resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
+ engines: {node: '>=8'}
+
+ '@istanbuljs/schema@0.1.3':
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+
+ '@jest/console@29.7.0':
+ resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/core@29.7.0':
+ resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ '@jest/environment@29.7.0':
+ resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/expect-utils@29.7.0':
+ resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/expect@29.7.0':
+ resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/fake-timers@29.7.0':
+ resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/globals@29.7.0':
+ resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/reporters@29.7.0':
+ resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ '@jest/schemas@29.6.3':
+ resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/source-map@29.6.3':
+ resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/test-result@29.7.0':
+ resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/test-sequencer@29.7.0':
+ resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/transform@29.7.0':
+ resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/types@29.6.3':
+ resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
@@ -1272,10 +1537,19 @@ packages:
resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==}
engines: {node: '>=18'}
+ '@sinclair/typebox@0.27.10':
+ resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==}
+
'@sindresorhus/merge-streams@2.3.0':
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
engines: {node: '>=18'}
+ '@sinonjs/commons@3.0.1':
+ resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
+
+ '@sinonjs/fake-timers@10.3.0':
+ resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+
'@smithy/abort-controller@4.2.12':
resolution: {integrity: sha512-xolrFw6b+2iYGl6EcOL7IJY71vvyZ0DJ3mcKtpykqPe2uscwtzDZJa1uVQXyP7w9Dd+kGwYnPbMsJrGISKiY/Q==}
engines: {node: '>=18.0.0'}
@@ -1485,6 +1759,18 @@ packages:
'@tsconfig/node16@1.0.4':
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
'@types/chai@5.2.3':
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
@@ -1503,9 +1789,24 @@ packages:
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+ '@types/graceful-fs@4.1.9':
+ resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
+
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+ '@types/istanbul-lib-coverage@2.0.6':
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+
+ '@types/istanbul-lib-report@3.0.3':
+ resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
+
+ '@types/istanbul-reports@3.0.4':
+ resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+
+ '@types/jest@29.5.14':
+ resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
+
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
@@ -1539,9 +1840,18 @@ packages:
'@types/ssh2@1.15.5':
resolution: {integrity: sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ==}
+ '@types/stack-utils@2.0.3':
+ resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+ '@types/yargs-parser@21.0.3':
+ resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+
+ '@types/yargs@17.0.35':
+ resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==}
+
'@typespec/ts-http-runtime@0.3.3':
resolution: {integrity: sha512-91fp6CAAJSRtH5ja95T1FHSKa8aPW9/Zw6cta81jlZTUw/+Vq8jM/AfF/14h2b71wwR84JUTW/3Y8QPhDAawFA==}
engines: {node: '>=20.0.0'}
@@ -1614,6 +1924,10 @@ packages:
ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
+ ansi-escapes@4.3.2:
+ resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+ engines: {node: '>=8'}
+
ansi-escapes@7.3.0:
resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==}
engines: {node: '>=18'}
@@ -1630,6 +1944,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
@@ -1652,6 +1970,9 @@ packages:
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+ argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -1690,6 +2011,30 @@ packages:
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+ aws-cdk-lib@2.244.0:
+ resolution: {integrity: sha512-j5FVeZv5W+v6j6OnW8RjoN04T+8pYvDJJV7yXhhj4IiGDKPgMH3fflQLQXJousd2QQk+nSAjghDVJcrZ4GFyGA==}
+ engines: {node: '>= 20.0.0'}
+ peerDependencies:
+ constructs: ^10.5.0
+ bundledDependencies:
+ - '@balena/dockerignore'
+ - '@aws-cdk/cloud-assembly-api'
+ - case
+ - fs-extra
+ - ignore
+ - jsonschema
+ - minimatch
+ - punycode
+ - semver
+ - table
+ - yaml
+ - mime-types
+
+ aws-cdk@2.1114.1:
+ resolution: {integrity: sha512-jMaKPWQQs1G6AbhfCQG2zGrgAhTxzP0jn4T2CuwONuvcV374dMPhfC/LBAv48ruSOgpCK9x6V1xeO/aH3EchAA==}
+ engines: {node: '>= 18.0.0'}
+ hasBin: true
+
axobject-query@4.1.0:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
engines: {node: '>= 0.4'}
@@ -1702,6 +2047,31 @@ packages:
react-native-b4a:
optional: true
+ babel-jest@29.7.0:
+ resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@babel/core': ^7.8.0
+
+ babel-plugin-istanbul@6.1.1:
+ resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
+ engines: {node: '>=8'}
+
+ babel-plugin-jest-hoist@29.6.3:
+ resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ babel-preset-current-node-syntax@1.2.0:
+ resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0 || ^8.0.0-0
+
+ babel-preset-jest@29.6.3:
+ resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
bail@2.0.2:
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
@@ -1753,6 +2123,11 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ baseline-browser-mapping@2.10.11:
+ resolution: {integrity: sha512-DAKrHphkJyiGuau/cFieRYhcTFeK/lBuD++C7cZ6KZHbMhBrisoi+EvhQ5RZrIfV5qwsW8kgQ07JIC+MDJRAhg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
bcrypt-pbkdf@1.0.2:
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
@@ -1784,6 +2159,18 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
+ browserslist@4.28.1:
+ resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ bs-logger@0.2.6:
+ resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
+ engines: {node: '>= 6'}
+
+ bser@2.1.1:
+ resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
+
buffer-crc32@1.0.0:
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
engines: {node: '>=8.0.0'}
@@ -1791,6 +2178,9 @@ packages:
buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
+ buffer-from@1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
@@ -1813,10 +2203,21 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
+ camelcase@5.3.1:
+ resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+ engines: {node: '>=6'}
+
+ camelcase@6.3.0:
+ resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+ engines: {node: '>=10'}
+
camelcase@8.0.0:
resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==}
engines: {node: '>=16'}
+ caniuse-lite@1.0.30001781:
+ resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==}
+
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -1832,6 +2233,10 @@ packages:
resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ char-regex@1.0.2:
+ resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
+ engines: {node: '>=10'}
+
character-entities-html4@2.1.0:
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
@@ -1848,10 +2253,17 @@ packages:
chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+ ci-info@3.9.0:
+ resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
+ engines: {node: '>=8'}
+
ci-info@4.4.0:
resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==}
engines: {node: '>=8'}
+ cjs-module-lexer@1.4.3:
+ resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
+
cli-boxes@3.0.0:
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
engines: {node: '>=10'}
@@ -1864,6 +2276,13 @@ packages:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
+ co@4.6.0:
+ resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
+ engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
+
+ collect-v8-coverage@1.0.3:
+ resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==}
+
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -1892,6 +2311,9 @@ packages:
resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==}
engines: {node: '>= 14'}
+ constructs@10.6.0:
+ resolution: {integrity: sha512-TxHOnBO5zMo/G76ykzGF/wMpEHu257TbWiIxP9K0Yv/+t70UzgBQiTqjkAsWOPC6jW91DzJI0+ehQV6xDRNBuQ==}
+
conventional-changelog-angular@8.3.0:
resolution: {integrity: sha512-DOuBwYSqWzfwuRByY9O4oOIvDlkUCTDzfbOgcSbkY+imXXj+4tmrEFao3K+FxemClYfYnZzsvudbwrhje9VHDA==}
engines: {node: '>=18'}
@@ -1905,6 +2327,9 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
cookie-es@1.2.2:
resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
@@ -1945,6 +2370,11 @@ packages:
resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
engines: {node: '>= 14'}
+ create-jest@29.7.0:
+ resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
+
create-require@1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
@@ -1995,6 +2425,18 @@ packages:
decode-named-character-reference@1.3.0:
resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
+ dedent@1.7.2:
+ resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==}
+ peerDependencies:
+ babel-plugin-macros: ^3.1.0
+ peerDependenciesMeta:
+ babel-plugin-macros:
+ optional: true
+
+ deepmerge@4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+
default-browser-id@5.0.1:
resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==}
engines: {node: '>=18'}
@@ -2021,6 +2463,10 @@ packages:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
+ detect-newline@3.1.0:
+ resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
+ engines: {node: '>=8'}
+
deterministic-object-hash@2.0.2:
resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==}
engines: {node: '>=18'}
@@ -2031,6 +2477,10 @@ packages:
devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+ diff-sequences@29.6.3:
+ resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
diff@4.0.4:
resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
engines: {node: '>=0.3.1'}
@@ -2089,6 +2539,13 @@ packages:
resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==}
engines: {ecmascript: '>= es5', node: '>=4'}
+ electron-to-chromium@1.5.328:
+ resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==}
+
+ emittery@0.13.1:
+ resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
+ engines: {node: '>=12'}
+
emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
@@ -2137,10 +2594,19 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
+ escape-string-regexp@2.0.0:
+ resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+ engines: {node: '>=8'}
+
escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
+ esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
@@ -2161,10 +2627,22 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ execa@5.1.1:
+ resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+ engines: {node: '>=10'}
+
+ exit@0.1.2:
+ resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
+ engines: {node: '>= 0.8.0'}
+
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
+ expect@29.7.0:
+ resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
@@ -2178,6 +2656,9 @@ packages:
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
engines: {node: '>=8.6.0'}
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
fast-uri@3.1.0:
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
@@ -2191,6 +2672,9 @@ packages:
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
+ fb-watchman@2.0.2:
+ resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
@@ -2204,6 +2688,10 @@ packages:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
+ find-up@4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+
flattie@1.1.1:
resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==}
engines: {node: '>=8'}
@@ -2222,11 +2710,21 @@ packages:
fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+ fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
@@ -2235,10 +2733,18 @@ packages:
resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==}
engines: {node: '>=18'}
+ get-package-type@0.1.0:
+ resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
+ engines: {node: '>=8.0.0'}
+
get-port@7.1.0:
resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==}
engines: {node: '>=16'}
+ get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+
get-tsconfig@4.13.7:
resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==}
@@ -2264,6 +2770,10 @@ packages:
resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==}
engines: {node: 18 || 20 || >=22}
+ glob@7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
+
global-directory@4.0.1:
resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==}
engines: {node: '>=18'}
@@ -2278,10 +2788,19 @@ packages:
h3@1.15.10:
resolution: {integrity: sha512-YzJeWSkDZxAhvmp8dexjRK5hxziRO7I9m0N53WhvYL5NiWfkUkzssVzY9jvGu0HBoLFW6+duYmNSn6MaZBCCtg==}
+ handlebars@4.7.9:
+ resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==}
+ engines: {node: '>=0.4.7'}
+ hasBin: true
+
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
hast-util-from-html@2.0.3:
resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
@@ -2336,6 +2855,10 @@ packages:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
+ human-signals@2.1.0:
+ resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+ engines: {node: '>=10.17.0'}
+
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@@ -2347,13 +2870,26 @@ packages:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
+ import-local@3.2.0:
+ resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
+ engines: {node: '>=8'}
+ hasBin: true
+
import-meta-resolve@4.2.0:
resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
index-to-position@1.2.0:
resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==}
engines: {node: '>=18'}
+ inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -2370,6 +2906,10 @@ packages:
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
is-docker@3.0.0:
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -2383,6 +2923,10 @@ packages:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
+ is-generator-fn@2.1.0:
+ resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
+ engines: {node: '>=6'}
+
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
@@ -2422,10 +2966,22 @@ packages:
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
engines: {node: '>=8'}
+ istanbul-lib-instrument@5.2.1:
+ resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-instrument@6.0.3:
+ resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
+ engines: {node: '>=10'}
+
istanbul-lib-report@3.0.1:
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
engines: {node: '>=10'}
+ istanbul-lib-source-maps@4.0.1:
+ resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
+ engines: {node: '>=10'}
+
istanbul-reports@3.2.0:
resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
engines: {node: '>=8'}
@@ -2437,44 +2993,182 @@ packages:
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
- jiti@2.6.1:
- resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+ jest-changed-files@29.7.0:
+ resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-circus@29.7.0:
+ resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-cli@29.7.0:
+ resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
- js-tokens@10.0.0:
- resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+ jest-config@29.7.0:
+ resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@types/node': '*'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ ts-node:
+ optional: true
- js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ jest-diff@29.7.0:
+ resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- js-yaml@4.1.1:
- resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
- hasBin: true
+ jest-docblock@29.7.0:
+ resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+ jest-each@29.7.0:
+ resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- json-schema-traverse@1.0.0:
- resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+ jest-environment-node@29.7.0:
+ resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
+ jest-get-type@29.6.3:
+ resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jsonwebtoken@9.0.3:
- resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==}
- engines: {node: '>=12', npm: '>=6'}
+ jest-haste-map@29.7.0:
+ resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jwa@2.0.1:
- resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==}
+ jest-leak-detector@29.7.0:
+ resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jws@4.0.1:
- resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
+ jest-matcher-utils@29.7.0:
+ resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- kleur@3.0.3:
- resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
- engines: {node: '>=6'}
+ jest-message-util@29.7.0:
+ resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-mock@29.7.0:
+ resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-pnp-resolver@1.2.3:
+ resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
+ engines: {node: '>=6'}
+ peerDependencies:
+ jest-resolve: '*'
+ peerDependenciesMeta:
+ jest-resolve:
+ optional: true
+
+ jest-regex-util@29.6.3:
+ resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-resolve-dependencies@29.7.0:
+ resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-resolve@29.7.0:
+ resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-runner@29.7.0:
+ resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-runtime@29.7.0:
+ resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-snapshot@29.7.0:
+ resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-util@29.7.0:
+ resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-validate@29.7.0:
+ resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-watcher@29.7.0:
+ resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-worker@29.7.0:
+ resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest@29.7.0:
+ resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ jiti@2.6.1:
+ resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+ hasBin: true
+
+ js-tokens@10.0.0:
+ resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@3.14.2:
+ resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
+ hasBin: true
+
+ js-yaml@4.1.1:
+ resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+ json-schema-traverse@1.0.0:
+ resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ jsonwebtoken@9.0.3:
+ resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==}
+ engines: {node: '>=12', npm: '>=6'}
+
+ jwa@2.0.1:
+ resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==}
+
+ jws@4.0.1:
+ resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
+
+ kleur@3.0.3:
+ resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+ engines: {node: '>=6'}
lazystream@1.0.1:
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
@@ -2534,9 +3228,17 @@ packages:
resolution: {integrity: sha512-JNfJ5gAn0KADvJ1I6/xMcx70+/6TL6U9gqGkKvPw5RNMfatC7jIg0Evl97HN846xmfz959BV70l8r3QsBJk30w==}
hasBin: true
+ leven@3.1.0:
+ resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
+ engines: {node: '>=6'}
+
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ locate-path@5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+
lodash.camelcase@4.3.0:
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
@@ -2561,6 +3263,9 @@ packages:
lodash.kebabcase@4.1.1:
resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==}
+ lodash.memoize@4.1.2:
+ resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
+
lodash.mergewith@4.6.2:
resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==}
@@ -2599,6 +3304,9 @@ packages:
resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==}
engines: {node: 20 || >=22}
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -2612,6 +3320,9 @@ packages:
make-error@1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+ makeerror@1.0.12:
+ resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
@@ -2668,6 +3379,9 @@ packages:
resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==}
engines: {node: '>=18'}
+ merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -2760,6 +3474,10 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
+ mimic-fn@2.1.0:
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+ engines: {node: '>=6'}
+
minimatch@10.2.4:
resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==}
engines: {node: 18 || 20 || >=22}
@@ -2794,6 +3512,12 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ neo-async@2.6.2:
+ resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+
neotraverse@0.6.18:
resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==}
engines: {node: '>= 10'}
@@ -2804,9 +3528,15 @@ packages:
node-fetch-native@1.6.7:
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
+ node-int64@0.4.0:
+ resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
+
node-mock-http@1.0.4:
resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==}
+ node-releases@2.0.36:
+ resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==}
+
normalize-package-data@6.0.2:
resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==}
engines: {node: ^16.14.0 || >=18.0.0}
@@ -2815,6 +3545,10 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
+ npm-run-path@4.0.1:
+ resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+ engines: {node: '>=8'}
+
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
@@ -2830,6 +3564,10 @@ packages:
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ onetime@5.1.2:
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+ engines: {node: '>=6'}
+
oniguruma-parser@0.12.1:
resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==}
@@ -2840,10 +3578,22 @@ packages:
resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==}
engines: {node: '>=18'}
+ p-limit@2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
p-limit@6.2.0:
resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==}
engines: {node: '>=18'}
+ p-locate@4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+
p-map@7.0.4:
resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==}
engines: {node: '>=18'}
@@ -2856,6 +3606,10 @@ packages:
resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==}
engines: {node: '>=14.16'}
+ p-try@2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
@@ -2880,14 +3634,25 @@ packages:
parse5@7.3.0:
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
path-expression-matcher@1.2.0:
resolution: {integrity: sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==}
engines: {node: '>=14.0.0'}
+ path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
@@ -2917,6 +3682,14 @@ packages:
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
+ pirates@4.0.7:
+ resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
+ engines: {node: '>= 6'}
+
+ pkg-dir@4.2.0:
+ resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
+ engines: {node: '>=8'}
+
pluralize@2.0.0:
resolution: {integrity: sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==}
@@ -2928,6 +3701,10 @@ packages:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
+ pretty-format@29.7.0:
+ resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
prismjs@1.30.0:
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
engines: {node: '>=6'}
@@ -2960,6 +3737,9 @@ packages:
pump@3.0.4:
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==}
+ pure-rand@6.1.0:
+ resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -2969,6 +3749,9 @@ packages:
rc-config-loader@4.1.4:
resolution: {integrity: sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==}
+ react-is@18.3.1:
+ resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+
read-pkg@9.0.1:
resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==}
engines: {node: '>=18'}
@@ -3039,6 +3822,10 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
+ resolve-cwd@3.0.0:
+ resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
+ engines: {node: '>=8'}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -3050,6 +3837,15 @@ packages:
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ resolve.exports@2.0.3:
+ resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
+ engines: {node: '>=10'}
+
+ resolve@1.22.11:
+ resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
retext-latin@4.0.0:
resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==}
@@ -3100,6 +3896,10 @@ packages:
engines: {node: '>=20.0.0'}
hasBin: true
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
semver@7.7.4:
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
engines: {node: '>=10'}
@@ -3138,6 +3938,10 @@ packages:
engines: {node: '>=20.19.5', npm: '>=10.8.2'}
hasBin: true
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
slash@5.1.0:
resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
engines: {node: '>=14.16'}
@@ -3154,6 +3958,13 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ source-map-support@0.5.13:
+ resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
+
+ source-map@0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+
space-separated-tokens@2.0.2:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
@@ -3176,6 +3987,9 @@ packages:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
+ sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+
ssh-remote-port-forward@1.0.4:
resolution: {integrity: sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ==}
@@ -3183,6 +3997,10 @@ packages:
resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==}
engines: {node: '>=10.16.0'}
+ stack-utils@2.0.6:
+ resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+ engines: {node: '>=10'}
+
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
@@ -3195,6 +4013,10 @@ packages:
streamx@2.23.0:
resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==}
+ string-length@4.0.2:
+ resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
+ engines: {node: '>=10'}
+
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -3224,6 +4046,18 @@ packages:
resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
engines: {node: '>=12'}
+ strip-bom@4.0.0:
+ resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
+ engines: {node: '>=8'}
+
+ strip-final-newline@2.0.0:
+ resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+ engines: {node: '>=6'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
strnum@2.2.0:
resolution: {integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==}
@@ -3234,10 +4068,18 @@ packages:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
+ supports-color@8.1.1:
+ resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+ engines: {node: '>=10'}
+
supports-hyperlinks@3.2.0:
resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==}
engines: {node: '>=14.18'}
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
svgo@4.0.1:
resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==}
engines: {node: '>=16'}
@@ -3267,6 +4109,10 @@ packages:
resolution: {integrity: sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==}
engines: {node: '>=18'}
+ test-exclude@6.0.0:
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+ engines: {node: '>=8'}
+
testcontainers@11.12.0:
resolution: {integrity: sha512-VWtH+UQejVYYvb53ohEZRbx2naxyDvwO9lQ6A0VgmVE2Oh8r9EF09I+BfmrXpd9N9ntpzhao9di2yNwibSz5KA==}
@@ -3302,6 +4148,9 @@ packages:
resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==}
engines: {node: '>=14.14'}
+ tmpl@1.0.5:
+ resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -3312,6 +4161,33 @@ packages:
trough@2.2.0:
resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
+ ts-jest@29.4.6:
+ resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@babel/core': '>=7.0.0-beta.0 <8'
+ '@jest/transform': ^29.0.0 || ^30.0.0
+ '@jest/types': ^29.0.0 || ^30.0.0
+ babel-jest: ^29.0.0 || ^30.0.0
+ esbuild: '*'
+ jest: ^29.0.0 || ^30.0.0
+ jest-util: ^29.0.0 || ^30.0.0
+ typescript: '>=4.3 <6'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ '@jest/transform':
+ optional: true
+ '@jest/types':
+ optional: true
+ babel-jest:
+ optional: true
+ esbuild:
+ optional: true
+ jest-util:
+ optional: true
+
ts-node@10.9.2:
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
hasBin: true
@@ -3347,6 +4223,14 @@ packages:
tweetnacl@0.14.5:
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
+ type-detect@4.0.8:
+ resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ engines: {node: '>=4'}
+
+ type-fest@0.21.3:
+ resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+ engines: {node: '>=10'}
+
type-fest@4.41.0:
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
engines: {node: '>=16'}
@@ -3359,6 +4243,11 @@ packages:
ufo@1.6.3:
resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
+ uglify-js@3.19.3:
+ resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
+ engines: {node: '>=0.8.0'}
+ hasBin: true
+
ultrahtml@1.6.0:
resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
@@ -3481,6 +4370,12 @@ packages:
uploadthing:
optional: true
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -3495,6 +4390,10 @@ packages:
v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+ v8-to-istanbul@9.3.0:
+ resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
+ engines: {node: '>=10.12.0'}
+
validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
@@ -3633,6 +4532,9 @@ packages:
jsdom:
optional: true
+ walker@1.0.8:
+ resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+
web-namespaces@2.0.1:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
@@ -3654,6 +4556,9 @@ packages:
resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==}
engines: {node: '>=18'}
+ wordwrap@1.0.0:
+ resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
@@ -3669,6 +4574,10 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ write-file-atomic@4.0.2:
+ resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
+ engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+
wsl-utils@0.1.0:
resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==}
engines: {node: '>=18'}
@@ -3680,6 +4589,9 @@ packages:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
yaml@2.8.3:
resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==}
engines: {node: '>= 14.6'}
@@ -3697,6 +4609,10 @@ packages:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
engines: {node: '>=6'}
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
yocto-queue@1.2.2:
resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==}
engines: {node: '>=12.20'}
@@ -3787,6 +4703,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@aws-cdk/asset-awscli-v1@2.2.263': {}
+
+ '@aws-cdk/asset-node-proxy-agent-v6@2.1.1': {}
+
+ '@aws-cdk/cloud-assembly-schema@52.2.0': {}
+
'@aws-crypto/sha256-browser@5.2.0':
dependencies:
'@aws-crypto/sha256-js': 5.2.0
@@ -4349,14 +5271,182 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.1.1
+ '@babel/compat-data@7.29.0': {}
+
+ '@babel/core@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-compilation-targets': 7.28.6
+ '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
+ '@babel/helpers': 7.29.2
+ '@babel/parser': 7.29.0
+ '@babel/template': 7.28.6
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.1':
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.28.6':
+ dependencies:
+ '@babel/compat-data': 7.29.0
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.28.1
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.28.6':
+ dependencies:
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-module-imports': 7.28.6
+ '@babel/helper-validator-identifier': 7.28.5
+ '@babel/traverse': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.28.6': {}
+
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.28.5': {}
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.29.2':
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+
'@babel/parser@7.29.0':
dependencies:
'@babel/types': 7.29.0
+ '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/template@7.28.6':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+
+ '@babel/traverse@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.29.0
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/types@7.29.0':
dependencies:
'@babel/helper-string-parser': 7.27.1
@@ -4364,6 +5454,8 @@ snapshots:
'@balena/dockerignore@1.0.2': {}
+ '@bcoe/v8-coverage@0.2.3': {}
+
'@bcoe/v8-coverage@1.0.2': {}
'@biomejs/biome@2.4.5':
@@ -4832,16 +5924,198 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@jridgewell/resolve-uri@3.1.2': {}
+ '@istanbuljs/load-nyc-config@1.1.0':
+ dependencies:
+ camelcase: 5.3.1
+ find-up: 4.1.0
+ get-package-type: 0.1.0
+ js-yaml: 3.14.2
+ resolve-from: 5.0.0
- '@jridgewell/sourcemap-codec@1.5.5': {}
+ '@istanbuljs/schema@0.1.3': {}
- '@jridgewell/trace-mapping@0.3.31':
+ '@jest/console@29.7.0':
dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.5
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ chalk: 4.1.2
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ slash: 3.0.0
- '@jridgewell/trace-mapping@0.3.9':
+ '@jest/core@29.7.0(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))':
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/reporters': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-changed-files: 29.7.0
+ jest-config: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ jest-haste-map: 29.7.0
+ jest-message-util: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-resolve-dependencies: 29.7.0
+ jest-runner: 29.7.0
+ jest-runtime: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ jest-watcher: 29.7.0
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-ansi: 6.0.1
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ '@jest/environment@29.7.0':
+ dependencies:
+ '@jest/fake-timers': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ jest-mock: 29.7.0
+
+ '@jest/expect-utils@29.7.0':
+ dependencies:
+ jest-get-type: 29.6.3
+
+ '@jest/expect@29.7.0':
+ dependencies:
+ expect: 29.7.0
+ jest-snapshot: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/fake-timers@29.7.0':
+ dependencies:
+ '@jest/types': 29.6.3
+ '@sinonjs/fake-timers': 10.3.0
+ '@types/node': 25.3.3
+ jest-message-util: 29.7.0
+ jest-mock: 29.7.0
+ jest-util: 29.7.0
+
+ '@jest/globals@29.7.0':
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/expect': 29.7.0
+ '@jest/types': 29.6.3
+ jest-mock: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/reporters@29.7.0':
+ dependencies:
+ '@bcoe/v8-coverage': 0.2.3
+ '@jest/console': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@jridgewell/trace-mapping': 0.3.31
+ '@types/node': 25.3.3
+ chalk: 4.1.2
+ collect-v8-coverage: 1.0.3
+ exit: 0.1.2
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-instrument: 6.0.3
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 4.0.1
+ istanbul-reports: 3.2.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ jest-worker: 29.7.0
+ slash: 3.0.0
+ string-length: 4.0.2
+ strip-ansi: 6.0.1
+ v8-to-istanbul: 9.3.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/schemas@29.6.3':
+ dependencies:
+ '@sinclair/typebox': 0.27.10
+
+ '@jest/source-map@29.6.3':
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ callsites: 3.1.0
+ graceful-fs: 4.2.11
+
+ '@jest/test-result@29.7.0':
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ collect-v8-coverage: 1.0.3
+
+ '@jest/test-sequencer@29.7.0':
+ dependencies:
+ '@jest/test-result': 29.7.0
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ slash: 3.0.0
+
+ '@jest/transform@29.7.0':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@jest/types': 29.6.3
+ '@jridgewell/trace-mapping': 0.3.31
+ babel-plugin-istanbul: 6.1.1
+ chalk: 4.1.2
+ convert-source-map: 2.0.0
+ fast-json-stable-stringify: 2.1.0
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-util: 29.7.0
+ micromatch: 4.0.8
+ pirates: 4.0.7
+ slash: 3.0.0
+ write-file-atomic: 4.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/types@29.6.3':
+ dependencies:
+ '@jest/schemas': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ '@types/istanbul-reports': 3.0.4
+ '@types/node': 25.3.3
+ '@types/yargs': 17.0.35
+ chalk: 4.1.2
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@jridgewell/trace-mapping@0.3.9':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
@@ -5078,8 +6352,18 @@ snapshots:
'@simple-libs/stream-utils@1.2.0': {}
+ '@sinclair/typebox@0.27.10': {}
+
'@sindresorhus/merge-streams@2.3.0': {}
+ '@sinonjs/commons@3.0.1':
+ dependencies:
+ type-detect: 4.0.8
+
+ '@sinonjs/fake-timers@10.3.0':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+
'@smithy/abort-controller@4.2.12':
dependencies:
'@smithy/types': 4.13.1
@@ -5409,6 +6693,27 @@ snapshots:
'@tsconfig/node16@1.0.4': {}
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
'@types/chai@5.2.3':
dependencies:
'@types/deep-eql': 4.0.2
@@ -5433,10 +6738,29 @@ snapshots:
'@types/estree@1.0.8': {}
+ '@types/graceful-fs@4.1.9':
+ dependencies:
+ '@types/node': 25.3.3
+
'@types/hast@3.0.4':
dependencies:
'@types/unist': 3.0.3
+ '@types/istanbul-lib-coverage@2.0.6': {}
+
+ '@types/istanbul-lib-report@3.0.3':
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.6
+
+ '@types/istanbul-reports@3.0.4':
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.3
+
+ '@types/jest@29.5.14':
+ dependencies:
+ expect: 29.7.0
+ pretty-format: 29.7.0
+
'@types/mdast@4.0.4':
dependencies:
'@types/unist': 3.0.3
@@ -5478,8 +6802,16 @@ snapshots:
dependencies:
'@types/node': 18.19.130
+ '@types/stack-utils@2.0.3': {}
+
'@types/unist@3.0.3': {}
+ '@types/yargs-parser@21.0.3': {}
+
+ '@types/yargs@17.0.35':
+ dependencies:
+ '@types/yargs-parser': 21.0.3
+
'@typespec/ts-http-runtime@0.3.3':
dependencies:
http-proxy-agent: 7.0.2
@@ -5568,6 +6900,10 @@ snapshots:
dependencies:
string-width: 4.2.3
+ ansi-escapes@4.3.2:
+ dependencies:
+ type-fest: 0.21.3
+
ansi-escapes@7.3.0:
dependencies:
environment: 1.1.0
@@ -5580,6 +6916,8 @@ snapshots:
dependencies:
color-convert: 2.0.1
+ ansi-styles@5.2.0: {}
+
ansi-styles@6.2.3: {}
anymatch@3.1.3:
@@ -5615,6 +6953,10 @@ snapshots:
arg@5.0.2: {}
+ argparse@1.0.10:
+ dependencies:
+ sprintf-js: 1.0.3
+
argparse@2.0.1: {}
aria-query@5.3.2: {}
@@ -5743,10 +7085,74 @@ snapshots:
async@3.2.6: {}
+ aws-cdk-lib@2.244.0(constructs@10.6.0):
+ dependencies:
+ '@aws-cdk/asset-awscli-v1': 2.2.263
+ '@aws-cdk/asset-node-proxy-agent-v6': 2.1.1
+ '@aws-cdk/cloud-assembly-schema': 52.2.0
+ constructs: 10.6.0
+
+ aws-cdk@2.1114.1: {}
+
axobject-query@4.1.0: {}
b4a@1.8.0: {}
+ babel-jest@29.7.0(@babel/core@7.29.0):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@jest/transform': 29.7.0
+ '@types/babel__core': 7.20.5
+ babel-plugin-istanbul: 6.1.1
+ babel-preset-jest: 29.6.3(@babel/core@7.29.0)
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ slash: 3.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-istanbul@6.1.1:
+ dependencies:
+ '@babel/helper-plugin-utils': 7.28.6
+ '@istanbuljs/load-nyc-config': 1.1.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-instrument: 5.2.1
+ test-exclude: 6.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-jest-hoist@29.6.3:
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ '@types/babel__core': 7.20.5
+ '@types/babel__traverse': 7.28.0
+
+ babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0)
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0)
+ '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0)
+
+ babel-preset-jest@29.6.3(@babel/core@7.29.0):
+ dependencies:
+ '@babel/core': 7.29.0
+ babel-plugin-jest-hoist: 29.6.3
+ babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
+
bail@2.0.2: {}
balanced-match@4.0.4: {}
@@ -5788,6 +7194,8 @@ snapshots:
base64-js@1.5.1: {}
+ baseline-browser-mapping@2.10.11: {}
+
bcrypt-pbkdf@1.0.2:
dependencies:
tweetnacl: 0.14.5
@@ -5827,10 +7235,28 @@ snapshots:
dependencies:
fill-range: 7.1.1
+ browserslist@4.28.1:
+ dependencies:
+ baseline-browser-mapping: 2.10.11
+ caniuse-lite: 1.0.30001781
+ electron-to-chromium: 1.5.328
+ node-releases: 2.0.36
+ update-browserslist-db: 1.2.3(browserslist@4.28.1)
+
+ bs-logger@0.2.6:
+ dependencies:
+ fast-json-stable-stringify: 2.1.0
+
+ bser@2.1.1:
+ dependencies:
+ node-int64: 0.4.0
+
buffer-crc32@1.0.0: {}
buffer-equal-constant-time@1.0.1: {}
+ buffer-from@1.1.2: {}
+
buffer@5.7.1:
dependencies:
base64-js: 1.5.1
@@ -5852,8 +7278,14 @@ snapshots:
callsites@3.1.0: {}
+ camelcase@5.3.1: {}
+
+ camelcase@6.3.0: {}
+
camelcase@8.0.0: {}
+ caniuse-lite@1.0.30001781: {}
+
ccount@2.0.1: {}
chai@6.2.2: {}
@@ -5865,6 +7297,8 @@ snapshots:
chalk@5.6.2: {}
+ char-regex@1.0.2: {}
+
character-entities-html4@2.1.0: {}
character-entities-legacy@3.0.0: {}
@@ -5877,8 +7311,12 @@ snapshots:
chownr@1.1.4: {}
+ ci-info@3.9.0: {}
+
ci-info@4.4.0: {}
+ cjs-module-lexer@1.4.3: {}
+
cli-boxes@3.0.0: {}
cliui@8.0.1:
@@ -5889,6 +7327,10 @@ snapshots:
clsx@2.1.1: {}
+ co@4.6.0: {}
+
+ collect-v8-coverage@1.0.3: {}
+
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@@ -5916,6 +7358,8 @@ snapshots:
normalize-path: 3.0.0
readable-stream: 4.7.0
+ constructs@10.6.0: {}
+
conventional-changelog-angular@8.3.0:
dependencies:
compare-func: 2.0.0
@@ -5929,6 +7373,8 @@ snapshots:
'@simple-libs/stream-utils': 1.2.0
meow: 13.2.0
+ convert-source-map@2.0.0: {}
+
cookie-es@1.2.2: {}
cookie@1.1.1: {}
@@ -5964,6 +7410,21 @@ snapshots:
crc-32: 1.2.2
readable-stream: 4.7.0
+ create-jest@29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3)):
+ dependencies:
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-config: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ jest-util: 29.7.0
+ prompts: 2.4.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
create-require@1.1.1: {}
cross-spawn@7.0.6:
@@ -6012,6 +7473,10 @@ snapshots:
dependencies:
character-entities: 2.0.2
+ dedent@1.7.2: {}
+
+ deepmerge@4.3.1: {}
+
default-browser-id@5.0.1: {}
default-browser@5.5.0:
@@ -6030,6 +7495,8 @@ snapshots:
detect-libc@2.1.2:
optional: true
+ detect-newline@3.1.0: {}
+
deterministic-object-hash@2.0.2:
dependencies:
base-64: 1.0.0
@@ -6040,6 +7507,8 @@ snapshots:
dependencies:
dequal: 2.0.3
+ diff-sequences@29.6.3: {}
+
diff@4.0.4: {}
diff@8.0.4: {}
@@ -6107,6 +7576,10 @@ snapshots:
dependencies:
version-range: 4.15.0
+ electron-to-chromium@1.5.328: {}
+
+ emittery@0.13.1: {}
+
emoji-regex@10.6.0: {}
emoji-regex@8.0.0: {}
@@ -6191,8 +7664,12 @@ snapshots:
escalade@3.2.0: {}
+ escape-string-regexp@2.0.0: {}
+
escape-string-regexp@5.0.0: {}
+ esprima@4.0.1: {}
+
estree-walker@2.0.2: {}
estree-walker@3.0.3:
@@ -6211,8 +7688,30 @@ snapshots:
events@3.3.0: {}
+ execa@5.1.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ get-stream: 6.0.1
+ human-signals: 2.1.0
+ is-stream: 2.0.1
+ merge-stream: 2.0.0
+ npm-run-path: 4.0.1
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ strip-final-newline: 2.0.0
+
+ exit@0.1.2: {}
+
expect-type@1.3.0: {}
+ expect@29.7.0:
+ dependencies:
+ '@jest/expect-utils': 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+
extend@3.0.2: {}
fast-deep-equal@3.1.3: {}
@@ -6227,6 +7726,8 @@ snapshots:
merge2: 1.4.1
micromatch: 4.0.8
+ fast-json-stable-stringify@2.1.0: {}
+
fast-uri@3.1.0: {}
fast-xml-builder@1.1.4:
@@ -6243,6 +7744,10 @@ snapshots:
dependencies:
reusify: 1.1.0
+ fb-watchman@2.0.2:
+ dependencies:
+ bser: 2.1.1
+
fdir@6.5.0(picomatch@4.0.4):
optionalDependencies:
picomatch: 4.0.4
@@ -6251,6 +7756,11 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
+ find-up@4.1.0:
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+
flattie@1.1.1: {}
fontace@0.4.1:
@@ -6268,15 +7778,25 @@ snapshots:
fs-constants@1.0.0: {}
+ fs.realpath@1.0.0: {}
+
fsevents@2.3.3:
optional: true
+ function-bind@1.1.2: {}
+
+ gensync@1.0.0-beta.2: {}
+
get-caller-file@2.0.5: {}
get-east-asian-width@1.5.0: {}
+ get-package-type@0.1.0: {}
+
get-port@7.1.0: {}
+ get-stream@6.0.1: {}
+
get-tsconfig@4.13.7:
dependencies:
resolve-pkg-maps: 1.0.0
@@ -6308,6 +7828,15 @@ snapshots:
minipass: 7.1.3
path-scurry: 2.0.2
+ glob@7.2.3:
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 10.2.4
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+
global-directory@4.0.1:
dependencies:
ini: 4.1.1
@@ -6335,8 +7864,21 @@ snapshots:
ufo: 1.6.3
uncrypto: 0.1.3
+ handlebars@4.7.9:
+ dependencies:
+ minimist: 1.2.8
+ neo-async: 2.6.2
+ source-map: 0.6.1
+ wordwrap: 1.0.0
+ optionalDependencies:
+ uglify-js: 3.19.3
+
has-flag@4.0.0: {}
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
hast-util-from-html@2.0.3:
dependencies:
'@types/hast': 3.0.4
@@ -6450,6 +7992,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ human-signals@2.1.0: {}
+
ieee754@1.2.1: {}
ignore@7.0.5: {}
@@ -6459,10 +8003,22 @@ snapshots:
parent-module: 1.0.1
resolve-from: 4.0.0
+ import-local@3.2.0:
+ dependencies:
+ pkg-dir: 4.2.0
+ resolve-cwd: 3.0.0
+
import-meta-resolve@4.2.0: {}
+ imurmurhash@0.1.4: {}
+
index-to-position@1.2.0: {}
+ inflight@1.0.6:
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+
inherits@2.0.4: {}
ini@4.1.1: {}
@@ -6479,12 +8035,18 @@ snapshots:
is-arrayish@0.2.1: {}
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
is-docker@3.0.0: {}
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {}
+ is-generator-fn@2.1.0: {}
+
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
@@ -6511,12 +8073,40 @@ snapshots:
istanbul-lib-coverage@3.2.2: {}
+ istanbul-lib-instrument@5.2.1:
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/parser': 7.29.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.2
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-lib-instrument@6.0.3:
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/parser': 7.29.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.2
+ semver: 7.7.4
+ transitivePeerDependencies:
+ - supports-color
+
istanbul-lib-report@3.0.1:
dependencies:
istanbul-lib-coverage: 3.2.2
make-dir: 4.0.0
supports-color: 7.2.0
+ istanbul-lib-source-maps@4.0.1:
+ dependencies:
+ debug: 4.4.3
+ istanbul-lib-coverage: 3.2.2
+ source-map: 0.6.1
+ transitivePeerDependencies:
+ - supports-color
+
istanbul-reports@3.2.0:
dependencies:
html-escaper: 2.0.2
@@ -6534,16 +8124,332 @@ snapshots:
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
+ jest-changed-files@29.7.0:
+ dependencies:
+ execa: 5.1.1
+ jest-util: 29.7.0
+ p-limit: 3.1.0
+
+ jest-circus@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/expect': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ chalk: 4.1.2
+ co: 4.6.0
+ dedent: 1.7.2
+ is-generator-fn: 2.1.0
+ jest-each: 29.7.0
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-runtime: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ p-limit: 3.1.0
+ pretty-format: 29.7.0
+ pure-rand: 6.1.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-cli@29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ create-jest: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ exit: 0.1.2
+ import-local: 3.2.0
+ jest-config: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ jest-config@29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3)):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@jest/test-sequencer': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.29.0)
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ deepmerge: 4.3.1
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-circus: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-get-type: 29.6.3
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-runner: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ micromatch: 4.0.8
+ parse-json: 5.2.0
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-json-comments: 3.1.1
+ optionalDependencies:
+ '@types/node': 25.3.3
+ ts-node: 10.9.2(@types/node@25.3.3)(typescript@5.9.3)
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-diff@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ diff-sequences: 29.6.3
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-docblock@29.7.0:
+ dependencies:
+ detect-newline: 3.1.0
+
+ jest-each@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ jest-get-type: 29.6.3
+ jest-util: 29.7.0
+ pretty-format: 29.7.0
+
+ jest-environment-node@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/fake-timers': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ jest-mock: 29.7.0
+ jest-util: 29.7.0
+
+ jest-get-type@29.6.3: {}
+
+ jest-haste-map@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/graceful-fs': 4.1.9
+ '@types/node': 25.3.3
+ anymatch: 3.1.3
+ fb-watchman: 2.0.2
+ graceful-fs: 4.2.11
+ jest-regex-util: 29.6.3
+ jest-util: 29.7.0
+ jest-worker: 29.7.0
+ micromatch: 4.0.8
+ walker: 1.0.8
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ jest-leak-detector@29.7.0:
+ dependencies:
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-matcher-utils@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-message-util@29.7.0:
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@jest/types': 29.6.3
+ '@types/stack-utils': 2.0.3
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+
+ jest-mock@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ jest-util: 29.7.0
+
+ jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
+ optionalDependencies:
+ jest-resolve: 29.7.0
+
+ jest-regex-util@29.6.3: {}
+
+ jest-resolve-dependencies@29.7.0:
+ dependencies:
+ jest-regex-util: 29.6.3
+ jest-snapshot: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-resolve@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ resolve: 1.22.11
+ resolve.exports: 2.0.3
+ slash: 3.0.0
+
+ jest-runner@29.7.0:
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/environment': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ chalk: 4.1.2
+ emittery: 0.13.1
+ graceful-fs: 4.2.11
+ jest-docblock: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-haste-map: 29.7.0
+ jest-leak-detector: 29.7.0
+ jest-message-util: 29.7.0
+ jest-resolve: 29.7.0
+ jest-runtime: 29.7.0
+ jest-util: 29.7.0
+ jest-watcher: 29.7.0
+ jest-worker: 29.7.0
+ p-limit: 3.1.0
+ source-map-support: 0.5.13
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-runtime@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/fake-timers': 29.7.0
+ '@jest/globals': 29.7.0
+ '@jest/source-map': 29.6.3
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ chalk: 4.1.2
+ cjs-module-lexer: 1.4.3
+ collect-v8-coverage: 1.0.3
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-message-util: 29.7.0
+ jest-mock: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ slash: 3.0.0
+ strip-bom: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-snapshot@29.7.0:
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
+ '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0)
+ '@babel/types': 7.29.0
+ '@jest/expect-utils': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
+ chalk: 4.1.2
+ expect: 29.7.0
+ graceful-fs: 4.2.11
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ natural-compare: 1.4.0
+ pretty-format: 29.7.0
+ semver: 7.7.4
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-util@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ graceful-fs: 4.2.11
+ picomatch: 2.3.2
+
+ jest-validate@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ camelcase: 6.3.0
+ chalk: 4.1.2
+ jest-get-type: 29.6.3
+ leven: 3.1.0
+ pretty-format: 29.7.0
+
+ jest-watcher@29.7.0:
+ dependencies:
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.3.3
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ emittery: 0.13.1
+ jest-util: 29.7.0
+ string-length: 4.0.2
+
+ jest-worker@29.7.0:
+ dependencies:
+ '@types/node': 25.3.3
+ jest-util: 29.7.0
+ merge-stream: 2.0.0
+ supports-color: 8.1.1
+
+ jest@29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ '@jest/types': 29.6.3
+ import-local: 3.2.0
+ jest-cli: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
jiti@2.6.1: {}
js-tokens@10.0.0: {}
js-tokens@4.0.0: {}
+ js-yaml@3.14.2:
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
+ jsesc@3.1.0: {}
+
json-parse-even-better-errors@2.3.1: {}
json-schema-traverse@1.0.0: {}
@@ -6623,8 +8529,14 @@ snapshots:
lefthook-windows-arm64: 2.1.4
lefthook-windows-x64: 2.1.4
+ leven@3.1.0: {}
+
lines-and-columns@1.2.4: {}
+ locate-path@5.0.0:
+ dependencies:
+ p-locate: 4.1.0
+
lodash.camelcase@4.3.0: {}
lodash.includes@4.3.0: {}
@@ -6641,6 +8553,8 @@ snapshots:
lodash.kebabcase@4.1.1: {}
+ lodash.memoize@4.1.2: {}
+
lodash.mergewith@4.6.2: {}
lodash.once@4.1.1: {}
@@ -6665,6 +8579,10 @@ snapshots:
lru-cache@11.2.7: {}
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -6681,6 +8599,10 @@ snapshots:
make-error@1.3.6: {}
+ makeerror@1.0.12:
+ dependencies:
+ tmpl: 1.0.5
+
markdown-table@3.0.4: {}
mdast-util-definitions@6.0.0:
@@ -6811,6 +8733,8 @@ snapshots:
meow@13.2.0: {}
+ merge-stream@2.0.0: {}
+
merge2@1.4.1: {}
micromark-core-commonmark@2.0.3:
@@ -7009,6 +8933,8 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.2
+ mimic-fn@2.1.0: {}
+
minimatch@10.2.4:
dependencies:
brace-expansion: 5.0.4
@@ -7030,6 +8956,10 @@ snapshots:
nanoid@3.3.11: {}
+ natural-compare@1.4.0: {}
+
+ neo-async@2.6.2: {}
+
neotraverse@0.6.18: {}
nlcst-to-string@4.0.0:
@@ -7038,8 +8968,12 @@ snapshots:
node-fetch-native@1.6.7: {}
+ node-int64@0.4.0: {}
+
node-mock-http@1.0.4: {}
+ node-releases@2.0.36: {}
+
normalize-package-data@6.0.2:
dependencies:
hosted-git-info: 7.0.2
@@ -7048,6 +8982,10 @@ snapshots:
normalize-path@3.0.0: {}
+ npm-run-path@4.0.1:
+ dependencies:
+ path-key: 3.1.1
+
nth-check@2.1.1:
dependencies:
boolbase: 1.0.0
@@ -7066,6 +9004,10 @@ snapshots:
dependencies:
wrappy: 1.0.2
+ onetime@5.1.2:
+ dependencies:
+ mimic-fn: 2.1.0
+
oniguruma-parser@0.12.1: {}
oniguruma-to-es@4.3.5:
@@ -7081,10 +9023,22 @@ snapshots:
is-inside-container: 1.0.0
wsl-utils: 0.1.0
+ p-limit@2.3.0:
+ dependencies:
+ p-try: 2.2.0
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
p-limit@6.2.0:
dependencies:
yocto-queue: 1.2.2
+ p-locate@4.1.0:
+ dependencies:
+ p-limit: 2.3.0
+
p-map@7.0.4: {}
p-queue@8.1.1:
@@ -7094,6 +9048,8 @@ snapshots:
p-timeout@6.1.4: {}
+ p-try@2.2.0: {}
+
package-json-from-dist@1.0.1: {}
package-manager-detector@1.6.0: {}
@@ -7128,10 +9084,16 @@ snapshots:
dependencies:
entities: 6.0.1
+ path-exists@4.0.0: {}
+
path-expression-matcher@1.2.0: {}
+ path-is-absolute@1.0.1: {}
+
path-key@3.1.1: {}
+ path-parse@1.0.7: {}
+
path-scurry@1.11.1:
dependencies:
lru-cache: 10.4.3
@@ -7154,6 +9116,12 @@ snapshots:
picomatch@4.0.4: {}
+ pirates@4.0.7: {}
+
+ pkg-dir@4.2.0:
+ dependencies:
+ find-up: 4.1.0
+
pluralize@2.0.0: {}
pluralize@8.0.0: {}
@@ -7164,6 +9132,12 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
+ pretty-format@29.7.0:
+ dependencies:
+ '@jest/schemas': 29.6.3
+ ansi-styles: 5.2.0
+ react-is: 18.3.1
+
prismjs@1.30.0: {}
process-nextick-args@2.0.1: {}
@@ -7210,6 +9184,8 @@ snapshots:
end-of-stream: 1.4.5
once: 1.4.0
+ pure-rand@6.1.0: {}
+
queue-microtask@1.2.3: {}
radix3@1.1.2: {}
@@ -7223,6 +9199,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ react-is@18.3.1: {}
+
read-pkg@9.0.1:
dependencies:
'@types/normalize-package-data': 2.4.4
@@ -7343,12 +9321,24 @@ snapshots:
require-from-string@2.0.2: {}
+ resolve-cwd@3.0.0:
+ dependencies:
+ resolve-from: 5.0.0
+
resolve-from@4.0.0: {}
resolve-from@5.0.0: {}
resolve-pkg-maps@1.0.0: {}
+ resolve.exports@2.0.3: {}
+
+ resolve@1.22.11:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
retext-latin@4.0.0:
dependencies:
'@types/nlcst': 2.0.3
@@ -7436,6 +9426,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ semver@6.3.1: {}
+
semver@7.7.4: {}
sharp@0.34.5:
@@ -7502,6 +9494,8 @@ snapshots:
arg: 5.0.2
sax: 1.6.0
+ slash@3.0.0: {}
+
slash@5.1.0: {}
slice-ansi@4.0.0:
@@ -7514,6 +9508,13 @@ snapshots:
source-map-js@1.2.1: {}
+ source-map-support@0.5.13:
+ dependencies:
+ buffer-from: 1.1.2
+ source-map: 0.6.1
+
+ source-map@0.6.1: {}
+
space-separated-tokens@2.0.2: {}
spdx-correct@3.2.0:
@@ -7534,6 +9535,8 @@ snapshots:
split2@4.2.0: {}
+ sprintf-js@1.0.3: {}
+
ssh-remote-port-forward@1.0.4:
dependencies:
'@types/ssh2': 0.5.52
@@ -7547,6 +9550,10 @@ snapshots:
cpu-features: 0.0.10
nan: 2.25.0
+ stack-utils@2.0.6:
+ dependencies:
+ escape-string-regexp: 2.0.0
+
stackback@0.0.2: {}
std-env@3.10.0: {}
@@ -7562,6 +9569,11 @@ snapshots:
- bare-abort-controller
- react-native-b4a
+ string-length@4.0.2:
+ dependencies:
+ char-regex: 1.0.2
+ strip-ansi: 6.0.1
+
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
@@ -7601,6 +9613,12 @@ snapshots:
dependencies:
ansi-regex: 6.2.2
+ strip-bom@4.0.0: {}
+
+ strip-final-newline@2.0.0: {}
+
+ strip-json-comments@3.1.1: {}
+
strnum@2.2.0: {}
structured-source@4.0.0:
@@ -7611,11 +9629,17 @@ snapshots:
dependencies:
has-flag: 4.0.0
+ supports-color@8.1.1:
+ dependencies:
+ has-flag: 4.0.0
+
supports-hyperlinks@3.2.0:
dependencies:
has-flag: 4.0.0
supports-color: 7.2.0
+ supports-preserve-symlinks-flag@1.0.0: {}
+
svgo@4.0.1:
dependencies:
commander: 11.1.0
@@ -7684,6 +9708,12 @@ snapshots:
ansi-escapes: 7.3.0
supports-hyperlinks: 3.2.0
+ test-exclude@6.0.0:
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 7.2.3
+ minimatch: 10.2.4
+
testcontainers@11.12.0:
dependencies:
'@balena/dockerignore': 1.0.2
@@ -7734,6 +9764,8 @@ snapshots:
tmp@0.2.5: {}
+ tmpl@1.0.5: {}
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -7742,6 +9774,26 @@ snapshots:
trough@2.2.0: {}
+ ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3)))(typescript@5.9.3):
+ dependencies:
+ bs-logger: 0.2.6
+ fast-json-stable-stringify: 2.1.0
+ handlebars: 4.7.9
+ jest: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
+ json5: 2.2.3
+ lodash.memoize: 4.1.2
+ make-error: 1.3.6
+ semver: 7.7.4
+ type-fest: 4.41.0
+ typescript: 5.9.3
+ yargs-parser: 21.1.1
+ optionalDependencies:
+ '@babel/core': 7.29.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.29.0)
+ jest-util: 29.7.0
+
ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
@@ -7775,12 +9827,19 @@ snapshots:
tweetnacl@0.14.5: {}
+ type-detect@4.0.8: {}
+
+ type-fest@0.21.3: {}
+
type-fest@4.41.0: {}
typescript@5.9.3: {}
ufo@1.6.3: {}
+ uglify-js@3.19.3:
+ optional: true
+
ultrahtml@1.6.0: {}
uncrypto@0.1.3: {}
@@ -7869,6 +9928,12 @@ snapshots:
'@azure/identity': 4.13.0
'@azure/keyvault-secrets': 4.10.0(@azure/core-client@1.10.1)
+ update-browserslist-db@1.2.3(browserslist@4.28.1):
+ dependencies:
+ browserslist: 4.28.1
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
util-deprecate@1.0.2: {}
uuid@10.0.0: {}
@@ -7877,6 +9942,12 @@ snapshots:
v8-compile-cache-lib@3.0.1: {}
+ v8-to-istanbul@9.3.0:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ '@types/istanbul-lib-coverage': 2.0.6
+ convert-source-map: 2.0.0
+
validate-npm-package-license@3.0.4:
dependencies:
spdx-correct: 3.2.0
@@ -7970,6 +10041,10 @@ snapshots:
- tsx
- yaml
+ walker@1.0.8:
+ dependencies:
+ makeerror: 1.0.12
+
web-namespaces@2.0.1: {}
which-pm-runs@1.1.0: {}
@@ -7987,6 +10062,8 @@ snapshots:
dependencies:
string-width: 7.2.0
+ wordwrap@1.0.0: {}
+
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
@@ -8007,6 +10084,11 @@ snapshots:
wrappy@1.0.2: {}
+ write-file-atomic@4.0.2:
+ dependencies:
+ imurmurhash: 0.1.4
+ signal-exit: 3.0.7
+
wsl-utils@0.1.0:
dependencies:
is-wsl: 3.1.1
@@ -8015,6 +10097,8 @@ snapshots:
y18n@5.0.8: {}
+ yallist@3.1.1: {}
+
yaml@2.8.3: {}
yargs-parser@21.1.1: {}
@@ -8031,6 +10115,8 @@ snapshots:
yn@3.1.1: {}
+ yocto-queue@0.1.0: {}
+
yocto-queue@1.2.2: {}
yocto-spinner@0.2.3:
diff --git a/src/iac/.gitignore b/src/iac/.gitignore
new file mode 100644
index 00000000..64a52dba
--- /dev/null
+++ b/src/iac/.gitignore
@@ -0,0 +1,19 @@
+*.js
+!jest.config.js
+*.d.ts
+node_modules
+
+# CDK asset staging directory
+.cdk.staging
+**/cdk.out/
+**/dist/
+**/coverage/
+
+# Custom files
+coverage
+*.js.map
+!*.snap
+!bin
+
+yarn.lock
+cdk.context.json
\ No newline at end of file
diff --git a/src/iac/.instructions.md b/src/iac/.instructions.md
new file mode 100644
index 00000000..3e2b5fc9
--- /dev/null
+++ b/src/iac/.instructions.md
@@ -0,0 +1,39 @@
+---
+applyTo: "src/iac/**"
+---
+
+## CDK Infrastructure Rules (TypeScript)
+
+AWS CDK infrastructure-as-code for the Envilder project. Deploys the static
+website (Astro) and CI/CD pipeline.
+
+### Structure
+
+- `src/infra/iac.ts` — Entry point. Creates CDK App and calls DeployInfrastructureHandler
+- `src/infra/iacConfig.ts` — Top-level deployment config
+- `src/infra/config/` — Per-layer config: `frontendConfig.ts`, `sharedConfig.ts`
+- `src/infra/buildspecs/` — CodeBuild specs for test and production phases
+- `src/aws/` — CDK stack constructs (website, pipeline, VPC)
+- `src/config/` — Deployment orchestration framework (handlers, builders, validation)
+- `test/` — Snapshot tests via Jest
+
+### Conventions
+
+- **Declarative config** — Define resources in config objects, not imperative CDK code
+- **Environment-aware**: Use `AppEnvironment` enum (Development, LocalDevelopment, Test, Production)
+- Import from local `config/` directory — no external shared-iac dependency
+
+### Config Rules
+
+- One config file per layer (`frontend`, `shared`)
+- All timeouts and limits must have explicit values (no CDK defaults)
+
+### Testing
+
+- Snapshot tests in `test/` — update snapshots when stack changes are intentional
+- Run `pnpm test` from iac directory after any config or construct change
+
+### Formatting
+
+- Biome: 4 spaces, double quotes, semicolons, trailing commas, LF
+- `import type` for type-only imports
diff --git a/src/iac/.npmignore b/src/iac/.npmignore
new file mode 100644
index 00000000..c1d6d45d
--- /dev/null
+++ b/src/iac/.npmignore
@@ -0,0 +1,6 @@
+*.ts
+!*.d.ts
+
+# CDK asset staging directory
+.cdk.staging
+cdk.out
diff --git a/src/iac/README.md b/src/iac/README.md
new file mode 100644
index 00000000..ad707058
--- /dev/null
+++ b/src/iac/README.md
@@ -0,0 +1,173 @@
+# XXTemplateXX Infrastructure as Code (IaC)
+
+Infrastructure as Code project for XXTemplateXX-specific AWS resources using AWS CDK with TypeScript.
+
+## Overview
+
+This project manages the infrastructure resources specific to the XXTemplateXX application, including:
+
+- **Lambda Functions**: Serverless compute for APIs and background jobs
+- **API Gateway**: REST API endpoints and routing
+- **DynamoDB/RDS**: Application databases
+- **S3 Buckets**: Static assets and data storage
+- **CloudFront**: Content delivery network for frontend apps
+- **SQS Queues**: Message queuing for async processing
+- **CloudWatch**: Logging and monitoring
+- **Cognito**: OAuth2 authentication broker with Google and Microsoft IdP federation
+
+## Prerequisites
+
+- **Node.js**: 22+ (recommended)
+- **pnpm**: Latest version
+- **AWS CLI**: Latest version with configured credentials
+- **AWS CDK**: v2.x (installed via pnpm)
+
+## Getting Started
+
+### Installation
+
+Navigate to this directory and install dependencies:
+
+```bash
+cd xxtemplatexx/src/iac
+pnpm install
+```
+
+### Configuration
+
+The `cdk.json` file tells the CDK Toolkit how to execute your app and contains project-specific settings.
+
+## Available Commands
+
+| Command | Description |
+| ------- | ----------- |
+| `pnpm build` | Compile TypeScript to JavaScript |
+| `pnpm watch` | Watch for changes and compile automatically |
+| `pnpm test` | Run Jest unit tests |
+| `cdk deploy` | Deploy this stack to your AWS account/region |
+| `cdk diff` | Compare deployed stack with current state |
+| `cdk synth` | Generate CloudFormation template |
+| `cdk destroy` | Remove deployed stack from AWS |
+
+## Deployment
+
+### Deploy to AWS
+
+```bash
+# Synthesize CloudFormation template
+pnpm build && cdk synth
+
+# Preview changes
+cdk diff
+
+# Deploy to AWS
+cdk deploy
+```
+
+## Project Structure
+
+```text
+xxtemplatexx/src/iac/
+├── bin/ # CDK app entry point (reads config and builds stacks)
+├── buildspecs/ # CI buildspec definitions
+├── test/ # Jest tests (incl. template snapshots)
+├── cdk.json # CDK configuration
+├── package.json # Dependencies and scripts
+└── tsconfig.json # TypeScript configuration
+```
+
+## Key Infrastructure Components
+
+### Lambda Functions
+
+- **API Lambdas**: HTTP-facing lambdas (via API Gateway) and/or direct Function URL (optional)
+- **Background Lambdas**: Asynchronous/background jobs
+
+### Lambda Function URL (optional)
+
+Some Lambdas can optionally be exposed via an AWS Lambda Function URL.
+
+- Configuration lives in [xxtemplatexx/src/iac/bin/config/backendConfig.ts](xxtemplatexx/src/iac/bin/config/backendConfig.ts)
+- Enable by setting `enableFunctionUrl: true` on a Lambda config entry
+- When enabled, the stack creates a Function URL and outputs it as a CloudFormation output
+
+### Frontend Deployment
+
+- **XXTemplateXX Frontend**: Static assets on S3 + CloudFront
+
+### Messaging
+
+- **SQS Queues**:
+ - `processes`: Background jobs
+
+## Environment Variables
+
+Infrastructure configuration is managed through:
+
+- **AWS Systems Manager Parameter Store**: Secure parameter storage
+- **Environment-specific values**: Development, Staging, Production
+- **Secrets Manager**: Sensitive credentials (API keys, database passwords)
+
+## Additional Documentation
+
+- [CDK Setup Guide](../../../docs/iac/CdkSetup.md) - Complete setup instructions
+- [Create New CDK Project](../../../docs/iac/CreateCdkProject.md) - How to create new IaC projects
+- [AWS CDK Documentation](https://docs.aws.amazon.com/cdk/) - Official AWS CDK docs
+- [Architecture Overview](../../../README.md#️-architecture-overview) - System architecture
+
+## Best Practices
+
+- Always run `cdk diff` before deploying to preview changes
+- Use separate AWS accounts/regions for development, staging, and production
+- Tag all resources appropriately for cost tracking
+- Follow the principle of least privilege for IAM roles
+- Use CDK constructs for reusable infrastructure patterns
+
+## CI/CD Integration
+
+This infrastructure is deployed through AWS CodePipeline. See the
+[CI/CD Pipeline documentation](../../../README.md#-aws-resources--management) for more details.
+
+## Troubleshooting
+
+### Common Issues
+
+#### Issue: CDK version mismatch
+
+```bash
+# Update CDK to latest version
+pnpm update aws-cdk
+```
+
+#### Issue: AWS credentials not found
+
+```bash
+# Configure AWS CLI
+aws configure
+```
+
+#### Issue: Stack deployment fails
+
+```bash
+# Check CloudFormation events in AWS Console
+# Or use: cdk deploy --verbose
+```
+
+#### Issue: Resource limit exceeded
+
+- Check AWS service quotas in the AWS Console
+- Request limit increases if needed
+
+## Support
+
+For questions or issues:
+
+1. Check the [CDK Setup Guide](../../../docs/iac/CdkSetup.md)
+2. Review AWS CDK documentation
+3. Contact the DevOps team
+4. Open an issue in the repository
+
+---
+
+**Last Updated**: January 2025
+**Maintained by**: DevOps Team
diff --git a/src/iac/biome.jsonc b/src/iac/biome.jsonc
new file mode 100644
index 00000000..76273582
--- /dev/null
+++ b/src/iac/biome.jsonc
@@ -0,0 +1,9 @@
+{
+ "extends": "//",
+ // CDK projects use bin/ for source code, so we need to re-include it
+ "files": {
+ "includes": [
+ "**"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/iac/cdk.json b/src/iac/cdk.json
new file mode 100644
index 00000000..e7a1fb08
--- /dev/null
+++ b/src/iac/cdk.json
@@ -0,0 +1,56 @@
+{
+ "app": "npx ts-node --prefer-ts-exts src/infra/iac.ts",
+ "profile": "mac",
+ "watch": {
+ "include": [
+ "**"
+ ],
+ "exclude": [
+ "README.md",
+ "cdk*.json",
+ "**/*.d.ts",
+ "**/*.js",
+ "tsconfig.json",
+ "package*.json",
+ "yarn.lock",
+ "node_modules",
+ "test"
+ ]
+ },
+ "context": {
+ "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
+ "@aws-cdk/core:checkSecretUsage": true,
+ "@aws-cdk/core:target-partitions": [
+ "aws",
+ "aws-cn"
+ ],
+ "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
+ "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
+ "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
+ "@aws-cdk/aws-iam:minimizePolicies": true,
+ "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
+ "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
+ "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
+ "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
+ "@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
+ "@aws-cdk/core:enablePartitionLiterals": true,
+ "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
+ "@aws-cdk/aws-iam:standardizedServicePrincipals": true,
+ "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
+ "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
+ "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
+ "@aws-cdk/aws-route53-patters:useCertificate": true,
+ "@aws-cdk/customresources:installLatestAwsSdkDefault": false,
+ "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
+ "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
+ "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
+ "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
+ "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
+ "@aws-cdk/aws-redshift:columnId": true,
+ "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
+ "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
+ "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
+ "@aws-cdk/aws-kms:aliasNameRef": true,
+ "@aws-cdk/core:includePrefixInUniqueNameGeneration": true
+ }
+}
\ No newline at end of file
diff --git a/src/iac/jest.config.js b/src/iac/jest.config.js
new file mode 100644
index 00000000..b91139a2
--- /dev/null
+++ b/src/iac/jest.config.js
@@ -0,0 +1,18 @@
+/** @type {import('jest').Config} */
+const config = {
+ testEnvironment: "node",
+ roots: ["/test"],
+ testMatch: ["**/*.test.ts"],
+ transform: {
+ "^.+\\.ts?$": ["ts-jest"],
+ },
+ collectCoverage: true,
+ coverageDirectory: "coverage",
+ verbose: false,
+ reporters: [
+ "default",
+ ],
+};
+
+// eslint-disable-next-line no-undef
+module.exports = config;
diff --git a/src/iac/package.json b/src/iac/package.json
new file mode 100644
index 00000000..b1369b94
--- /dev/null
+++ b/src/iac/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "@envilder/iac",
+ "version": "0.1.0",
+ "license": "UNLICENSED",
+ "scripts": {
+ "build": "tsc --build",
+ "watch": "tsc -w",
+ "test": "jest --colors --seed=1",
+ "test:update": "jest --colors --seed=1 --updateSnapshot --verbose",
+ "test:ci": "jest --colors --seed=1 --ci --verbose",
+ "test:ci:update": "jest --colors --seed=1 --ci --updateSnapshot --verbose",
+ "cdk": "cdk",
+ "lint": "biome lint ./src ./test",
+ "lint:fix": "biome lint --fix ./src ./test",
+ "format": "biome format ./src ./test",
+ "format:write": "biome format --write ./src ./test"
+ },
+ "dependencies": {
+ "aws-cdk-lib": "^2.200.0",
+ "constructs": "^10.4.2"
+ },
+ "devDependencies": {
+ "@types/jest": "^29.5.14",
+ "aws-cdk": "^2.200.0",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.3.4",
+ "ts-node": "^10.9.2",
+ "typescript": "^5.9.3"
+ }
+}
\ No newline at end of file
diff --git a/src/iac/pnpm-lock.yaml b/src/iac/pnpm-lock.yaml
new file mode 100644
index 00000000..a6cfacd6
--- /dev/null
+++ b/src/iac/pnpm-lock.yaml
@@ -0,0 +1,2759 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ aws-cdk-lib:
+ specifier: ^2.200.0
+ version: 2.244.0(constructs@10.6.0)
+ constructs:
+ specifier: ^10.4.2
+ version: 10.6.0
+ devDependencies:
+ '@types/jest':
+ specifier: ^29.5.14
+ version: 29.5.14
+ aws-cdk:
+ specifier: ^2.200.0
+ version: 2.1114.1
+ jest:
+ specifier: ^29.7.0
+ version: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ ts-jest:
+ specifier: ^29.3.4
+ version: 29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3)
+ ts-node:
+ specifier: ^10.9.2
+ version: 10.9.2(@types/node@25.5.0)(typescript@5.9.3)
+ typescript:
+ specifier: ^5.9.3
+ version: 5.9.3
+
+packages:
+
+ '@aws-cdk/asset-awscli-v1@2.2.263':
+ resolution: {integrity: sha512-X9JvcJhYcb7PHs8R7m4zMablO5C9PGb/hYfLnxds9h/rKJu6l7MiXE/SabCibuehxPnuO/vk+sVVJiUWrccarQ==}
+
+ '@aws-cdk/asset-node-proxy-agent-v6@2.1.1':
+ resolution: {integrity: sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==}
+
+ '@aws-cdk/cloud-assembly-schema@52.2.0':
+ resolution: {integrity: sha512-ourZjixQ/UfsZc7gdk3vt1eHBODMUjQTYYYCY3ZX8fiXyHtWNDAYZPrXUK96jpCC2fLP+tfHTJrBjZ563pmcEw==}
+ engines: {node: '>= 18.0.0'}
+ bundledDependencies:
+ - jsonschema
+ - semver
+
+ '@babel/code-frame@7.29.0':
+ resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.29.0':
+ resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.0':
+ resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.1':
+ resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.28.6':
+ resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.28.6':
+ resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.6':
+ resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.28.6':
+ resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.29.2':
+ resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.2':
+ resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-syntax-async-generators@7.8.4':
+ resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-bigint@7.8.3':
+ resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-class-properties@7.12.13':
+ resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-class-static-block@7.14.5':
+ resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-import-attributes@7.28.6':
+ resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-import-meta@7.10.4':
+ resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-json-strings@7.8.3':
+ resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-jsx@7.28.6':
+ resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
+ resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
+ resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-numeric-separator@7.10.4':
+ resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-object-rest-spread@7.8.3':
+ resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3':
+ resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-optional-chaining@7.8.3':
+ resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-private-property-in-object@7.14.5':
+ resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-top-level-await@7.14.5':
+ resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-typescript@7.28.6':
+ resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.28.6':
+ resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.0':
+ resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
+ '@bcoe/v8-coverage@0.2.3':
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+
+ '@cspotcode/source-map-support@0.8.1':
+ resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
+ engines: {node: '>=12'}
+
+ '@istanbuljs/load-nyc-config@1.1.0':
+ resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
+ engines: {node: '>=8'}
+
+ '@istanbuljs/schema@0.1.3':
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+
+ '@jest/console@29.7.0':
+ resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/core@29.7.0':
+ resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ '@jest/environment@29.7.0':
+ resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/expect-utils@29.7.0':
+ resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/expect@29.7.0':
+ resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/fake-timers@29.7.0':
+ resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/globals@29.7.0':
+ resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/reporters@29.7.0':
+ resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ '@jest/schemas@29.6.3':
+ resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/source-map@29.6.3':
+ resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/test-result@29.7.0':
+ resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/test-sequencer@29.7.0':
+ resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/transform@29.7.0':
+ resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/types@29.6.3':
+ resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@jridgewell/trace-mapping@0.3.9':
+ resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+
+ '@sinclair/typebox@0.27.10':
+ resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==}
+
+ '@sinonjs/commons@3.0.1':
+ resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
+
+ '@sinonjs/fake-timers@10.3.0':
+ resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+
+ '@tsconfig/node10@1.0.12':
+ resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==}
+
+ '@tsconfig/node12@1.0.11':
+ resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
+
+ '@tsconfig/node14@1.0.3':
+ resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
+
+ '@tsconfig/node16@1.0.4':
+ resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
+ '@types/graceful-fs@4.1.9':
+ resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
+
+ '@types/istanbul-lib-coverage@2.0.6':
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+
+ '@types/istanbul-lib-report@3.0.3':
+ resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
+
+ '@types/istanbul-reports@3.0.4':
+ resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+
+ '@types/jest@29.5.14':
+ resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
+
+ '@types/node@25.5.0':
+ resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==}
+
+ '@types/stack-utils@2.0.3':
+ resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+
+ '@types/yargs-parser@21.0.3':
+ resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+
+ '@types/yargs@17.0.35':
+ resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==}
+
+ acorn-walk@8.3.5:
+ resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==}
+ engines: {node: '>=0.4.0'}
+
+ acorn@8.16.0:
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ansi-escapes@4.3.2:
+ resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+ engines: {node: '>=8'}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
+ arg@4.1.3:
+ resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+
+ argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+
+ aws-cdk-lib@2.244.0:
+ resolution: {integrity: sha512-j5FVeZv5W+v6j6OnW8RjoN04T+8pYvDJJV7yXhhj4IiGDKPgMH3fflQLQXJousd2QQk+nSAjghDVJcrZ4GFyGA==}
+ engines: {node: '>= 20.0.0'}
+ peerDependencies:
+ constructs: ^10.5.0
+ bundledDependencies:
+ - '@balena/dockerignore'
+ - '@aws-cdk/cloud-assembly-api'
+ - case
+ - fs-extra
+ - ignore
+ - jsonschema
+ - minimatch
+ - punycode
+ - semver
+ - table
+ - yaml
+ - mime-types
+
+ aws-cdk@2.1114.1:
+ resolution: {integrity: sha512-jMaKPWQQs1G6AbhfCQG2zGrgAhTxzP0jn4T2CuwONuvcV374dMPhfC/LBAv48ruSOgpCK9x6V1xeO/aH3EchAA==}
+ engines: {node: '>= 18.0.0'}
+ hasBin: true
+
+ babel-jest@29.7.0:
+ resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@babel/core': ^7.8.0
+
+ babel-plugin-istanbul@6.1.1:
+ resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
+ engines: {node: '>=8'}
+
+ babel-plugin-jest-hoist@29.6.3:
+ resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ babel-preset-current-node-syntax@1.2.0:
+ resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0 || ^8.0.0-0
+
+ babel-preset-jest@29.6.3:
+ resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ baseline-browser-mapping@2.10.11:
+ resolution: {integrity: sha512-DAKrHphkJyiGuau/cFieRYhcTFeK/lBuD++C7cZ6KZHbMhBrisoi+EvhQ5RZrIfV5qwsW8kgQ07JIC+MDJRAhg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ brace-expansion@1.1.13:
+ resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browserslist@4.28.1:
+ resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ bs-logger@0.2.6:
+ resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
+ engines: {node: '>= 6'}
+
+ bser@2.1.1:
+ resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
+
+ buffer-from@1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ camelcase@5.3.1:
+ resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+ engines: {node: '>=6'}
+
+ camelcase@6.3.0:
+ resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+ engines: {node: '>=10'}
+
+ caniuse-lite@1.0.30001781:
+ resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ char-regex@1.0.2:
+ resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
+ engines: {node: '>=10'}
+
+ ci-info@3.9.0:
+ resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
+ engines: {node: '>=8'}
+
+ cjs-module-lexer@1.4.3:
+ resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
+
+ cliui@8.0.1:
+ resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+ engines: {node: '>=12'}
+
+ co@4.6.0:
+ resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
+ engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
+
+ collect-v8-coverage@1.0.3:
+ resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ constructs@10.6.0:
+ resolution: {integrity: sha512-TxHOnBO5zMo/G76ykzGF/wMpEHu257TbWiIxP9K0Yv/+t70UzgBQiTqjkAsWOPC6jW91DzJI0+ehQV6xDRNBuQ==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ create-jest@29.7.0:
+ resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
+
+ create-require@1.1.1:
+ resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ dedent@1.7.2:
+ resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==}
+ peerDependencies:
+ babel-plugin-macros: ^3.1.0
+ peerDependenciesMeta:
+ babel-plugin-macros:
+ optional: true
+
+ deepmerge@4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+
+ detect-newline@3.1.0:
+ resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
+ engines: {node: '>=8'}
+
+ diff-sequences@29.6.3:
+ resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ diff@4.0.4:
+ resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
+ engines: {node: '>=0.3.1'}
+
+ electron-to-chromium@1.5.328:
+ resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==}
+
+ emittery@0.13.1:
+ resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
+ engines: {node: '>=12'}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ error-ex@1.3.4:
+ resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@2.0.0:
+ resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+ engines: {node: '>=8'}
+
+ esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ execa@5.1.1:
+ resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+ engines: {node: '>=10'}
+
+ exit@0.1.2:
+ resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
+ engines: {node: '>= 0.8.0'}
+
+ expect@29.7.0:
+ resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fb-watchman@2.0.2:
+ resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-up@4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+
+ fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ get-caller-file@2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+
+ get-package-type@0.1.0:
+ resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
+ engines: {node: '>=8.0.0'}
+
+ get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+
+ glob@7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ handlebars@4.7.9:
+ resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==}
+ engines: {node: '>=0.4.7'}
+ hasBin: true
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
+ human-signals@2.1.0:
+ resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+ engines: {node: '>=10.17.0'}
+
+ import-local@3.2.0:
+ resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
+ engines: {node: '>=8'}
+ hasBin: true
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-generator-fn@2.1.0:
+ resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
+ engines: {node: '>=6'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-stream@2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-instrument@5.2.1:
+ resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-instrument@6.0.3:
+ resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-source-maps@4.0.1:
+ resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
+ engines: {node: '>=10'}
+
+ istanbul-reports@3.2.0:
+ resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
+ engines: {node: '>=8'}
+
+ jest-changed-files@29.7.0:
+ resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-circus@29.7.0:
+ resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-cli@29.7.0:
+ resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ jest-config@29.7.0:
+ resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@types/node': '*'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ ts-node:
+ optional: true
+
+ jest-diff@29.7.0:
+ resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-docblock@29.7.0:
+ resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-each@29.7.0:
+ resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-environment-node@29.7.0:
+ resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-get-type@29.6.3:
+ resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-haste-map@29.7.0:
+ resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-leak-detector@29.7.0:
+ resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-matcher-utils@29.7.0:
+ resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-message-util@29.7.0:
+ resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-mock@29.7.0:
+ resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-pnp-resolver@1.2.3:
+ resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
+ engines: {node: '>=6'}
+ peerDependencies:
+ jest-resolve: '*'
+ peerDependenciesMeta:
+ jest-resolve:
+ optional: true
+
+ jest-regex-util@29.6.3:
+ resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-resolve-dependencies@29.7.0:
+ resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-resolve@29.7.0:
+ resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-runner@29.7.0:
+ resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-runtime@29.7.0:
+ resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-snapshot@29.7.0:
+ resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-util@29.7.0:
+ resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-validate@29.7.0:
+ resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-watcher@29.7.0:
+ resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-worker@29.7.0:
+ resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest@29.7.0:
+ resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@3.14.2:
+ resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ kleur@3.0.3:
+ resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+ engines: {node: '>=6'}
+
+ leven@3.1.0:
+ resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
+ engines: {node: '>=6'}
+
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ locate-path@5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+
+ lodash.memoize@4.1.2:
+ resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+
+ make-error@1.3.6:
+ resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+
+ makeerror@1.0.12:
+ resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+
+ merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mimic-fn@2.1.0:
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+ engines: {node: '>=6'}
+
+ minimatch@3.1.5:
+ resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
+
+ minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ neo-async@2.6.2:
+ resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+
+ node-int64@0.4.0:
+ resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
+
+ node-releases@2.0.36:
+ resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==}
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ npm-run-path@4.0.1:
+ resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+ engines: {node: '>=8'}
+
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+ onetime@5.1.2:
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+ engines: {node: '>=6'}
+
+ p-limit@2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+
+ p-try@2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.2:
+ resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
+ engines: {node: '>=8.6'}
+
+ pirates@4.0.7:
+ resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
+ engines: {node: '>= 6'}
+
+ pkg-dir@4.2.0:
+ resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
+ engines: {node: '>=8'}
+
+ pretty-format@29.7.0:
+ resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ prompts@2.4.2:
+ resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
+ engines: {node: '>= 6'}
+
+ pure-rand@6.1.0:
+ resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
+
+ react-is@18.3.1:
+ resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+
+ require-directory@2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+
+ resolve-cwd@3.0.0:
+ resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
+ engines: {node: '>=8'}
+
+ resolve-from@5.0.0:
+ resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+ engines: {node: '>=8'}
+
+ resolve.exports@2.0.3:
+ resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
+ engines: {node: '>=10'}
+
+ resolve@1.22.11:
+ resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.4:
+ resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ signal-exit@3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+
+ sisteransi@1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
+ source-map-support@0.5.13:
+ resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
+
+ source-map@0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+
+ sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+
+ stack-utils@2.0.6:
+ resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+ engines: {node: '>=10'}
+
+ string-length@4.0.2:
+ resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
+ engines: {node: '>=10'}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-bom@4.0.0:
+ resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
+ engines: {node: '>=8'}
+
+ strip-final-newline@2.0.0:
+ resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+ engines: {node: '>=6'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ supports-color@8.1.1:
+ resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+ engines: {node: '>=10'}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ test-exclude@6.0.0:
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+ engines: {node: '>=8'}
+
+ tmpl@1.0.5:
+ resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ ts-jest@29.4.6:
+ resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@babel/core': '>=7.0.0-beta.0 <8'
+ '@jest/transform': ^29.0.0 || ^30.0.0
+ '@jest/types': ^29.0.0 || ^30.0.0
+ babel-jest: ^29.0.0 || ^30.0.0
+ esbuild: '*'
+ jest: ^29.0.0 || ^30.0.0
+ jest-util: ^29.0.0 || ^30.0.0
+ typescript: '>=4.3 <6'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ '@jest/transform':
+ optional: true
+ '@jest/types':
+ optional: true
+ babel-jest:
+ optional: true
+ esbuild:
+ optional: true
+ jest-util:
+ optional: true
+
+ ts-node@10.9.2:
+ resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
+ hasBin: true
+ peerDependencies:
+ '@swc/core': '>=1.2.50'
+ '@swc/wasm': '>=1.2.50'
+ '@types/node': '*'
+ typescript: '>=2.7'
+ peerDependenciesMeta:
+ '@swc/core':
+ optional: true
+ '@swc/wasm':
+ optional: true
+
+ type-detect@4.0.8:
+ resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ engines: {node: '>=4'}
+
+ type-fest@0.21.3:
+ resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+ engines: {node: '>=10'}
+
+ type-fest@4.41.0:
+ resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
+ engines: {node: '>=16'}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ uglify-js@3.19.3:
+ resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
+ engines: {node: '>=0.8.0'}
+ hasBin: true
+
+ undici-types@7.18.2:
+ resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
+
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ v8-compile-cache-lib@3.0.1:
+ resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+
+ v8-to-istanbul@9.3.0:
+ resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
+ engines: {node: '>=10.12.0'}
+
+ walker@1.0.8:
+ resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ wordwrap@1.0.0:
+ resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ write-file-atomic@4.0.2:
+ resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
+ engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+
+ y18n@5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yargs-parser@21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+
+ yargs@17.7.2:
+ resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
+ engines: {node: '>=12'}
+
+ yn@3.1.1:
+ resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
+ engines: {node: '>=6'}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+snapshots:
+
+ '@aws-cdk/asset-awscli-v1@2.2.263': {}
+
+ '@aws-cdk/asset-node-proxy-agent-v6@2.1.1': {}
+
+ '@aws-cdk/cloud-assembly-schema@52.2.0': {}
+
+ '@babel/code-frame@7.29.0':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.28.5
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.29.0': {}
+
+ '@babel/core@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-compilation-targets': 7.28.6
+ '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
+ '@babel/helpers': 7.29.2
+ '@babel/parser': 7.29.2
+ '@babel/template': 7.28.6
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.1':
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.28.6':
+ dependencies:
+ '@babel/compat-data': 7.29.0
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.28.1
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.28.6':
+ dependencies:
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-module-imports': 7.28.6
+ '@babel/helper-validator-identifier': 7.28.5
+ '@babel/traverse': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.28.6': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.28.5': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.29.2':
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+
+ '@babel/parser@7.29.2':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-plugin-utils': 7.28.6
+
+ '@babel/template@7.28.6':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+
+ '@babel/traverse@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.29.2
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
+ '@bcoe/v8-coverage@0.2.3': {}
+
+ '@cspotcode/source-map-support@0.8.1':
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.9
+
+ '@istanbuljs/load-nyc-config@1.1.0':
+ dependencies:
+ camelcase: 5.3.1
+ find-up: 4.1.0
+ get-package-type: 0.1.0
+ js-yaml: 3.14.2
+ resolve-from: 5.0.0
+
+ '@istanbuljs/schema@0.1.3': {}
+
+ '@jest/console@29.7.0':
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ chalk: 4.1.2
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ slash: 3.0.0
+
+ '@jest/core@29.7.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))':
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/reporters': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-changed-files: 29.7.0
+ jest-config: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ jest-haste-map: 29.7.0
+ jest-message-util: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-resolve-dependencies: 29.7.0
+ jest-runner: 29.7.0
+ jest-runtime: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ jest-watcher: 29.7.0
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-ansi: 6.0.1
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ '@jest/environment@29.7.0':
+ dependencies:
+ '@jest/fake-timers': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ jest-mock: 29.7.0
+
+ '@jest/expect-utils@29.7.0':
+ dependencies:
+ jest-get-type: 29.6.3
+
+ '@jest/expect@29.7.0':
+ dependencies:
+ expect: 29.7.0
+ jest-snapshot: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/fake-timers@29.7.0':
+ dependencies:
+ '@jest/types': 29.6.3
+ '@sinonjs/fake-timers': 10.3.0
+ '@types/node': 25.5.0
+ jest-message-util: 29.7.0
+ jest-mock: 29.7.0
+ jest-util: 29.7.0
+
+ '@jest/globals@29.7.0':
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/expect': 29.7.0
+ '@jest/types': 29.6.3
+ jest-mock: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/reporters@29.7.0':
+ dependencies:
+ '@bcoe/v8-coverage': 0.2.3
+ '@jest/console': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@jridgewell/trace-mapping': 0.3.31
+ '@types/node': 25.5.0
+ chalk: 4.1.2
+ collect-v8-coverage: 1.0.3
+ exit: 0.1.2
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-instrument: 6.0.3
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 4.0.1
+ istanbul-reports: 3.2.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ jest-worker: 29.7.0
+ slash: 3.0.0
+ string-length: 4.0.2
+ strip-ansi: 6.0.1
+ v8-to-istanbul: 9.3.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/schemas@29.6.3':
+ dependencies:
+ '@sinclair/typebox': 0.27.10
+
+ '@jest/source-map@29.6.3':
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ callsites: 3.1.0
+ graceful-fs: 4.2.11
+
+ '@jest/test-result@29.7.0':
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ collect-v8-coverage: 1.0.3
+
+ '@jest/test-sequencer@29.7.0':
+ dependencies:
+ '@jest/test-result': 29.7.0
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ slash: 3.0.0
+
+ '@jest/transform@29.7.0':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@jest/types': 29.6.3
+ '@jridgewell/trace-mapping': 0.3.31
+ babel-plugin-istanbul: 6.1.1
+ chalk: 4.1.2
+ convert-source-map: 2.0.0
+ fast-json-stable-stringify: 2.1.0
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-util: 29.7.0
+ micromatch: 4.0.8
+ pirates: 4.0.7
+ slash: 3.0.0
+ write-file-atomic: 4.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/types@29.6.3':
+ dependencies:
+ '@jest/schemas': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ '@types/istanbul-reports': 3.0.4
+ '@types/node': 25.5.0
+ '@types/yargs': 17.0.35
+ chalk: 4.1.2
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@jridgewell/trace-mapping@0.3.9':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@sinclair/typebox@0.27.10': {}
+
+ '@sinonjs/commons@3.0.1':
+ dependencies:
+ type-detect: 4.0.8
+
+ '@sinonjs/fake-timers@10.3.0':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+
+ '@tsconfig/node10@1.0.12': {}
+
+ '@tsconfig/node12@1.0.11': {}
+
+ '@tsconfig/node14@1.0.3': {}
+
+ '@tsconfig/node16@1.0.4': {}
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@types/graceful-fs@4.1.9':
+ dependencies:
+ '@types/node': 25.5.0
+
+ '@types/istanbul-lib-coverage@2.0.6': {}
+
+ '@types/istanbul-lib-report@3.0.3':
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.6
+
+ '@types/istanbul-reports@3.0.4':
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.3
+
+ '@types/jest@29.5.14':
+ dependencies:
+ expect: 29.7.0
+ pretty-format: 29.7.0
+
+ '@types/node@25.5.0':
+ dependencies:
+ undici-types: 7.18.2
+
+ '@types/stack-utils@2.0.3': {}
+
+ '@types/yargs-parser@21.0.3': {}
+
+ '@types/yargs@17.0.35':
+ dependencies:
+ '@types/yargs-parser': 21.0.3
+
+ acorn-walk@8.3.5:
+ dependencies:
+ acorn: 8.16.0
+
+ acorn@8.16.0: {}
+
+ ansi-escapes@4.3.2:
+ dependencies:
+ type-fest: 0.21.3
+
+ ansi-regex@5.0.1: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ ansi-styles@5.2.0: {}
+
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.2
+
+ arg@4.1.3: {}
+
+ argparse@1.0.10:
+ dependencies:
+ sprintf-js: 1.0.3
+
+ aws-cdk-lib@2.244.0(constructs@10.6.0):
+ dependencies:
+ '@aws-cdk/asset-awscli-v1': 2.2.263
+ '@aws-cdk/asset-node-proxy-agent-v6': 2.1.1
+ '@aws-cdk/cloud-assembly-schema': 52.2.0
+ constructs: 10.6.0
+
+ aws-cdk@2.1114.1: {}
+
+ babel-jest@29.7.0(@babel/core@7.29.0):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@jest/transform': 29.7.0
+ '@types/babel__core': 7.20.5
+ babel-plugin-istanbul: 6.1.1
+ babel-preset-jest: 29.6.3(@babel/core@7.29.0)
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ slash: 3.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-istanbul@6.1.1:
+ dependencies:
+ '@babel/helper-plugin-utils': 7.28.6
+ '@istanbuljs/load-nyc-config': 1.1.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-instrument: 5.2.1
+ test-exclude: 6.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-jest-hoist@29.6.3:
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ '@types/babel__core': 7.20.5
+ '@types/babel__traverse': 7.28.0
+
+ babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0)
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0)
+ '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0)
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0)
+
+ babel-preset-jest@29.6.3(@babel/core@7.29.0):
+ dependencies:
+ '@babel/core': 7.29.0
+ babel-plugin-jest-hoist: 29.6.3
+ babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
+
+ balanced-match@1.0.2: {}
+
+ baseline-browser-mapping@2.10.11: {}
+
+ brace-expansion@1.1.13:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browserslist@4.28.1:
+ dependencies:
+ baseline-browser-mapping: 2.10.11
+ caniuse-lite: 1.0.30001781
+ electron-to-chromium: 1.5.328
+ node-releases: 2.0.36
+ update-browserslist-db: 1.2.3(browserslist@4.28.1)
+
+ bs-logger@0.2.6:
+ dependencies:
+ fast-json-stable-stringify: 2.1.0
+
+ bser@2.1.1:
+ dependencies:
+ node-int64: 0.4.0
+
+ buffer-from@1.1.2: {}
+
+ callsites@3.1.0: {}
+
+ camelcase@5.3.1: {}
+
+ camelcase@6.3.0: {}
+
+ caniuse-lite@1.0.30001781: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ char-regex@1.0.2: {}
+
+ ci-info@3.9.0: {}
+
+ cjs-module-lexer@1.4.3: {}
+
+ cliui@8.0.1:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
+ co@4.6.0: {}
+
+ collect-v8-coverage@1.0.3: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ concat-map@0.0.1: {}
+
+ constructs@10.6.0: {}
+
+ convert-source-map@2.0.0: {}
+
+ create-jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
+ dependencies:
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-config: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ jest-util: 29.7.0
+ prompts: 2.4.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ create-require@1.1.1: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ dedent@1.7.2: {}
+
+ deepmerge@4.3.1: {}
+
+ detect-newline@3.1.0: {}
+
+ diff-sequences@29.6.3: {}
+
+ diff@4.0.4: {}
+
+ electron-to-chromium@1.5.328: {}
+
+ emittery@0.13.1: {}
+
+ emoji-regex@8.0.0: {}
+
+ error-ex@1.3.4:
+ dependencies:
+ is-arrayish: 0.2.1
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@2.0.0: {}
+
+ esprima@4.0.1: {}
+
+ execa@5.1.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ get-stream: 6.0.1
+ human-signals: 2.1.0
+ is-stream: 2.0.1
+ merge-stream: 2.0.0
+ npm-run-path: 4.0.1
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ strip-final-newline: 2.0.0
+
+ exit@0.1.2: {}
+
+ expect@29.7.0:
+ dependencies:
+ '@jest/expect-utils': 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fb-watchman@2.0.2:
+ dependencies:
+ bser: 2.1.1
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ find-up@4.1.0:
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+
+ fs.realpath@1.0.0: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2: {}
+
+ gensync@1.0.0-beta.2: {}
+
+ get-caller-file@2.0.5: {}
+
+ get-package-type@0.1.0: {}
+
+ get-stream@6.0.1: {}
+
+ glob@7.2.3:
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.5
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+
+ graceful-fs@4.2.11: {}
+
+ handlebars@4.7.9:
+ dependencies:
+ minimist: 1.2.8
+ neo-async: 2.6.2
+ source-map: 0.6.1
+ wordwrap: 1.0.0
+ optionalDependencies:
+ uglify-js: 3.19.3
+
+ has-flag@4.0.0: {}
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ html-escaper@2.0.2: {}
+
+ human-signals@2.1.0: {}
+
+ import-local@3.2.0:
+ dependencies:
+ pkg-dir: 4.2.0
+ resolve-cwd: 3.0.0
+
+ imurmurhash@0.1.4: {}
+
+ inflight@1.0.6:
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+
+ inherits@2.0.4: {}
+
+ is-arrayish@0.2.1: {}
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-generator-fn@2.1.0: {}
+
+ is-number@7.0.0: {}
+
+ is-stream@2.0.1: {}
+
+ isexe@2.0.0: {}
+
+ istanbul-lib-coverage@3.2.2: {}
+
+ istanbul-lib-instrument@5.2.1:
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/parser': 7.29.2
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.2
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-lib-instrument@6.0.3:
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/parser': 7.29.2
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.2
+ semver: 7.7.4
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-lib-report@3.0.1:
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+
+ istanbul-lib-source-maps@4.0.1:
+ dependencies:
+ debug: 4.4.3
+ istanbul-lib-coverage: 3.2.2
+ source-map: 0.6.1
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-reports@3.2.0:
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+
+ jest-changed-files@29.7.0:
+ dependencies:
+ execa: 5.1.1
+ jest-util: 29.7.0
+ p-limit: 3.1.0
+
+ jest-circus@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/expect': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ chalk: 4.1.2
+ co: 4.6.0
+ dedent: 1.7.2
+ is-generator-fn: 2.1.0
+ jest-each: 29.7.0
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-runtime: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ p-limit: 3.1.0
+ pretty-format: 29.7.0
+ pure-rand: 6.1.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-cli@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ create-jest: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ exit: 0.1.2
+ import-local: 3.2.0
+ jest-config: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ jest-config@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@jest/test-sequencer': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.29.0)
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ deepmerge: 4.3.1
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-circus: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-get-type: 29.6.3
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-runner: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ micromatch: 4.0.8
+ parse-json: 5.2.0
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-json-comments: 3.1.1
+ optionalDependencies:
+ '@types/node': 25.5.0
+ ts-node: 10.9.2(@types/node@25.5.0)(typescript@5.9.3)
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-diff@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ diff-sequences: 29.6.3
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-docblock@29.7.0:
+ dependencies:
+ detect-newline: 3.1.0
+
+ jest-each@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ jest-get-type: 29.6.3
+ jest-util: 29.7.0
+ pretty-format: 29.7.0
+
+ jest-environment-node@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/fake-timers': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ jest-mock: 29.7.0
+ jest-util: 29.7.0
+
+ jest-get-type@29.6.3: {}
+
+ jest-haste-map@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/graceful-fs': 4.1.9
+ '@types/node': 25.5.0
+ anymatch: 3.1.3
+ fb-watchman: 2.0.2
+ graceful-fs: 4.2.11
+ jest-regex-util: 29.6.3
+ jest-util: 29.7.0
+ jest-worker: 29.7.0
+ micromatch: 4.0.8
+ walker: 1.0.8
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ jest-leak-detector@29.7.0:
+ dependencies:
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-matcher-utils@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-message-util@29.7.0:
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@jest/types': 29.6.3
+ '@types/stack-utils': 2.0.3
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+
+ jest-mock@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ jest-util: 29.7.0
+
+ jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
+ optionalDependencies:
+ jest-resolve: 29.7.0
+
+ jest-regex-util@29.6.3: {}
+
+ jest-resolve-dependencies@29.7.0:
+ dependencies:
+ jest-regex-util: 29.6.3
+ jest-snapshot: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-resolve@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ resolve: 1.22.11
+ resolve.exports: 2.0.3
+ slash: 3.0.0
+
+ jest-runner@29.7.0:
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/environment': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ chalk: 4.1.2
+ emittery: 0.13.1
+ graceful-fs: 4.2.11
+ jest-docblock: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-haste-map: 29.7.0
+ jest-leak-detector: 29.7.0
+ jest-message-util: 29.7.0
+ jest-resolve: 29.7.0
+ jest-runtime: 29.7.0
+ jest-util: 29.7.0
+ jest-watcher: 29.7.0
+ jest-worker: 29.7.0
+ p-limit: 3.1.0
+ source-map-support: 0.5.13
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-runtime@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/fake-timers': 29.7.0
+ '@jest/globals': 29.7.0
+ '@jest/source-map': 29.6.3
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ chalk: 4.1.2
+ cjs-module-lexer: 1.4.3
+ collect-v8-coverage: 1.0.3
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-message-util: 29.7.0
+ jest-mock: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ slash: 3.0.0
+ strip-bom: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-snapshot@29.7.0:
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
+ '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0)
+ '@babel/types': 7.29.0
+ '@jest/expect-utils': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
+ chalk: 4.1.2
+ expect: 29.7.0
+ graceful-fs: 4.2.11
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ natural-compare: 1.4.0
+ pretty-format: 29.7.0
+ semver: 7.7.4
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-util@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ graceful-fs: 4.2.11
+ picomatch: 2.3.2
+
+ jest-validate@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ camelcase: 6.3.0
+ chalk: 4.1.2
+ jest-get-type: 29.6.3
+ leven: 3.1.0
+ pretty-format: 29.7.0
+
+ jest-watcher@29.7.0:
+ dependencies:
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 25.5.0
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ emittery: 0.13.1
+ jest-util: 29.7.0
+ string-length: 4.0.2
+
+ jest-worker@29.7.0:
+ dependencies:
+ '@types/node': 25.5.0
+ jest-util: 29.7.0
+ merge-stream: 2.0.0
+ supports-color: 8.1.1
+
+ jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ '@jest/types': 29.6.3
+ import-local: 3.2.0
+ jest-cli: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@3.14.2:
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+
+ jsesc@3.1.0: {}
+
+ json-parse-even-better-errors@2.3.1: {}
+
+ json5@2.2.3: {}
+
+ kleur@3.0.3: {}
+
+ leven@3.1.0: {}
+
+ lines-and-columns@1.2.4: {}
+
+ locate-path@5.0.0:
+ dependencies:
+ p-locate: 4.1.0
+
+ lodash.memoize@4.1.2: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ make-dir@4.0.0:
+ dependencies:
+ semver: 7.7.4
+
+ make-error@1.3.6: {}
+
+ makeerror@1.0.12:
+ dependencies:
+ tmpl: 1.0.5
+
+ merge-stream@2.0.0: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.2
+
+ mimic-fn@2.1.0: {}
+
+ minimatch@3.1.5:
+ dependencies:
+ brace-expansion: 1.1.13
+
+ minimist@1.2.8: {}
+
+ ms@2.1.3: {}
+
+ natural-compare@1.4.0: {}
+
+ neo-async@2.6.2: {}
+
+ node-int64@0.4.0: {}
+
+ node-releases@2.0.36: {}
+
+ normalize-path@3.0.0: {}
+
+ npm-run-path@4.0.1:
+ dependencies:
+ path-key: 3.1.1
+
+ once@1.4.0:
+ dependencies:
+ wrappy: 1.0.2
+
+ onetime@5.1.2:
+ dependencies:
+ mimic-fn: 2.1.0
+
+ p-limit@2.3.0:
+ dependencies:
+ p-try: 2.2.0
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@4.1.0:
+ dependencies:
+ p-limit: 2.3.0
+
+ p-try@2.2.0: {}
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ error-ex: 1.3.4
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
+ path-exists@4.0.0: {}
+
+ path-is-absolute@1.0.1: {}
+
+ path-key@3.1.1: {}
+
+ path-parse@1.0.7: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.2: {}
+
+ pirates@4.0.7: {}
+
+ pkg-dir@4.2.0:
+ dependencies:
+ find-up: 4.1.0
+
+ pretty-format@29.7.0:
+ dependencies:
+ '@jest/schemas': 29.6.3
+ ansi-styles: 5.2.0
+ react-is: 18.3.1
+
+ prompts@2.4.2:
+ dependencies:
+ kleur: 3.0.3
+ sisteransi: 1.0.5
+
+ pure-rand@6.1.0: {}
+
+ react-is@18.3.1: {}
+
+ require-directory@2.1.1: {}
+
+ resolve-cwd@3.0.0:
+ dependencies:
+ resolve-from: 5.0.0
+
+ resolve-from@5.0.0: {}
+
+ resolve.exports@2.0.3: {}
+
+ resolve@1.22.11:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ semver@6.3.1: {}
+
+ semver@7.7.4: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ signal-exit@3.0.7: {}
+
+ sisteransi@1.0.5: {}
+
+ slash@3.0.0: {}
+
+ source-map-support@0.5.13:
+ dependencies:
+ buffer-from: 1.1.2
+ source-map: 0.6.1
+
+ source-map@0.6.1: {}
+
+ sprintf-js@1.0.3: {}
+
+ stack-utils@2.0.6:
+ dependencies:
+ escape-string-regexp: 2.0.0
+
+ string-length@4.0.2:
+ dependencies:
+ char-regex: 1.0.2
+ strip-ansi: 6.0.1
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-bom@4.0.0: {}
+
+ strip-final-newline@2.0.0: {}
+
+ strip-json-comments@3.1.1: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-color@8.1.1:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ test-exclude@6.0.0:
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 7.2.3
+ minimatch: 3.1.5
+
+ tmpl@1.0.5: {}
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3):
+ dependencies:
+ bs-logger: 0.2.6
+ fast-json-stable-stringify: 2.1.0
+ handlebars: 4.7.9
+ jest: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
+ json5: 2.2.3
+ lodash.memoize: 4.1.2
+ make-error: 1.3.6
+ semver: 7.7.4
+ type-fest: 4.41.0
+ typescript: 5.9.3
+ yargs-parser: 21.1.1
+ optionalDependencies:
+ '@babel/core': 7.29.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.29.0)
+ jest-util: 29.7.0
+
+ ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3):
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ '@tsconfig/node10': 1.0.12
+ '@tsconfig/node12': 1.0.11
+ '@tsconfig/node14': 1.0.3
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 25.5.0
+ acorn: 8.16.0
+ acorn-walk: 8.3.5
+ arg: 4.1.3
+ create-require: 1.1.1
+ diff: 4.0.4
+ make-error: 1.3.6
+ typescript: 5.9.3
+ v8-compile-cache-lib: 3.0.1
+ yn: 3.1.1
+
+ type-detect@4.0.8: {}
+
+ type-fest@0.21.3: {}
+
+ type-fest@4.41.0: {}
+
+ typescript@5.9.3: {}
+
+ uglify-js@3.19.3:
+ optional: true
+
+ undici-types@7.18.2: {}
+
+ update-browserslist-db@1.2.3(browserslist@4.28.1):
+ dependencies:
+ browserslist: 4.28.1
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ v8-compile-cache-lib@3.0.1: {}
+
+ v8-to-istanbul@9.3.0:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ '@types/istanbul-lib-coverage': 2.0.6
+ convert-source-map: 2.0.0
+
+ walker@1.0.8:
+ dependencies:
+ makeerror: 1.0.12
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ wordwrap@1.0.0: {}
+
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrappy@1.0.2: {}
+
+ write-file-atomic@4.0.2:
+ dependencies:
+ imurmurhash: 0.1.4
+ signal-exit: 3.0.7
+
+ y18n@5.0.8: {}
+
+ yallist@3.1.1: {}
+
+ yargs-parser@21.1.1: {}
+
+ yargs@17.7.2:
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+
+ yn@3.1.1: {}
+
+ yocto-queue@0.1.0: {}
diff --git a/src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts b/src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts
new file mode 100644
index 00000000..d66d0d24
--- /dev/null
+++ b/src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts
@@ -0,0 +1,579 @@
+import * as path from 'node:path';
+import {
+ Duration,
+ type Environment,
+ type RemovalPolicy,
+ SecretValue,
+ aws_codebuild,
+} from 'aws-cdk-lib';
+import {
+ BuildSpec,
+ LinuxBuildImage,
+ PipelineProject,
+} from 'aws-cdk-lib/aws-codebuild';
+import {
+ Artifact,
+ Pipeline,
+ PipelineType,
+ type StageProps,
+} from 'aws-cdk-lib/aws-codepipeline';
+import {
+ CodeBuildAction,
+ GitHubSourceAction,
+ GitHubTrigger,
+ ManualApprovalAction,
+} from 'aws-cdk-lib/aws-codepipeline-actions';
+import { DetailType } from 'aws-cdk-lib/aws-codestarnotifications';
+import type { IVpc } from 'aws-cdk-lib/aws-ec2';
+import {
+ ArnPrincipal,
+ PolicyDocument,
+ PolicyStatement,
+ Role,
+ ServicePrincipal,
+} from 'aws-cdk-lib/aws-iam';
+import { SlackChannelConfiguration } from 'aws-cdk-lib/aws-chatbot';
+import { Key } from 'aws-cdk-lib/aws-kms';
+import { Bucket } from 'aws-cdk-lib/aws-s3';
+import { Topic } from 'aws-cdk-lib/aws-sns';
+import { EmailSubscription } from 'aws-cdk-lib/aws-sns-subscriptions';
+import type { Construct } from 'constructs';
+import type { AppEnvironment } from '../../../config/domain/model/appEnvironment';
+import { formatRepoNameForCloudFormation } from '../../../config/infrastructure/utilities/cloudFormationUtils';
+import {
+ type CustomStackProps,
+ CustomStack,
+} from '../../../config/domain/customStack';
+
+/**
+ * Cache configuration types for CodeBuild projects
+ */
+export type CacheConfig =
+ | { type: 'none' }
+ | { type: 'local' }
+ | { type: 's3'; bucketName?: string };
+
+export interface PipelineStackProps extends CustomStackProps {
+ branch: string;
+ githubRepo: string;
+ envName: AppEnvironment;
+ domain: string;
+ secretTokenArn: string;
+ deployBuildSpec: string[];
+ testBuildSpec: string[];
+ vpc: IVpc;
+ testProjectName: string;
+ bucketRemovalPolicy: RemovalPolicy;
+ environment?: object;
+ filterPaths?: string[];
+ manualApproval?: boolean;
+ emailNotification?: string;
+ slackChannelConfigurationName?: string;
+ cacheConfig?: CacheConfig;
+}
+
+/**
+ * PipelineStack defines a complete CI/CD pipeline using AWS CodePipeline, CodeBuild, and CodeDeploy.
+ *
+ * The stack creates source actions from GitHub, test and deploy actions based on provided buildspec files,
+ * and configures notifications for pipeline state changes. It also creates the necessary IAM roles for pipeline,
+ * test, and deploy stages, and sets up Slack and email notifications based on manual approval settings.
+ *
+ * @example
+ * const pipelineStack = new PipelineStack(app, {
+ * branch: "main",
+ * githubRepo: "my-repo",
+ * envName: AppEnvironment.PROD,
+ * domain: "example.com",
+ * secretTokenArn: "arn:aws:secretsmanager:...",
+ * deployBuildSpec: ["deploy/buildspec.yml"],
+ * testBuildSpec: ["test/buildspec.yml"],
+ * vpc: myVpc,
+ * testProjectName: "MyTestProject",
+ * bucketRemovalPolicy: RemovalPolicy.DESTROY,
+ * environment: { CUSTOM_VAR: { value: "value" } },
+ * filterPaths: ["src/**"],
+ * manualApproval: true,
+ * // plus additional CustomStackProps...
+ * });
+ */
+export class PipelineStack extends CustomStack {
+ readonly githubOwner: string = 'macalbert';
+
+ /**
+ * Constructs a new instance of PipelineStack.
+ *
+ * The constructor sets up the pipeline by creating the source, test, deploy stages, and notifications.
+ * It creates separate IAM roles for the pipeline, test, and deploy actions, and uses a pre-existing artifact bucket.
+ *
+ * @param scope - The scope in which this stack is defined.
+ * @param props - The properties for configuring the pipeline.
+ */
+ constructor(scope: Construct, props: PipelineStackProps) {
+ super(scope, props);
+
+ const pipelineRole = this.createPipelineRole(props, 'pipeline');
+
+ const pipelineRoleTest = this.createPipelineRole(
+ props,
+ 'test',
+ new ArnPrincipal(pipelineRole.roleArn),
+ );
+ const pipelineRoleDeploy = this.createPipelineRole(
+ props,
+ 'deploy',
+ new ArnPrincipal(pipelineRole.roleArn),
+ );
+
+ const sourceOutput = new Artifact();
+
+ const sourceAction = new GitHubSourceAction({
+ actionName: `checkout-${props.envName}-${props.githubRepo}`.toLowerCase(),
+ owner: this.githubOwner,
+ repo: props.githubRepo,
+ branch: props.branch,
+ output: sourceOutput,
+ oauthToken: SecretValue.secretsManager(props.secretTokenArn),
+ trigger: GitHubTrigger.WEBHOOK,
+ });
+
+ const testActions = props.testBuildSpec.map((buildspec) =>
+ this.createTestAction(sourceOutput, props, buildspec, pipelineRoleTest),
+ );
+
+ const deployActions = props.deployBuildSpec.map((buildspec) =>
+ this.createDeployAction(
+ sourceOutput,
+ props,
+ buildspec,
+ pipelineRoleDeploy,
+ ),
+ );
+
+ const stages: StageProps[] = this.createStages(
+ sourceAction,
+ testActions,
+ props,
+ pipelineRole,
+ deployActions,
+ );
+
+ const artifactBucket = Bucket.fromBucketName(
+ this,
+ 'envilder-codepipeline-artifact',
+ 'envilder-codepipeline-artifact',
+ );
+
+ const pipeline = new Pipeline(this, 'Pipeline', {
+ pipelineType: PipelineType.V2,
+ role: pipelineRole,
+ pipelineName: `${props.githubRepo}-${props.envName}`.toLowerCase(),
+ stages: stages,
+ artifactBucket: artifactBucket,
+ });
+
+ this.createNotifications(props, pipeline);
+ }
+
+ /**
+ * Configures notifications for pipeline state changes and manual approvals.
+ *
+ * Uses an existing AWS Chatbot Slack configuration as the notification target.
+ *
+ * @param props - The pipeline properties.
+ * @param pipeline - The CodePipeline instance.
+ */
+ private createNotifications(props: PipelineStackProps, pipeline: Pipeline) {
+ if (props.slackChannelConfigurationName) {
+ // Import the existing Slack channel configuration
+ const slackChannelConfigurationArn = `arn:aws:chatbot::${this.props.env?.account}:chat-configuration/slack-channel/${props.slackChannelConfigurationName}`;
+ const slackTarget =
+ SlackChannelConfiguration.fromSlackChannelConfigurationArn(
+ this,
+ 'SlackChannelConfig',
+ slackChannelConfigurationArn,
+ );
+
+ // Create notification rule for pipeline state changes
+ pipeline.notifyOnExecutionStateChange(
+ `${formatRepoNameForCloudFormation(props.githubRepo)}-PipelineNotifications-${props.envName}`,
+ slackTarget,
+ {
+ detailType: DetailType.BASIC,
+ notificationRuleName: `${props.githubRepo}-${props.envName}-pipeline-updates`,
+ },
+ );
+
+ if (props.manualApproval === true) {
+ // Create notification rule for manual approval state changes
+ pipeline.notifyOnAnyManualApprovalStateChange(
+ `${formatRepoNameForCloudFormation(props.githubRepo)}-ManualApproval-${props.envName}`,
+ slackTarget,
+ {
+ detailType: DetailType.FULL,
+ notificationRuleName: `${props.githubRepo}-${props.envName}-manual-approval`,
+ },
+ );
+ }
+ }
+
+ if (props.manualApproval === true) {
+ const emailTopic = new Topic(
+ this,
+ `${formatRepoNameForCloudFormation(props.githubRepo)}_ManualApprovealEmail_${props.envName}`,
+ {
+ displayName: `⚠️ ${props.githubRepo} [${props.envName.toUpperCase()}] - Manual Approval Required`,
+ masterKey: new Key(
+ this,
+ `Key-${formatRepoNameForCloudFormation(props.githubRepo)}-ManualApprovealEmail-${props.envName}`.toLowerCase(),
+ ),
+ },
+ );
+ emailTopic.addSubscription(new EmailSubscription('mac.albert@gmail.com'));
+
+ pipeline.notifyOnAnyManualApprovalStateChange(
+ `${formatRepoNameForCloudFormation(props.githubRepo)}-NotifyManualApproval-${props.envName}`,
+ emailTopic,
+ {
+ detailType: DetailType.BASIC,
+ notificationRuleName:
+ `${props.githubRepo} (${props.envName}) - Approval Required (Email)`.toLowerCase(),
+ },
+ );
+ }
+ }
+
+ /**
+ * Creates an IAM role for a specific pipeline component.
+ *
+ * The role is created with an inline policy document based on the provided domain and environment,
+ * and additional assume role permissions for Lambda, CodePipeline, and CodeBuild.
+ *
+ * @param props - The pipeline properties.
+ * @param roleType - A string representing the type of role (e.g., "pipeline", "deploy", or "test").
+ * @returns The created IAM role.
+ */
+ private createPipelineRole(
+ props: PipelineStackProps,
+ roleType: string,
+ additionalPrincipal?: ArnPrincipal,
+ ): Role {
+ const policyDocument = this.getPolicyDocument(props.domain, props.env);
+
+ const pipelineRole = new Role(this, `Role-${roleType}`, {
+ assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
+ description: `Role for CD pipeline in repo ${props.githubRepo} (${props.envName})`,
+ inlinePolicies: { customApiPolicyDocument: policyDocument },
+ });
+
+ pipelineRole.assumeRolePolicy?.addStatements(
+ new PolicyStatement({
+ principals: [
+ new ServicePrincipal('lambda.amazonaws.com'),
+ new ServicePrincipal('codepipeline.amazonaws.com'),
+ new ServicePrincipal('codebuild.amazonaws.com'),
+ ],
+ actions: ['sts:AssumeRole'],
+ }),
+ );
+
+ if (additionalPrincipal) {
+ pipelineRole.assumeRolePolicy?.addStatements(
+ new PolicyStatement({
+ principals: [additionalPrincipal],
+ actions: ['sts:AssumeRole'],
+ }),
+ );
+ }
+
+ return pipelineRole;
+ }
+
+ /**
+ * Creates the stages for the CodePipeline.
+ *
+ * This method defines the stages for source, manual approval (if enabled), test, and deploy actions.
+ *
+ * @param sourceAction - The GitHub source action.
+ * @param testAction - An array of CodeBuild actions for testing.
+ * @param props - The pipeline properties.
+ * @param pipelineRole - The IAM role for the pipeline.
+ * @param deployAction - An array of CodeBuild actions for deployment.
+ * @returns An array of StageProps defining the pipeline stages.
+ */
+ private createStages(
+ sourceAction: GitHubSourceAction,
+ testAction: CodeBuildAction[],
+ props: PipelineStackProps,
+ pipelineRole: Role,
+ deployAction: CodeBuildAction[],
+ ): StageProps[] {
+ const stages: StageProps[] = [
+ { actions: [sourceAction], stageName: 'Source' },
+ ];
+
+ if (props.manualApproval) {
+ const manualApprovalAction = new ManualApprovalAction({
+ actionName:
+ `${props.githubRepo}-ManualApproval-${props.envName}`.toLowerCase(),
+ role: pipelineRole,
+ });
+
+ stages.push({
+ actions: [manualApprovalAction],
+ stageName:
+ `${props.githubRepo}-ManualApproval-${props.envName}`.toLowerCase(),
+ });
+ }
+
+ stages.push({ actions: testAction, stageName: 'Test' });
+ stages.push({ actions: deployAction, stageName: 'Deploy' });
+
+ return stages;
+ }
+
+ /**
+ * Creates a CodeBuild action for testing.
+ *
+ * This method creates a PipelineProject for testing using the provided buildspec file.
+ * It configures the project environment with a Linux build image and returns a CodeBuildAction.
+ *
+ * @param sourceOutput - The source artifact from GitHub.
+ * @param props - The pipeline properties.
+ * @param buildspec - The filename of the test buildspec.
+ * @param pipelineRole - The IAM role to use for the test project.
+ * @returns The created CodeBuildAction for testing.
+ */
+ private createTestAction(
+ sourceOutput: Artifact,
+ props: PipelineStackProps,
+ buildspec: string,
+ pipelineRole: Role,
+ ): CodeBuildAction {
+ const fileName = path.parse(path.basename(buildspec)).name;
+ const projectName =
+ `${fileName}-test-${formatRepoNameForCloudFormation(props.githubRepo)}-${props.envName}`.toLowerCase();
+
+ const project = new PipelineProject(this, `Test-${fileName}`, {
+ environment: {
+ buildImage: LinuxBuildImage.STANDARD_7_0,
+ privileged: true,
+ computeType: aws_codebuild.ComputeType.SMALL,
+ },
+ timeout: Duration.minutes(15),
+ environmentVariables: {},
+ buildSpec: BuildSpec.fromSourceFilename(buildspec),
+ role: pipelineRole,
+ vpc: props.vpc,
+ projectName: projectName,
+ cache: this.resolveCache(props.cacheConfig, `test-${fileName}`, props),
+ });
+
+ return new CodeBuildAction({
+ input: sourceOutput,
+ actionName: projectName,
+ project: project,
+ role: pipelineRole,
+ });
+ }
+
+ /**
+ * Creates a CodeBuild action for deployment.
+ *
+ * This method creates a PipelineProject for deployment using the provided buildspec file.
+ * It configures the environment variables and returns a CodeBuildAction for the deployment stage.
+ *
+ * @param sourceOutput - The source artifact from GitHub.
+ * @param props - The pipeline properties.
+ * @param buildspec - The filename of the deploy buildspec.
+ * @param pipelineRole - The IAM role to use for the deploy project.
+ * @returns The created CodeBuildAction for deployment.
+ */
+ private createDeployAction(
+ sourceOutput: Artifact,
+ props: PipelineStackProps,
+ buildspec: string,
+ pipelineRole: Role,
+ ): CodeBuildAction {
+ const fileName = path.parse(path.basename(buildspec)).name;
+ const projectName =
+ `${fileName}-deploy-${formatRepoNameForCloudFormation(props.githubRepo)}-${props.envName}`.toLowerCase();
+
+ const project = new PipelineProject(this, fileName, {
+ environment: {
+ buildImage: LinuxBuildImage.STANDARD_7_0,
+ privileged: true,
+ computeType: aws_codebuild.ComputeType.SMALL,
+ },
+ timeout: Duration.minutes(30),
+ environmentVariables: this.getEnvironmentVariables(props),
+ buildSpec: BuildSpec.fromSourceFilename(buildspec),
+ role: pipelineRole,
+ projectName: projectName,
+ cache: this.resolveCache(props.cacheConfig, `deploy-${fileName}`, props),
+ });
+
+ return new CodeBuildAction({
+ input: sourceOutput,
+ actionName: projectName,
+ project: project,
+ role: pipelineRole,
+ });
+ }
+
+ /**
+ * Resolves the cache configuration for CodeBuild projects.
+ *
+ * @param cacheConfig - The cache configuration (none, local, or S3).
+ * @param cacheBucketSuffix - Suffix for the cache bucket identifier (e.g., "test-filename" or "deploy-filename").
+ * @param props - The pipeline properties for generating cache prefixes.
+ * @returns The resolved CodeBuild cache configuration or undefined if disabled.
+ */
+ private resolveCache(
+ cacheConfig: CacheConfig | undefined,
+ cacheBucketSuffix: string,
+ props: PipelineStackProps,
+ ): aws_codebuild.Cache | undefined {
+ if (!cacheConfig) {
+ return undefined;
+ }
+
+ switch (cacheConfig.type) {
+ case 'local':
+ return aws_codebuild.Cache.local(
+ aws_codebuild.LocalCacheMode.DOCKER_LAYER,
+ aws_codebuild.LocalCacheMode.CUSTOM,
+ );
+
+ case 's3': {
+ const bucketName =
+ cacheConfig.bucketName ||
+ `codebuild-${this.props.env?.region}-${this.props.env?.account}`;
+ const cacheBucket = Bucket.fromBucketName(
+ this,
+ `CodeBuildCacheBucket-${cacheBucketSuffix}`,
+ bucketName,
+ );
+ const prefix = `${props.githubRepo}`;
+ return aws_codebuild.Cache.bucket(cacheBucket, { prefix });
+ }
+ default:
+ return undefined;
+ }
+ }
+
+ /**
+ * Retrieves and merges environment variables for the deploy project.
+ *
+ * By default, it includes ASPNETCORE_ENVIRONMENT set to the environment name.
+ * If additional environment variables are provided, they are merged.
+ *
+ * @param props - The pipeline properties.
+ * @returns An object containing the environment variables.
+ */
+ private getEnvironmentVariables(props: PipelineStackProps) {
+ let environmentVariables = {
+ ASPNETCORE_ENVIRONMENT: { value: props.envName },
+ };
+
+ if (props.environment !== null) {
+ environmentVariables = {
+ ...props.environment,
+ ...{ ASPNETCORE_ENVIRONMENT: { value: props.envName } },
+ };
+ }
+
+ return environmentVariables;
+ }
+
+ /**
+ * Constructs a policy document for the pipeline role.
+ *
+ * The policy document includes permissions for assuming roles, CloudWatch logging,
+ * CodeBuild reporting, S3 access, Secrets Manager, SES, KMS, SQS, and SSM.
+ *
+ * @param domain - The domain for SES email sending.
+ * @param env - The AWS environment information.
+ * @returns A PolicyDocument object in JSON format.
+ */
+ private getPolicyDocument(domain: string, env?: Environment) {
+ return PolicyDocument.fromJson({
+ Version: '2012-10-17',
+ Statement: [
+ {
+ Action: ['sts:AssumeRole'],
+ Resource: [`arn:aws:iam::${env?.account}:role/*`],
+ Effect: 'Allow',
+ },
+ {
+ Action: [
+ 'logs:CreateLogGroup',
+ 'logs:CreateLogStream',
+ 'logs:PutLogEvents',
+ ],
+ Resource: [`arn:aws:logs:${env?.region}:${env?.account}:log-group:*`],
+ Effect: 'Allow',
+ },
+ {
+ Action: [
+ 'codebuild:BatchPutCodeCoverages',
+ 'codebuild:BatchPutTestCases',
+ 'codebuild:CreateReport',
+ 'codebuild:CreateReportGroup',
+ 'codebuild:UpdateReport',
+ 'codebuild:StartBuild',
+ ],
+ Resource: `arn:aws:codebuild:${env?.region}:${env?.account}:project/*`,
+ Effect: 'Allow',
+ },
+ {
+ Action: ['s3:GetBucket*', 's3:GetObject*', 's3:List*'],
+ Resource: ['arn:aws:s3:::*'],
+ Effect: 'Allow',
+ },
+ {
+ Action: [
+ 'secretsmanager:GetResourcePolicy',
+ 'secretsmanager:GetSecretValue',
+ 'secretsmanager:DescribeSecret',
+ 'secretsmanager:ListSecretVersionIds',
+ ],
+ Resource: ['*'],
+ Effect: 'Allow',
+ },
+ {
+ Action: ['ses:SendEmail'],
+ Resource: [
+ `arn:aws:ses:${env?.region}:${env?.account}:identity/${domain}`,
+ ],
+ Effect: 'Allow',
+ },
+ {
+ Action: [
+ 'kms:Decrypt',
+ 'kms:DescribeKey',
+ 'kms:Encrypt',
+ 'kms:GenerateDataKey*',
+ 'kms:ReEncrypt*',
+ ],
+ Resource: `arn:aws:kms:${env?.region}:${env?.account}:*`,
+ Effect: 'Allow',
+ },
+ {
+ Action: ['sqs:*'],
+ Resource: `arn:aws:sqs:${env?.region}:${env?.account}:*`,
+ Effect: 'Allow',
+ },
+ {
+ Action: [
+ 'ssm:GetParameter',
+ 'ssm:GetParameters',
+ 'ssm:GetParametersByPath',
+ ],
+ Resource: [`arn:aws:ssm:${env?.region}:${env?.account}:parameter/*`],
+ Effect: 'Allow',
+ },
+ ],
+ });
+ }
+}
diff --git a/src/iac/src/aws/network/vpcLookupStack.ts b/src/iac/src/aws/network/vpcLookupStack.ts
new file mode 100644
index 00000000..4a2360c1
--- /dev/null
+++ b/src/iac/src/aws/network/vpcLookupStack.ts
@@ -0,0 +1,24 @@
+import { type Environment, Stack, type StackProps } from 'aws-cdk-lib';
+import { type IVpc, Vpc } from 'aws-cdk-lib/aws-ec2';
+import type { Construct } from 'constructs';
+
+export interface VpcLookupStackProps extends StackProps {
+ vpcId: string;
+ env?: Environment;
+}
+
+/**
+ * Stack for looking up an existing VPC by ID
+ * This is used to retrieve VPC information for stack deployments
+ */
+export class VpcLookupStack extends Stack {
+ public readonly vpc: IVpc;
+
+ constructor(scope: Construct, props: VpcLookupStackProps) {
+ super(scope, props.vpcId, props);
+
+ this.vpc = Vpc.fromLookup(this, 'VpcNetwork', {
+ vpcId: props.vpcId,
+ });
+ }
+}
diff --git a/src/iac/src/aws/network/vpcStack.ts b/src/iac/src/aws/network/vpcStack.ts
new file mode 100644
index 00000000..26ad9fcb
--- /dev/null
+++ b/src/iac/src/aws/network/vpcStack.ts
@@ -0,0 +1,112 @@
+import { CfnOutput } from 'aws-cdk-lib';
+import {
+ type IVpc,
+ IpAddresses,
+ type SubnetConfiguration,
+ Vpc,
+} from 'aws-cdk-lib/aws-ec2';
+import type { Construct } from 'constructs';
+import {
+ CustomStack,
+ type CustomStackProps,
+} from '../../config/domain/customStack';
+
+/**
+ * Properties for configuring the VPC stack.
+ *
+ * This interface extends CustomStackProps with additional properties required to create a VPC.
+ *
+ * Properties include:
+ * - vpcName: The base name for the VPC.
+ * - vpcCdir: The CIDR block for the VPC.
+ * - maxAzs: (Optional) The maximum number of availability zones to use.
+ * - natGateways: (Optional) The number of NAT gateways to create.
+ * - enableDnsHostnames: (Optional) Whether to enable DNS hostnames for instances.
+ * - enableDnsSupport: (Optional) Whether to enable DNS support.
+ * - subnetConfiguration: An array of subnet configurations for the VPC.
+ *
+ * @example
+ * const vpcStackProps: VPCStackProps = {
+ * vpcName: "my-vpc",
+ * vpcCdir: "10.0.0.0/16",
+ * maxAzs: 3,
+ * natGateways: 1,
+ * enableDnsHostnames: true,
+ * enableDnsSupport: true,
+ * subnetConfiguration: [
+ * {
+ * name: "Public",
+ * subnetType: SubnetType.PUBLIC,
+ * cidrMask: 24,
+ * },
+ * {
+ * name: "Private",
+ * subnetType: SubnetType.PRIVATE_WITH_NAT,
+ * cidrMask: 24,
+ * },
+ * ],
+ * // plus additional CustomStackProps properties...
+ * };
+ */
+export interface VPCStackProps extends CustomStackProps {
+ vpcName: string;
+ vpcCdir: string;
+ maxAzs?: number;
+ natGateways?: number;
+ enableDnsHostnames?: boolean;
+ enableDnsSupport?: boolean;
+ subnetConfiguration: SubnetConfiguration[];
+}
+
+/**
+ * VpcStack provisions an Amazon Virtual Private Cloud (VPC) with the specified configuration.
+ *
+ * This stack creates a VPC with the given name (appended with the environment name), CIDR block, and subnet
+ * configurations. It supports optional settings such as maximum availability zones, NAT gateways, and DNS settings.
+ * The VPC ID is output as a CloudFormation output for external reference.
+ *
+ * @example
+ * new VpcStack(app, {
+ * vpcName: "my-vpc",
+ * vpcCdir: "10.0.0.0/16",
+ * maxAzs: 3,
+ * natGateways: 1,
+ * enableDnsHostnames: true,
+ * enableDnsSupport: true,
+ * subnetConfiguration: [ ... ],
+ * // plus additional CustomStackProps properties...
+ * });
+ */
+export class VpcStack extends CustomStack {
+ public readonly vpc: IVpc;
+
+ /**
+ * Constructs a new instance of the VpcStack.
+ *
+ * This constructor creates a new VPC with the provided configuration. The VPC's name is built by appending the
+ * environment name to the provided base vpcName. The CIDR block, availability zones, NAT gateways, and DNS settings
+ * are configured based on the input properties. Finally, the VPC ID is output as a CloudFormation output.
+ *
+ * @param scope - The construct scope in which this stack is defined.
+ * @param props - The properties for configuring the VPC.
+ */
+ constructor(scope: Construct, props: VPCStackProps) {
+ super(scope, props);
+
+ this.vpc = new Vpc(this, 'vpcId', {
+ vpcName: `${props.vpcName}-${props.envName}`,
+ ipAddresses: IpAddresses.cidr(props.vpcCdir),
+ maxAzs: props.maxAzs,
+ natGateways: props.natGateways,
+ enableDnsHostnames: props.enableDnsHostnames,
+ enableDnsSupport: props.enableDnsSupport,
+ subnetConfiguration: props.subnetConfiguration,
+ });
+
+ new CfnOutput(this, 'cfnOutputVpcId', {
+ value: this.vpc.vpcId,
+ description: 'Created VPC ID',
+ exportName: 'VpcStack:vpcId',
+ });
+ }
+}
diff --git a/src/iac/src/aws/website/S3CloudfrontUrlParametersFix.md b/src/iac/src/aws/website/S3CloudfrontUrlParametersFix.md
new file mode 100644
index 00000000..68ab9608
--- /dev/null
+++ b/src/iac/src/aws/website/S3CloudfrontUrlParametersFix.md
@@ -0,0 +1,258 @@
+# CloudFront URL Rewrite Handler for Static Next.js
+
+## Overview
+
+This handler enables **clean URLs** for static Next.js sites deployed to **S3 + CloudFront** while
+preserving query parameters. It performs internal URL rewrites (not redirects) so browser URLs remain unchanged.
+
+## What It Does
+
+1. **Removes trailing slashes** from URIs (except homepage): `/foo/` → `/foo`
+2. **Appends `.html`** to paths without known extensions: `/dashboard` → `/dashboard.html`
+3. **Preserves query strings**: `?userId=xxx` stays intact
+4. **Case-insensitive extensions**: Handles `/Photo.JPG` correctly
+5. **Excludes API routes**: `/api/*` paths remain untouched
+
+This solves the problem where accessing `https://xxtemplatexx.envilder.io/dashboard?userId=xxx` would
+fail because CloudFront/S3 looks for a literal `/dashboard` file instead of `/dashboard.html`.
+
+## Handler Code
+
+### Location
+
+- **Handler file**: `shared/src/iac/src/aws/website/cloudfront-url-rewrite.js`
+- **Stack file**: `shared/src/iac/src/aws/website/staticWebsiteStack.ts`
+
+The CloudFront Function is stored in a separate JavaScript file and imported using `FunctionCode.fromFile()`.
+
+### Implementation
+
+```javascript
+function handler(event) {
+ var req = event.request;
+ var uri = req.uri;
+
+ // Helpers ES5.1 (compatible with CloudFront Functions)
+ function endsWith(str, suffix) {
+ if (str == null || suffix == null) return false;
+ var sl = str.length,
+ su = suffix.length;
+ return sl >= su && str.substring(sl - su) === suffix;
+ }
+ function hasPrefix(str, prefix) {
+ if (str == null || prefix == null) return false;
+ return str.indexOf(prefix) === 0;
+ }
+
+ var staticExt = [
+ ".html",
+ ".js",
+ ".css",
+ ".png",
+ ".jpg",
+ ".jpeg",
+ ".gif",
+ ".svg",
+ ".ico",
+ ".woff",
+ ".woff2",
+ ".ttf",
+ ".otf",
+ ".eot",
+ ".json",
+ ".xml",
+ ".txt",
+ ".map",
+ ];
+
+ function hasKnownExt(uLower) {
+ for (var i = 0; i < staticExt.length; i++) {
+ if (endsWith(uLower, staticExt[i])) return true;
+ }
+ return false;
+ }
+
+ // Exclude API routes
+ var lower = uri.toLowerCase();
+ if (hasPrefix(lower, "/api/")) {
+ return req; // no changes
+ }
+
+ // Remove trailing slash (except homepage)
+ if (uri !== "/" && endsWith(uri, "/")) {
+ uri = uri.substring(0, uri.length - 1);
+ lower = uri.toLowerCase(); // recompute after modifying uri
+ }
+
+ // Append .html if no known extension
+ if (uri !== "/" && !hasKnownExt(lower)) {
+ // For /folder/index.html instead of /folder.html, use: uri += '/index.html';
+ uri += ".html";
+ }
+
+ req.uri = uri;
+ return req; // Query string preserved automatically in req.querystring
+}
+```
+
+**Key improvements:**
+
+- **ES5.1 compatible** - no `.endsWith()`, `.startsWith()`, or arrow functions
+- **Null-safe helpers** for string operations
+- **Case-insensitive** extension detection
+- **API route exclusion** with `/api/*`
+- **Recomputes `lower`** after URI modifications for correctness
+
+## URL Rewrite Examples
+
+| Input URL | Rewritten URI | Query Preserved |
+| ---------------------- | ------------------ | --------------------- |
+| `/` | `/` | N/A |
+| `/dashboard` | `/dashboard.html` | ✅ |
+| `/dashboard/` | `/dashboard.html` | ✅ |
+| `/groups?userId=xxx` | `/groups.html` | ✅ `?userId=xxx` |
+| `/app.js` | `/app.js` | ✅ |
+| `/IMG/Photo.JPG` | `/IMG/Photo.JPG` | ✅ (case-insensitive) |
+| `/api/users` | `/api/users` | ✅ (excluded) |
+| `/styles/main.css?v=1` | `/styles/main.css` | ✅ `?v=1` |
+
+## Deployment
+
+### Update CDK Stack
+
+The handler is now in a separate file for better maintainability:
+
+1. **Handler**: `shared/src/iac/src/aws/website/cloudfront-url-rewrite.js`
+2. **Stack**: `shared/src/iac/src/aws/website/staticWebsiteStack.ts` (imports with `fromFile`)
+
+To deploy changes:
+
+```bash
+cd xxtemplatexx/src/iac
+pnpm install && pnpm build
+pnpm cdk deploy githubrepo-FrontendDashboard
+```
+
+### Propagation & Testing
+
+- **Wait**: 15-30 minutes for edge location propagation
+- **Invalidate**: Create CloudFront invalidation `/*` for immediate visibility
+- **Test**: Access URLs with query parameters
+
+```bash
+# Production
+curl -I "https://xxtemplatexx.envilder.io/dashboard?userId=xxx"
+
+# Local Docker (nginx)
+docker compose up -d dashboard-web
+curl -I "http://localhost:81/dashboard?userId=xxx"
+```
+
+### Local Testing (Node.js)
+
+Test the function locally before deploying to AWS:
+
+```bash
+# From project root
+node test-cloudfront-function.js
+```
+
+**Expected output:**
+
+```txt
+🧪 Testing CloudFront Function (ES5.1)
+══════════════════════════════════════════════════════════════════════
+✅ / → /
+✅ /dashboard → /dashboard.html
+✅ /dashboard/ → /dashboard.html
+✅ /groups → /groups.html
+✅ /app.js → /app.js
+✅ /IMG/Photo.JPG → /IMG/Photo.JPG
+✅ /api/users → /api/users
+══════════════════════════════════════════════════════════════════════
+📊 Results: 15/15 passed
+✅ All tests passed!
+```
+
+The test script (`test-cloudfront-function.js`) validates:
+
+- Homepage handling (`/` → `/`)
+- HTML rewriting (`/dashboard` → `/dashboard.html`)
+- Trailing slash removal (`/dashboard/` → `/dashboard.html`)
+- Case-insensitive extensions (`/Photo.JPG` → `/Photo.JPG`)
+- API route exclusion (`/api/users` → `/api/users`)
+- Known extensions preserved (`/app.js` → `/app.js`)
+
+## Architecture Flow
+
+```txt
+Browser: /dashboard?userId=xxx
+ ↓
+CloudFront Edge → CloudFront Function (viewer-request)
+ | Rewrites: /dashboard → /dashboard.html
+ | Preserves: ?userId=xxx automatically
+ ↓
+S3 Origin: dashboard.html
+ ↓
+React App: useSearchParams() reads userId
+```
+
+## Verification Checklist
+
+- [ ] Function deployed to CloudFront (15-30 min wait)
+- [ ] URLs with parameters return 200: `/dashboard?userId=xxx`
+- [ ] API routes excluded: `/api/*` not rewritten
+- [ ] Case-insensitive extensions work: `/Photo.JPG`
+- [ ] React app reads params: `useSearchParams()` works
+
+## Local vs Production
+
+| Aspect | Local (nginx) | Production (CloudFront) |
+| ----------- | -------------- | ------------------------------ |
+| **Handler** | `try_files` | CloudFront Function |
+| **URL** | `localhost:81` | `template.envilder.io` |
+| **Deploy** | Instant | 15-30 min propagation |
+| **Cache** | nginx | Global edge cache |
+
+## Troubleshooting
+
+| Issue | Cause | Solution |
+| ----------------- | ----------------- | --------------------------------- |
+| **403 Forbidden** | OAI permissions | Check S3 bucket policy and IAM |
+| **404 Not Found** | Wrong rewrite | Verify function code, check logs |
+| **Params lost** | Cache policy | Ensure query strings forwarded |
+| **No changes** | Propagation delay | Wait 15-30 min + invalidate cache |
+
+## Optional Variants
+
+### Use `index.html` for directories
+
+If you prefer `/blog/` → `/blog/index.html` instead of `/blog.html`:
+
+```javascript
+if (uri !== "/" && uri.endsWith("/")) {
+ uri += "index.html";
+}
+```
+
+### Additional cache policy (if needed)
+
+Explicit cache policy for query string forwarding:
+
+```typescript
+import {
+ CachePolicy,
+ CacheQueryStringBehavior,
+} from "aws-cdk-lib/aws-cloudfront";
+
+const cachePolicy = new CachePolicy(this, "cache-policy", {
+ queryStringBehavior: CacheQueryStringBehavior.all(),
+ // ... other settings
+});
+```
+
+## Resources
+
+- [CloudFront Functions](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html)
+- [Next.js Static Export](https://nextjs.org/docs/app/building-your-application/deploying/static-exports)
+- [AWS CDK CloudFront](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront-readme.html)
diff --git a/src/iac/src/aws/website/cloudfront-url-rewrite.js b/src/iac/src/aws/website/cloudfront-url-rewrite.js
new file mode 100644
index 00000000..bb600507
--- /dev/null
+++ b/src/iac/src/aws/website/cloudfront-url-rewrite.js
@@ -0,0 +1,54 @@
+// CloudFront Function for URL rewriting
+// Compatible with CloudFront Functions runtime (ES5.1)
+// Query strings are automatically preserved by CloudFront
+
+function handler(event) {
+ var req = event.request;
+ var uri = req.uri;
+
+ // ES5.1 Helpers (without startsWith/endsWith or arrow functions)
+ function endsWith(str, suffix) {
+ if (str == null || suffix == null) return false;
+ var sl = str.length, su = suffix.length;
+ return sl >= su && str.substring(sl - su) === suffix;
+ }
+ function hasPrefix(str, prefix) {
+ if (str == null || prefix == null) return false;
+ return str.indexOf(prefix) === 0;
+ }
+
+ var staticExt = [
+ '.html', '.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg',
+ '.ico', '.woff', '.woff2', '.ttf', '.otf', '.eot', '.json', '.xml',
+ '.txt', '.map'
+ ];
+
+ function hasKnownExt(uLower) {
+ for (var i = 0; i < staticExt.length; i++) {
+ if (endsWith(uLower, staticExt[i])) return true;
+ }
+ return false;
+ }
+
+ // Exclude API routes
+ var lower = uri.toLowerCase();
+ if (hasPrefix(lower, '/api/')) {
+ return req; // no changes
+ }
+
+ // Remove trailing slash (except homepage)
+ if (uri !== '/' && endsWith(uri, '/')) {
+ uri = uri.substring(0, uri.length - 1);
+ lower = uri.toLowerCase(); // recompute after modifying uri
+ }
+
+ // Append .html if not homepage and no known extension
+ if (uri !== '/' && !hasKnownExt(lower)) {
+ // For /folder/index.html instead of /folder.html, use:
+ // uri += '/index.html';
+ uri += '.html';
+ }
+
+ req.uri = uri;
+ return req;
+}
diff --git a/src/iac/src/aws/website/staticWebsiteStack.ts b/src/iac/src/aws/website/staticWebsiteStack.ts
new file mode 100644
index 00000000..18762a7d
--- /dev/null
+++ b/src/iac/src/aws/website/staticWebsiteStack.ts
@@ -0,0 +1,286 @@
+import { join } from 'node:path';
+import { CfnOutput, Duration, RemovalPolicy } from 'aws-cdk-lib';
+import {
+ Certificate,
+ type ICertificate,
+} from 'aws-cdk-lib/aws-certificatemanager';
+import {
+ Distribution,
+ type ErrorResponse,
+ FunctionCode,
+ FunctionEventType,
+ Function as LambdaFunction,
+ OriginAccessIdentity,
+ ViewerProtocolPolicy,
+} from 'aws-cdk-lib/aws-cloudfront';
+import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
+import { ARecord, HostedZone, RecordTarget } from 'aws-cdk-lib/aws-route53';
+import { CloudFrontTarget } from 'aws-cdk-lib/aws-route53-targets';
+import {
+ BlockPublicAccess,
+ Bucket,
+ BucketAccessControl,
+ BucketEncryption,
+ HttpMethods,
+} from 'aws-cdk-lib/aws-s3';
+import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
+import type { Construct } from 'constructs';
+import {
+ CustomStack,
+ type CustomStackProps,
+ type DomainConfig,
+} from '../../config/domain/customStack';
+
+/**
+ * Properties for configuring the StaticWebsiteStack.
+ *
+ * This interface extends the base CustomStackProps and adds properties required for deploying a static website.
+ *
+ * Properties:
+ * - domains: Array of domain configurations, each with subdomain, domainName, hostedZoneId, and certificateId.
+ * - distFolderPath: The local path to the website distribution folder.
+ *
+ * @example
+ * const props: StaticWebsiteStackProps = {
+ * domains: [
+ * {
+ * subdomain: "www",
+ * domainName: "example.com",
+ * hostedZoneId: "Z123456ABCDEFG",
+ * certificateId: "abc123",
+ * },
+ * ],
+ * distFolderPath: "./dist",
+ * // plus additional CustomStackProps properties...
+ * };
+ */
+export interface StaticWebsiteStackProps extends CustomStackProps {
+ domains: DomainConfig[];
+ distFolderPath: string;
+}
+
+/**
+ * StaticWebsiteStack provisions a static website using an S3 bucket and CloudFront distribution.
+ *
+ * This stack creates an S3 bucket configured for hosting a static website with strict security settings.
+ * It then creates an Origin Access Identity (OAI) to allow CloudFront to securely access the bucket.
+ * A CloudFront distribution is configured with custom error responses and a URL rewrite function to handle
+ * pretty URLs. Finally, a Route 53 A record is created to map a custom domain name to the distribution.
+ *
+ * Note: This stack uses stable logical IDs for Route53 records based on domain names
+ * to prevent "resource already exists" errors during stack updates.
+ *
+ * CloudFormation outputs provide the CloudFront distribution domain name and the DNS record name.
+ *
+ * @example
+ * new StaticWebsiteStack(app, {
+ * recordName: "www",
+ * domainName: "example.com",
+ * distFolderPath: "./dist",
+ * certificateArn: "arn:aws:acm:region:account:certificate/abc123",
+ * hostedZoneId: "Z123456ABCDEFG",
+ * // plus additional CustomStackProps properties...
+ * });
+ */
+export class StaticWebsiteStack extends CustomStack {
+ constructor(scope: Construct, props: StaticWebsiteStackProps) {
+ super(scope, props);
+
+ if (!props.domains || props.domains.length === 0) {
+ throw new Error('At least one domain configuration is required');
+ }
+
+ // Get primary domain for bucket naming
+ const primaryDomain = props.domains[0];
+ const primaryFullDomainName =
+ primaryDomain.subdomain && primaryDomain.subdomain.length > 0
+ ? [primaryDomain.subdomain, primaryDomain.domainName]
+ .join('.')
+ .toLowerCase()
+ : primaryDomain.domainName.toLowerCase();
+
+ // Build array of all full domain names for CloudFront
+ const allDomainNames = props.domains.map((domain) =>
+ domain.subdomain && domain.subdomain.length > 0
+ ? `${domain.subdomain}.${domain.domainName}`.toLowerCase()
+ : domain.domainName.toLowerCase(),
+ );
+
+ // Group domains by certificate to create one certificate per unique certificateId
+ const certificateMap = new Map();
+ for (const domain of props.domains) {
+ if (!certificateMap.has(domain.certificateId)) {
+ const certificateArn = `arn:aws:acm:us-east-1:${props.env?.account}:certificate/${domain.certificateId}`;
+ certificateMap.set(
+ domain.certificateId,
+ Certificate.fromCertificateArn(
+ this,
+ `certificate-${domain.certificateId}`,
+ certificateArn,
+ ),
+ );
+ }
+ }
+
+ // Use primary certificate for CloudFront (all domains should share the same cert for CloudFront)
+ const primaryCertificate = certificateMap.get(primaryDomain.certificateId);
+ if (!primaryCertificate) {
+ throw new Error(
+ `Certificate not found for ${primaryDomain.certificateId}`,
+ );
+ }
+
+ // Create logging bucket for S3 access logs and CloudFront logs
+ const loggingBucket = new Bucket(this, 'logging-bucket', {
+ accessControl: BucketAccessControl.LOG_DELIVERY_WRITE,
+ publicReadAccess: false,
+ versioned: false,
+ removalPolicy: RemovalPolicy.DESTROY,
+ bucketName: `${primaryFullDomainName}-logs`,
+ autoDeleteObjects: true,
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
+ encryption: BucketEncryption.S3_MANAGED,
+ enforceSSL: true,
+ lifecycleRules: [
+ {
+ id: 'DeleteOldLogs',
+ expiration: Duration.days(90),
+ enabled: true,
+ },
+ ],
+ });
+
+ const bucketWebsite = new Bucket(this, 'static-website-bucket', {
+ accessControl: BucketAccessControl.PRIVATE,
+ publicReadAccess: false,
+ versioned: false,
+ removalPolicy: RemovalPolicy.DESTROY,
+ bucketName: primaryFullDomainName,
+ autoDeleteObjects: true,
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
+ encryption: BucketEncryption.S3_MANAGED,
+ cors: [
+ {
+ allowedMethods: [HttpMethods.GET, HttpMethods.HEAD],
+ allowedOrigins: ['*'],
+ allowedHeaders: ['*'],
+ },
+ ],
+ enforceSSL: true,
+ serverAccessLogsBucket: loggingBucket,
+ serverAccessLogsPrefix: 's3-access-logs/',
+ });
+
+ const originAccessIdentity = new OriginAccessIdentity(
+ this,
+ 'originAccessIdentity',
+ {
+ comment: `Setup access from CloudFront to the bucket ${primaryFullDomainName} (read)`,
+ },
+ );
+
+ bucketWebsite.grantRead(originAccessIdentity);
+
+ const errorResponses: ErrorResponse[] = [];
+
+ const errorResponse403: ErrorResponse = {
+ httpStatus: 403,
+ responseHttpStatus: 200,
+ responsePagePath: '/index.html',
+ ttl: Duration.seconds(10),
+ };
+
+ const errorResponse404: ErrorResponse = {
+ httpStatus: 404,
+ responseHttpStatus: 200,
+ responsePagePath: '/index.html',
+ ttl: Duration.seconds(10),
+ };
+
+ errorResponses.push(errorResponse403, errorResponse404);
+
+ const distribution = new Distribution(this, 'distribution', {
+ domainNames: allDomainNames,
+ defaultBehavior: {
+ origin: S3BucketOrigin.withOriginAccessIdentity(bucketWebsite, {
+ originAccessIdentity: originAccessIdentity,
+ }),
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
+ functionAssociations: [
+ {
+ eventType: FunctionEventType.VIEWER_REQUEST,
+ function: new LambdaFunction(
+ this,
+ `${primaryFullDomainName}-url-rewrite`.toLowerCase(),
+ {
+ code: FunctionCode.fromFile({
+ filePath: join(__dirname, 'cloudfront-url-rewrite.js'),
+ }),
+ },
+ ),
+ },
+ ],
+ },
+ defaultRootObject: 'index.html',
+ certificate: primaryCertificate,
+ errorResponses: errorResponses,
+ enableLogging: true,
+ logBucket: loggingBucket,
+ logFilePrefix: 'cloudfront-logs/',
+ });
+
+ new BucketDeployment(this, 'deploy-static-website', {
+ sources: [Source.asset(props.distFolderPath)],
+ destinationBucket: bucketWebsite,
+ distribution,
+ distributionPaths: ['/*'],
+ });
+
+ const aliasRecords: ARecord[] = [];
+ for (const [index, domainConfig] of props.domains.entries()) {
+ const fullDomainName =
+ domainConfig.subdomain && domainConfig.subdomain.length > 0
+ ? `${domainConfig.subdomain}.${domainConfig.domainName}`.toLowerCase()
+ : domainConfig.domainName.toLowerCase();
+
+ const zoneLogicalId =
+ index === 0
+ ? 'publicHostedZone-0'
+ : `hostedZone-${fullDomainName.replace(/[.-]/g, '')}`;
+
+ const zoneFromAttributes = HostedZone.fromHostedZoneAttributes(
+ this,
+ zoneLogicalId,
+ {
+ zoneName: domainConfig.domainName,
+ hostedZoneId: domainConfig.hostedZoneId,
+ },
+ );
+
+ const recordLogicalId =
+ index === 0
+ ? 'webDomainRecord-0'
+ : `webDomainRecord-${fullDomainName.replace(/[.-]/g, '')}`;
+
+ const aliasRecord = new ARecord(this, recordLogicalId, {
+ zone: zoneFromAttributes,
+ recordName: fullDomainName,
+ target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
+ });
+
+ aliasRecords.push(aliasRecord);
+ }
+
+ new CfnOutput(this, 'CloudFrontDistributionDomainName', {
+ value: distribution.distributionDomainName,
+ description: 'CloudFront distribution domain',
+ exportName: `${this.toCloudFormation()}-${props.envName}-CdnDomainName`,
+ });
+
+ new CfnOutput(this, 'DnsRecordName', {
+ value: aliasRecords[0].domainName || allDomainNames[0],
+ description: 'The DNS record name (primary)',
+ exportName: `${this.toCloudFormation()}-${props.envName}-AliasRecord`,
+ });
+ }
+}
diff --git a/src/iac/src/config/application/deployInfrastructure/deployInfrastructureHandler.ts b/src/iac/src/config/application/deployInfrastructure/deployInfrastructureHandler.ts
new file mode 100644
index 00000000..94969a73
--- /dev/null
+++ b/src/iac/src/config/application/deployInfrastructure/deployInfrastructureHandler.ts
@@ -0,0 +1,82 @@
+import type { App, Environment, Stack } from 'aws-cdk-lib';
+import { VpcLookupStack } from '../../../aws/network/vpcLookupStack';
+import { StackBuilderFactory } from '../../domain/builders/factories/stackBuilderFactory';
+import type { ILogger } from '../../domain/ports/iLogger';
+import type { IProjectPath } from '../../domain/ports/iProjectPath';
+import { StackBuilderService } from '../../domain/services/stackBuilderService';
+import { ConfigValidator } from '../../domain/validation/configValidator';
+import { ConsoleDeploymentLogger } from '../../infrastructure/logging/consoleDeploymentLogger';
+import { FileProjectPath } from '../../infrastructure/projectPath/fileProjectPath';
+import type { IDeploymentRequest } from './models/deploymentRequest';
+
+/**
+ * Use case: Deploy Infrastructure
+ * Orchestrates the CDK deployment process
+ */
+export class DeployInfrastructureHandler {
+ private readonly app: App;
+ private readonly envFromCli: Environment;
+ private readonly request: IDeploymentRequest;
+ private readonly projectPathResolver: IProjectPath;
+ private readonly logger: ILogger;
+ private readonly validator: ConfigValidator;
+
+ constructor(app: App, envFromCli: Environment, request: IDeploymentRequest) {
+ this.app = app;
+ this.envFromCli = envFromCli;
+ this.request = request;
+
+ this.logger = new ConsoleDeploymentLogger();
+ this.validator = new ConfigValidator();
+
+ this.projectPathResolver = new FileProjectPath(this.request.rootPath);
+ }
+
+ public getProjectPathResolver(): IProjectPath {
+ return this.projectPathResolver;
+ }
+
+ public run(): Stack[] {
+ try {
+ this.validator.validate(this.request);
+ this.logger.displayDeploymentInfo(
+ this.request,
+ this.projectPathResolver,
+ this.envFromCli.region,
+ this.envFromCli.account,
+ );
+ const stacks = this.buildStacks();
+ return stacks;
+ } catch (error) {
+ if (error instanceof Error) {
+ this.logger.logError(error);
+ }
+ throw error;
+ }
+ }
+
+ private buildStacks(): Stack[] {
+ const vpcStack = new VpcLookupStack(this.app, {
+ env: this.envFromCli,
+ vpcId: this.request.vpcId,
+ });
+
+ const stackBuilder = new StackBuilderService(
+ this.logger,
+ this.request.repoName,
+ this.envFromCli,
+ vpcStack.vpc,
+ this.app.node,
+ this.request.environment,
+ );
+
+ stackBuilder.getBranchName();
+
+ const stackParts = StackBuilderFactory.createStackParts(
+ this.app,
+ this.request,
+ );
+
+ return stackBuilder.buildStackParts(stackParts);
+ }
+}
diff --git a/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts b/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
new file mode 100644
index 00000000..7c7a4aa9
--- /dev/null
+++ b/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
@@ -0,0 +1,60 @@
+import type { AppEnvironment } from '../../../domain/model/appEnvironment';
+import type {
+ FrontendStackConfig,
+ SharedStackConfig,
+} from '../../../domain/model/stackConfig';
+
+/**
+ * IAC Domain configuration interface
+ */
+export interface IacDomainConfig {
+ /** Base domain name */
+ name: string;
+ /** ACM Certificate ID (without full ARN) */
+ certificateId: string;
+ /** Route53 Hosted Zone ID */
+ hostedZoneId: string;
+}
+
+/**
+ * Stacks configuration interface
+ */
+export interface StacksConfig {
+ frontend: FrontendStackConfig;
+ shared: SharedStackConfig;
+}
+
+/**
+ * Main Deployment configuration interface
+ */
+export interface IDeploymentRequest {
+ /** GitHub repository name */
+ repoName: string;
+
+ /** AWS VPC ID for deployment */
+ vpcId: string;
+
+ /** Git branch for deployment */
+ branch: string;
+
+ /** Application environment */
+ environment: AppEnvironment;
+
+ /** Domain configuration */
+ domain: IacDomainConfig;
+
+ /** Stacks configuration */
+ stacks: StacksConfig;
+
+ /**
+ * GitHub secret ARN for pipeline authentication
+ * @optional If not provided, a default pattern will be used
+ */
+ githubSecretArn?: string;
+
+ /**
+ * Root path for project resolution
+ * @optional Defaults to process.cwd()/../../../ if not specified
+ */
+ rootPath?: string;
+}
diff --git a/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts b/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts
new file mode 100644
index 00000000..3ebaaf08
--- /dev/null
+++ b/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts
@@ -0,0 +1,47 @@
+import type { App } from 'aws-cdk-lib';
+import type { IDeploymentRequest } from '../../../application/deployInfrastructure/models/deploymentRequest';
+import { FileProjectPath } from '../../../infrastructure/projectPath/fileProjectPath';
+import type { IStackBuilder } from '../../iStackBuilder';
+import type { IProjectPath } from '../../ports/iProjectPath';
+import { FrontendBuilder } from '../frontendBuilder';
+import { SharedBuilder } from '../sharedBuilder';
+
+/**
+ * Factory for creating stack builders based on configuration
+ */
+// biome-ignore lint/complexity/noStaticOnlyClass: factory pattern used across codebase
+export class StackBuilderFactory {
+ static createStackParts(
+ app: App,
+ config: IDeploymentRequest,
+ ): IStackBuilder[] {
+ const stackParts: IStackBuilder[] = [];
+
+ const projectPathResolver: IProjectPath = new FileProjectPath(
+ config.rootPath,
+ );
+
+ if (config.stacks.frontend) {
+ stackParts.push(
+ new FrontendBuilder({
+ stackName: 'FrontendStack',
+ scope: app,
+ iacConfig: config,
+ projectPathResolver,
+ }),
+ );
+ }
+
+ if (config.stacks.shared) {
+ stackParts.push(
+ new SharedBuilder({
+ stackName: 'SharedStack',
+ scope: app,
+ iacConfig: config,
+ }),
+ );
+ }
+
+ return stackParts;
+ }
+}
diff --git a/src/iac/src/config/domain/builders/frontendBuilder.ts b/src/iac/src/config/domain/builders/frontendBuilder.ts
new file mode 100644
index 00000000..1deffd0b
--- /dev/null
+++ b/src/iac/src/config/domain/builders/frontendBuilder.ts
@@ -0,0 +1,67 @@
+import type { Stack } from 'aws-cdk-lib';
+import type { StaticWebsiteStackProps } from '../../../aws/website/staticWebsiteStack';
+import { StaticWebsiteStack } from '../../../aws/website/staticWebsiteStack';
+import type { IacDomainConfig } from '../../application/deployInfrastructure/models/deploymentRequest';
+import type { IStackBuildContext, IStackBuildProps } from '../iStackBuilder';
+import { IStackBuilder } from '../iStackBuilder';
+import type { FrontendStackConfig } from '../model/stackConfig';
+import type { IProjectPath } from '../ports/iProjectPath';
+
+export interface FrontendBuilderProps extends IStackBuildProps {
+ projectPathResolver: IProjectPath;
+}
+
+export class FrontendBuilder extends IStackBuilder {
+ private readonly frontendConfig: FrontendStackConfig;
+ private readonly domain: IacDomainConfig;
+ private readonly projectPathResolver: IProjectPath;
+
+ constructor(frontendProps: FrontendBuilderProps) {
+ super(frontendProps);
+ if (!frontendProps.iacConfig.stacks.frontend) {
+ throw new Error('Frontend stack configuration is required');
+ }
+ this.frontendConfig = frontendProps.iacConfig.stacks.frontend;
+ this.domain = frontendProps.iacConfig.domain;
+ this.projectPathResolver = frontendProps.projectPathResolver;
+ }
+
+ build(context: IStackBuildContext): Stack[] {
+ this.context = context;
+ const stacks: Stack[] = [];
+
+ for (const websiteConfig of this.frontendConfig.staticWebsites) {
+ const staticWebsiteStack = this.createStaticWebsiteStack(websiteConfig);
+ stacks.push(staticWebsiteStack);
+ }
+
+ return stacks;
+ }
+
+ private createStaticWebsiteStack(
+ config: FrontendStackConfig['staticWebsites'][number],
+ ): StaticWebsiteStack {
+ const domainConfig = {
+ subdomain: config.subdomain,
+ domainName: this.domain.name,
+ certificateId: this.domain.certificateId,
+ hostedZoneId: this.domain.hostedZoneId,
+ };
+
+ const distFolderPath = this.projectPathResolver.resolveFullPath(
+ config.projectPath,
+ );
+
+ const frontendStackProps: StaticWebsiteStackProps = {
+ env: this.context.env,
+ name: config.name,
+ domains: [domainConfig],
+ distFolderPath,
+ envName: this.context.environment,
+ githubRepo: this.props.iacConfig.repoName,
+ stackName: `${this.props.iacConfig.repoName}-${config.name}`,
+ };
+
+ return new StaticWebsiteStack(this.props.scope, frontendStackProps);
+ }
+}
diff --git a/src/iac/src/config/domain/builders/sharedBuilder.ts b/src/iac/src/config/domain/builders/sharedBuilder.ts
new file mode 100644
index 00000000..a11e4409
--- /dev/null
+++ b/src/iac/src/config/domain/builders/sharedBuilder.ts
@@ -0,0 +1,65 @@
+import { RemovalPolicy, type Stack } from 'aws-cdk-lib';
+import type { PipelineStackProps } from '../../../aws/developerTools/codepipeline/pipelineStack';
+import { PipelineStack } from '../../../aws/developerTools/codepipeline/pipelineStack';
+import type { IacDomainConfig } from '../../application/deployInfrastructure/models/deploymentRequest';
+import type { IStackBuildContext, IStackBuildProps } from '../iStackBuilder';
+import { IStackBuilder } from '../iStackBuilder';
+import type { SharedStackConfig } from '../model/stackConfig';
+
+export type SharedBuilderProps = IStackBuildProps;
+
+export class SharedBuilder extends IStackBuilder {
+ private readonly sharedConfig: SharedStackConfig;
+ private readonly domain: IacDomainConfig;
+ private readonly repoName: string;
+
+ constructor(sharedProps: SharedBuilderProps) {
+ super(sharedProps);
+ if (!sharedProps.iacConfig.stacks.shared) {
+ throw new Error('Shared stack configuration is required');
+ }
+ this.sharedConfig = sharedProps.iacConfig.stacks.shared;
+ this.domain = sharedProps.iacConfig.domain;
+ this.repoName = sharedProps.iacConfig.repoName;
+ }
+
+ build(context: IStackBuildContext): Stack[] {
+ this.context = context;
+ const stacks: Stack[] = [];
+
+ if (this.sharedConfig.pipeline) {
+ for (const pipelineConfig of this.sharedConfig.pipeline) {
+ stacks.push(this.createPipelineStack(pipelineConfig));
+ }
+ }
+
+ return stacks;
+ }
+
+ private createPipelineStack(
+ config: NonNullable[number],
+ ): PipelineStack {
+ const pipeline: PipelineStackProps = {
+ name: 'Pipeline',
+ branch: this.props.iacConfig.branch,
+ githubRepo: this.repoName,
+ envName: this.context.environment,
+ secretTokenArn:
+ this.props.iacConfig.githubSecretArn ??
+ `arn:aws:secretsmanager:${this.context.env.region}:${this.context.env.account}:secret:github-access-token-secret-maOkMI`,
+ testBuildSpec: [...config.testBuildSpecs],
+ deployBuildSpec: [...config.deployBuildSpecs],
+ testProjectName: `${this.repoName}-Tests`,
+ vpc: this.context.vpc,
+ env: this.context.env,
+ bucketRemovalPolicy: RemovalPolicy.DESTROY,
+ domain: this.domain.name,
+ stackName: `${this.repoName}-CodePipeline`,
+ manualApproval: config.manualApproval,
+ slackChannelConfigurationName: config.slackChannelConfigurationName,
+ cacheConfig: { type: 's3' },
+ };
+
+ return new PipelineStack(this.props.scope, pipeline);
+ }
+}
diff --git a/src/iac/src/config/domain/customStack.ts b/src/iac/src/config/domain/customStack.ts
new file mode 100644
index 00000000..afd5d7b2
--- /dev/null
+++ b/src/iac/src/config/domain/customStack.ts
@@ -0,0 +1,64 @@
+import { Stack, type StackProps, Tags } from 'aws-cdk-lib';
+import type { Construct } from 'constructs';
+import { formatRepoNameForCloudFormation } from '../infrastructure/utilities/cloudFormationUtils';
+import type { AppEnvironment } from './model/appEnvironment';
+
+/**
+ * Configuration for a domain that the stack should serve.
+ * Used for multi-domain support in website stacks.
+ */
+export interface DomainConfig {
+ /** Optional subdomain prefix (e.g., "www", "api", "dashboard") */
+ subdomain?: string;
+ /** Root domain name (e.g., "example.com") */
+ domainName: string;
+ /** Route 53 hosted zone ID for this domain */
+ hostedZoneId: string;
+ /** ACM certificate ID (without the ARN prefix) */
+ certificateId: string;
+}
+
+export interface CustomStackProps extends StackProps {
+ githubRepo: string;
+ envName: AppEnvironment;
+ name: string;
+ stackName: string;
+}
+
+export class CustomStack extends Stack {
+ props: CustomStackProps;
+
+ constructor(scope: Construct, props: CustomStackProps) {
+ super(scope, getStackName(props), props);
+
+ this.props = props;
+
+ this.addProjectTags();
+ }
+
+ getStackId(): string {
+ return getStackName(this.props);
+ }
+
+ private addProjectTags(): void {
+ Tags.of(this).add('StackId', getStackName(this.props), {
+ priority: 300,
+ });
+
+ Tags.of(this).add('Environment', this.props.envName.valueOf(), {
+ priority: 300,
+ });
+
+ Tags.of(this).add('Project', this.props.githubRepo, {
+ priority: 300,
+ });
+ }
+
+ public toCloudFormation(): string {
+ return formatRepoNameForCloudFormation(this.props.githubRepo);
+ }
+}
+
+function getStackName(props: CustomStackProps): string {
+ return `macalbert-${formatRepoNameForCloudFormation(props.githubRepo)}-${props.name}-${props.envName}-stack`.toLowerCase();
+}
diff --git a/src/iac/src/config/domain/iStackBuilder.ts b/src/iac/src/config/domain/iStackBuilder.ts
new file mode 100644
index 00000000..176f7802
--- /dev/null
+++ b/src/iac/src/config/domain/iStackBuilder.ts
@@ -0,0 +1,43 @@
+import type { Environment, Stack } from 'aws-cdk-lib';
+import type { IVpc } from 'aws-cdk-lib/aws-ec2';
+import type { Construct } from 'constructs';
+import type { IDeploymentRequest } from '../application/deployInfrastructure/models/deploymentRequest';
+import { formatRepoNameForCloudFormation } from '../infrastructure/utilities/cloudFormationUtils';
+import type { AppEnvironment } from './model/appEnvironment';
+
+export interface IStackBuildProps {
+ stackName: string;
+ scope: Construct;
+ iacConfig: IDeploymentRequest;
+}
+
+export interface IStackBuildContext {
+ env: Environment;
+ vpc: IVpc;
+ environment: AppEnvironment;
+}
+
+export abstract class IStackBuilder {
+ protected props: IStackBuildProps;
+ protected context: IStackBuildContext;
+
+ constructor(props: IStackBuildProps) {
+ this.props = props;
+ }
+
+ abstract build(context: IStackBuildContext): Stack[];
+
+ /**
+ * Get the IAC configuration
+ */
+ public getIacConfig(): IDeploymentRequest {
+ return this.props.iacConfig;
+ }
+
+ /**
+ * Returns a formatted repository name that complies with AWS CloudFormation stack naming requirements.
+ */
+ public formatRepoNameForCloudFormation(): string {
+ return formatRepoNameForCloudFormation(this.props.iacConfig.repoName);
+ }
+}
diff --git a/src/iac/src/config/domain/model/appEnvironment.ts b/src/iac/src/config/domain/model/appEnvironment.ts
new file mode 100644
index 00000000..c4546b8e
--- /dev/null
+++ b/src/iac/src/config/domain/model/appEnvironment.ts
@@ -0,0 +1,8 @@
+export enum AppEnvironment {
+ Production = 'Production',
+ Development = 'Development',
+ Beta = 'Beta',
+ Staging = 'Staging',
+ GithubAction = 'GithubAction',
+ Test = 'Test',
+}
diff --git a/src/iac/src/config/domain/model/deploymentConfig.ts b/src/iac/src/config/domain/model/deploymentConfig.ts
new file mode 100644
index 00000000..b1169c8e
--- /dev/null
+++ b/src/iac/src/config/domain/model/deploymentConfig.ts
@@ -0,0 +1,21 @@
+import type { AppEnvironment } from './appEnvironment';
+import type { FrontendStackConfig, SharedStackConfig } from './stackConfig';
+
+/**
+ * Main deployment configuration interface for IAC projects
+ */
+export interface IDeploymentConfig {
+ repoName: string;
+ branch: string;
+ vpcId: string;
+ environment: AppEnvironment;
+ domain: {
+ name: string;
+ certificateId: string;
+ hostedZoneId: string;
+ };
+ stacks: {
+ frontend: FrontendStackConfig;
+ shared: SharedStackConfig;
+ };
+}
diff --git a/src/iac/src/config/domain/model/stackConfig.ts b/src/iac/src/config/domain/model/stackConfig.ts
new file mode 100644
index 00000000..d848eda2
--- /dev/null
+++ b/src/iac/src/config/domain/model/stackConfig.ts
@@ -0,0 +1,31 @@
+// ============================================================================
+// FRONTEND TYPES
+// ============================================================================
+
+export interface ModulePathConfig {
+ name: string;
+ projectPath: string;
+}
+
+export interface StaticWebsiteConfig extends ModulePathConfig {
+ subdomain: string;
+}
+
+export interface FrontendStackConfig {
+ staticWebsites: readonly StaticWebsiteConfig[];
+}
+
+// ============================================================================
+// SHARED TYPES
+// ============================================================================
+
+export interface PipelineConfig {
+ manualApproval: boolean;
+ slackChannelConfigurationName?: string;
+ testBuildSpecs: readonly string[];
+ deployBuildSpecs: readonly string[];
+}
+
+export interface SharedStackConfig {
+ pipeline?: readonly PipelineConfig[];
+}
diff --git a/src/iac/src/config/domain/ports/iFileOperations.ts b/src/iac/src/config/domain/ports/iFileOperations.ts
new file mode 100644
index 00000000..ef65c50b
--- /dev/null
+++ b/src/iac/src/config/domain/ports/iFileOperations.ts
@@ -0,0 +1,36 @@
+/**
+ * Interface for file operations
+ */
+export interface IFileOperations {
+ /**
+ * Copy a file from source to destination
+ * @param source Source file path
+ * @param destination Destination file path
+ */
+ copyFile(source: string, destination: string): void;
+
+ /**
+ * Delete a file
+ * @param filePath File path to delete
+ */
+ deleteFile(filePath: string): void;
+
+ /**
+ * Check if a file exists
+ * @param filePath File path to check
+ * @returns True if file exists, false otherwise
+ */
+ fileExists(filePath: string): boolean;
+
+ /**
+ * Read file contents
+ * @param filePath File path to read
+ * @returns File contents as string
+ */
+ readFile(filePath: string): string;
+
+ /**
+ * Disable Docker Buildx attestations if not already disabled
+ */
+ disableBuildxAttestations(): void;
+}
diff --git a/src/iac/src/config/domain/ports/iLogger.ts b/src/iac/src/config/domain/ports/iLogger.ts
new file mode 100644
index 00000000..6a397690
--- /dev/null
+++ b/src/iac/src/config/domain/ports/iLogger.ts
@@ -0,0 +1,45 @@
+import type { IDeploymentRequest } from '../../application/deployInfrastructure/models/deploymentRequest';
+import type { IProjectPath } from './iProjectPath';
+
+/**
+ * Interface for logging deployment information
+ */
+export interface ILogger {
+ /**
+ * Display deployment information
+ * @param config Deployment configuration
+ * @param pathResolver Project path resolver
+ * @param region AWS region
+ * @param account AWS account ID
+ */
+ displayDeploymentInfo(
+ config: IDeploymentRequest,
+ pathResolver: IProjectPath,
+ region?: string,
+ account?: string,
+ ): void;
+
+ /**
+ * Log that requested stacks are being built
+ */
+ logRequestedStacks(): void;
+
+ /**
+ * Log repository information
+ * @param repoName Repository name
+ * @param branchName Branch name
+ */
+ logRepositoryInfo(repoName: string, branchName: string): void;
+
+ /**
+ * Log an informational message
+ * @param message Message to log
+ */
+ logInfo(message: string): void;
+
+ /**
+ * Log an error
+ * @param error Error to log
+ */
+ logError(error: Error): void;
+}
diff --git a/src/iac/src/config/domain/ports/iProjectPath.ts b/src/iac/src/config/domain/ports/iProjectPath.ts
new file mode 100644
index 00000000..52490bf5
--- /dev/null
+++ b/src/iac/src/config/domain/ports/iProjectPath.ts
@@ -0,0 +1,23 @@
+/**
+ * Interface for resolving project paths.
+ * This abstraction allows different implementations of path resolution
+ * for different project structures.
+ */
+export interface IProjectPath {
+ /**
+ * Get the root path of the project/repository
+ */
+ getRootPath(): string;
+
+ /**
+ * Resolve a relative path to a full absolute path
+ * @param relativePath Path relative to the repository root
+ */
+ resolveFullPath(relativePath: string): string;
+
+ /**
+ * Generate the Dockerfile destination path from a project path
+ * @param projectPath Path to the project containing the Dockerfile
+ */
+ generateDockerfileDest(projectPath: string): string;
+}
diff --git a/src/iac/src/config/domain/services/stackBuilderService.ts b/src/iac/src/config/domain/services/stackBuilderService.ts
new file mode 100644
index 00000000..aac16281
--- /dev/null
+++ b/src/iac/src/config/domain/services/stackBuilderService.ts
@@ -0,0 +1,82 @@
+import type { Environment, Stack } from 'aws-cdk-lib';
+import type { IVpc } from 'aws-cdk-lib/aws-ec2';
+import type { Node } from 'constructs';
+import type { AppEnvironment } from '../../domain/model/appEnvironment';
+import type { ILogger } from '../../domain/ports/iLogger';
+import { StackBuildError } from '../../infrastructure/utilities/errors';
+import type { IStackBuilder } from '../iStackBuilder';
+
+/**
+ * Service responsible for building stacks from stack parts
+ */
+export class StackBuilderService {
+ constructor(
+ private readonly logger: ILogger,
+ private readonly githubRepo: string,
+ private readonly env: Environment,
+ private readonly vpc: IVpc,
+ private readonly node: Node,
+ private readonly environment: AppEnvironment,
+ ) {}
+
+ /**
+ * Get branch name from CDK context or default to main
+ */
+ getBranchName(): string {
+ const branchName = this.node.tryGetContext('branch') ?? 'main';
+ this.logger.logRepositoryInfo(this.githubRepo, branchName);
+ return branchName;
+ }
+
+ /**
+ * Build all stack parts
+ * @param stackParts Array of stack builders to build
+ * @returns Array of all created stacks
+ */
+ buildStackParts(stackParts: IStackBuilder[]): Stack[] {
+ this.logger.logRequestedStacks();
+
+ const context = {
+ env: this.env,
+ vpc: this.vpc,
+ environment: this.environment,
+ };
+
+ const allStacks: Stack[] = [];
+
+ for (const stack of stackParts) {
+ try {
+ const stacks = stack.build(context);
+ allStacks.push(...stacks);
+ } catch (error: unknown) {
+ // Check if this is a "Cannot find asset" error which can be safely ignored
+ if (typeof error === 'object' && error !== null) {
+ const errorMessage = error.toString();
+ if (errorMessage.includes('Error: Cannot find asset')) {
+ // Log ignored error for visibility
+ console.warn(
+ `⚠️ Ignoring "Cannot find asset" error in ${this.getStackName(stack)}: ${errorMessage}`,
+ );
+ } else {
+ throw new StackBuildError(
+ `Failed to build stack part: ${this.getStackName(stack)}`,
+ this.getStackName(stack),
+ error instanceof Error ? error : undefined,
+ );
+ }
+ } else {
+ throw error;
+ }
+ }
+ }
+
+ return allStacks;
+ }
+
+ /**
+ * Get stack name from stack part for error reporting
+ */
+ private getStackName(stack: IStackBuilder): string {
+ return stack.constructor.name;
+ }
+}
diff --git a/src/iac/src/config/domain/validation/configValidator.ts b/src/iac/src/config/domain/validation/configValidator.ts
new file mode 100644
index 00000000..333968a6
--- /dev/null
+++ b/src/iac/src/config/domain/validation/configValidator.ts
@@ -0,0 +1,94 @@
+import type { IDeploymentRequest } from '../../application/deployInfrastructure/models/deploymentRequest';
+import { ConfigValidationError } from '../../infrastructure/utilities/errors';
+
+/**
+ * Service responsible for validating IAC configuration
+ */
+export class ConfigValidator {
+ /**
+ * Validate IAC configuration
+ * @param config IAC configuration to validate
+ * @throws ConfigValidationError if validation fails
+ */
+ validate(config: IDeploymentRequest): void {
+ const errors: string[] = [];
+
+ // Validate required string fields
+ if (!config.repoName || config.repoName.trim() === '') {
+ errors.push('repoName is required and cannot be empty');
+ }
+
+ if (!config.vpcId || config.vpcId.trim() === '') {
+ errors.push('vpcId is required and cannot be empty');
+ }
+
+ if (!config.branch || config.branch.trim() === '') {
+ errors.push('branch is required and cannot be empty');
+ }
+
+ // Validate domain configuration
+ if (!config.domain) {
+ errors.push('domain configuration is required');
+ } else {
+ if (!config.domain.name || config.domain.name.trim() === '') {
+ errors.push('domain.name is required and cannot be empty');
+ }
+
+ if (
+ !config.domain.certificateId ||
+ config.domain.certificateId.trim() === ''
+ ) {
+ errors.push('domain.certificateId is required and cannot be empty');
+ }
+
+ if (
+ !config.domain.hostedZoneId ||
+ config.domain.hostedZoneId.trim() === ''
+ ) {
+ errors.push('domain.hostedZoneId is required and cannot be empty');
+ }
+ }
+
+ // Validate stacks configuration
+ if (!config.stacks) {
+ errors.push('stacks configuration is required');
+ } else {
+ if (!config.stacks.frontend) {
+ errors.push('stacks.frontend is required');
+ } else {
+ this.validateFrontendStacks(config.stacks.frontend, errors);
+ }
+ }
+
+ // Throw error if validation failed
+ if (errors.length > 0) {
+ throw new ConfigValidationError(
+ `Configuration validation failed with ${errors.length} error(s)`,
+ errors,
+ );
+ }
+ }
+
+ private validateFrontendStacks(
+ frontend: IDeploymentRequest['stacks']['frontend'],
+ errors: string[],
+ ): void {
+ if (frontend.staticWebsites) {
+ for (const [index, website] of frontend.staticWebsites.entries()) {
+ if (!website.name || website.name.trim() === '') {
+ errors.push(`frontend.staticWebsites[${index}].name is required`);
+ }
+ if (!website.projectPath || website.projectPath.trim() === '') {
+ errors.push(
+ `frontend.staticWebsites[${index}].projectPath is required`,
+ );
+ }
+ if (!website.subdomain || website.subdomain.trim() === '') {
+ errors.push(
+ `frontend.staticWebsites[${index}].subdomain is required`,
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/src/iac/src/config/infrastructure/fileOperations/fileOperations.ts b/src/iac/src/config/infrastructure/fileOperations/fileOperations.ts
new file mode 100644
index 00000000..6a1d194d
--- /dev/null
+++ b/src/iac/src/config/infrastructure/fileOperations/fileOperations.ts
@@ -0,0 +1,81 @@
+import fs from 'node:fs';
+import type { IFileOperations } from '../../domain/ports/iFileOperations';
+import { FileOperationError } from '../utilities/errors';
+
+/**
+ * Service responsible for file operations during deployment
+ */
+export class FileOperations implements IFileOperations {
+ /**
+ * Copy a file from source to destination
+ * @param source Source file path
+ * @param destination Destination file path
+ * @throws FileOperationError if copy fails
+ */
+ copyFile(source: string, destination: string): void {
+ try {
+ fs.copyFileSync(source, destination);
+ } catch (error) {
+ throw new FileOperationError(
+ `Failed to copy file from ${source} to ${destination}`,
+ source,
+ error instanceof Error ? error : undefined,
+ );
+ }
+ }
+
+ /**
+ * Delete a file
+ * @param filePath File path to delete
+ * @throws FileOperationError if deletion fails
+ */
+ deleteFile(filePath: string): void {
+ try {
+ if (fs.existsSync(filePath)) {
+ fs.unlinkSync(filePath);
+ }
+ } catch (error) {
+ throw new FileOperationError(
+ `Failed to delete file ${filePath}`,
+ filePath,
+ error instanceof Error ? error : undefined,
+ );
+ }
+ }
+
+ /**
+ * Check if a file exists
+ * @param filePath File path to check
+ * @returns True if file exists, false otherwise
+ */
+ fileExists(filePath: string): boolean {
+ return fs.existsSync(filePath);
+ }
+
+ /**
+ * Read file contents
+ * @param filePath File path to read
+ * @returns File contents as string
+ * @throws FileOperationError if read fails
+ */
+ readFile(filePath: string): string {
+ try {
+ return fs.readFileSync(filePath, 'utf-8');
+ } catch (error) {
+ throw new FileOperationError(
+ `Failed to read file ${filePath}`,
+ filePath,
+ error instanceof Error ? error : undefined,
+ );
+ }
+ }
+
+ /**
+ * Disable Docker Buildx attestations if not already disabled
+ */
+ disableBuildxAttestations(): void {
+ if (!process.env.BUILDX_NO_DEFAULT_ATTESTATIONS) {
+ process.env.BUILDX_NO_DEFAULT_ATTESTATIONS = '1';
+ }
+ }
+}
diff --git a/src/iac/src/config/infrastructure/logging/consoleDeploymentLogger.ts b/src/iac/src/config/infrastructure/logging/consoleDeploymentLogger.ts
new file mode 100644
index 00000000..5516744a
--- /dev/null
+++ b/src/iac/src/config/infrastructure/logging/consoleDeploymentLogger.ts
@@ -0,0 +1,140 @@
+import type { IDeploymentRequest } from '../../application/deployInfrastructure/models/deploymentRequest';
+import type { ModulePathConfig } from '../../domain/model/stackConfig';
+import type { ILogger } from '../../domain/ports/iLogger';
+import type { IProjectPath } from '../../domain/ports/iProjectPath';
+
+/**
+ * Service responsible for logging and displaying deployment information.
+ */
+export class ConsoleDeploymentLogger implements ILogger {
+ private log(message: string): void {
+ console.log(message);
+ }
+
+ private logColored(color: string, message: string): void {
+ console.log(`${color}${message}\x1b[0m`);
+ }
+
+ /**
+ * Display deployment information
+ * @param config IAC configuration
+ * @param pathResolver Project path resolver
+ * @param region AWS region
+ * @param account AWS account ID
+ */
+ displayDeploymentInfo(
+ config: IDeploymentRequest,
+ pathResolver: IProjectPath,
+ region?: string,
+ account?: string,
+ ): void {
+ this.log(
+ `\n------[${config.repoName}]----------------------------------------------------------------`,
+ );
+ this.logColored('\x1b[36m', '🔑 Credentials loaded from AWS CLI');
+
+ if (region) {
+ this.log(`Region: ${region}`);
+ }
+
+ if (account) {
+ this.log(`Account: ***${account.slice(-4)}`);
+ }
+
+ this.log('');
+
+ this.logModulePathsTable(config, pathResolver);
+ }
+
+ /**
+ * Log module paths in a formatted table
+ * @param config IAC configuration
+ * @param pathResolver Project path resolver
+ */
+ private logModulePathsTable(
+ config: IDeploymentRequest,
+ pathResolver: IProjectPath,
+ ): void {
+ const pathEntries: Array<{ label: string; value: string }> = [
+ {
+ label: 'Repository Root',
+ value: pathResolver.getRootPath(),
+ },
+ ];
+
+ const modules: ReadonlyArray = [
+ ...config.stacks.frontend.staticWebsites,
+ ];
+
+ for (const moduleConfig of modules) {
+ pathEntries.push({
+ label: moduleConfig.name,
+ value: pathResolver.resolveFullPath(moduleConfig.projectPath),
+ });
+ }
+
+ // Calculate column widths
+ const maxLabelLength = Math.max(
+ ...pathEntries.map((entry) => entry.label.length),
+ );
+
+ const maxValueLength = Math.max(
+ ...pathEntries.map((entry) => entry.value.length),
+ );
+
+ // Build table
+ const tableWidth = maxLabelLength + maxValueLength + 6;
+ const headerTitle = ' 📁 Module Paths Configuration ';
+ const headerPadding = Math.max(0, tableWidth - headerTitle.length - 2);
+
+ this.log(`\n╭─${headerTitle}${'─'.repeat(headerPadding)}╮`);
+
+ for (const { label, value } of pathEntries) {
+ const paddedLabel = label.padEnd(maxLabelLength);
+ const paddedValue = value.padEnd(maxValueLength);
+ this.log(`│ ${paddedLabel} │ ${paddedValue} │`);
+ }
+
+ this.log(
+ `╰${'─'.repeat(maxLabelLength + 2)}┴${'─'.repeat(maxValueLength + 2)}╯\n`,
+ );
+ }
+
+ /**
+ * Log requested stacks
+ */
+ logRequestedStacks(): void {
+ this.logColored('\x1b[36m', '🎯 Requested stacks:');
+ }
+
+ /**
+ * Log repository information
+ * @param repoName Repository name
+ * @param branchName Branch name
+ */
+ logRepositoryInfo(repoName: string, branchName: string): void {
+ this.logColored(
+ '\x1b[33m',
+ `🔌 Repository source https://github.com/macalbert/${repoName}/tree/${branchName}`,
+ );
+ }
+
+ /**
+ * Log an informational message
+ * @param message Message to log
+ */
+ logInfo(message: string): void {
+ this.log(message);
+ }
+
+ /**
+ * Log error message
+ * @param error Error to log
+ */
+ logError(error: Error): void {
+ console.error(`\x1b[31m❌ Error: ${error.message}\x1b[0m`);
+ if (error.stack) {
+ console.error(error.stack);
+ }
+ }
+}
diff --git a/src/iac/src/config/infrastructure/projectPath/fileProjectPath.ts b/src/iac/src/config/infrastructure/projectPath/fileProjectPath.ts
new file mode 100644
index 00000000..427327bb
--- /dev/null
+++ b/src/iac/src/config/infrastructure/projectPath/fileProjectPath.ts
@@ -0,0 +1,31 @@
+import path from 'node:path';
+import type { IProjectPath } from '../../domain/ports/iProjectPath';
+import { toKebabCase } from '../utilities/stringUtils';
+
+export class FileProjectPath implements IProjectPath {
+ private readonly rootPath: string;
+
+ constructor(rootPath?: string) {
+ this.rootPath = rootPath ?? path.join(process.cwd(), '../../../');
+ }
+
+ public getRootPath(): string {
+ return this.rootPath;
+ }
+
+ public generateDockerfileDest(projectPath: string): string {
+ const pathSegments = projectPath.split(/[/\\]/);
+ const appNameIndex = pathSegments.indexOf('apps') + 1;
+ if (appNameIndex === 0 || appNameIndex >= pathSegments.length) {
+ throw new Error(
+ `Cannot extract app name from project path: ${projectPath}`,
+ );
+ }
+ const appName = pathSegments[appNameIndex];
+ return `Dockerfile.${toKebabCase(appName)}`;
+ }
+
+ public resolveFullPath(projectPath: string): string {
+ return path.join(this.rootPath, projectPath);
+ }
+}
diff --git a/src/iac/src/config/infrastructure/utilities/cloudFormationUtils.ts b/src/iac/src/config/infrastructure/utilities/cloudFormationUtils.ts
new file mode 100644
index 00000000..27ee2df2
--- /dev/null
+++ b/src/iac/src/config/infrastructure/utilities/cloudFormationUtils.ts
@@ -0,0 +1,26 @@
+/**
+ * Utilities for AWS CloudFormation related operations
+ */
+
+/**
+ * Returns a formatted repository name that complies with AWS CloudFormation stack naming requirements.
+ * Stack names must match the regular expression: /^[A-Za-z][A-Za-z0-9-]*$/
+ * - Must start with a letter (A-Z, a-z)
+ * - Can only contain letters, numbers, and hyphens
+ *
+ * @param repoName The GitHub repository name to format
+ * @returns A formatted name that complies with CloudFormation naming requirements
+ */
+export function formatRepoNameForCloudFormation(repoName: string): string {
+ let formattedName = repoName.toLowerCase();
+
+ formattedName = formattedName.replace(/[^A-Za-z0-9]/g, '-');
+ formattedName = formattedName.replace(/-+/g, '-');
+ formattedName = formattedName.replace(/^-|-$/g, '');
+
+ if (!/^[A-Za-z]/.test(formattedName)) {
+ formattedName = `r-${formattedName}`;
+ }
+
+ return formattedName;
+}
diff --git a/src/iac/src/config/infrastructure/utilities/errors.ts b/src/iac/src/config/infrastructure/utilities/errors.ts
new file mode 100644
index 00000000..21de50b4
--- /dev/null
+++ b/src/iac/src/config/infrastructure/utilities/errors.ts
@@ -0,0 +1,72 @@
+/**
+ * Base error class for all IAC deployment errors
+ */
+export class DeploymentError extends Error {
+ public cause?: Error;
+
+ constructor(message: string, cause?: Error) {
+ super(message);
+ this.name = 'DeploymentError';
+ this.cause = cause;
+ Error.captureStackTrace(this, this.constructor);
+ if (cause) {
+ this.stack += `\nCaused by: ${cause.stack}`;
+ }
+ }
+}
+
+/**
+ * Error thrown when file operations fail
+ */
+export class FileOperationError extends DeploymentError {
+ constructor(
+ message: string,
+ public readonly filePath: string,
+ cause?: Error,
+ ) {
+ super(message, cause);
+ this.name = 'FileOperationError';
+ }
+}
+
+/**
+ * Error thrown when ECR authentication fails
+ */
+export class EcrAuthError extends DeploymentError {
+ constructor(
+ message: string,
+ public readonly region?: string,
+ public readonly account?: string,
+ cause?: Error,
+ ) {
+ super(message, cause);
+ this.name = 'EcrAuthError';
+ }
+}
+
+/**
+ * Error thrown when stack building fails
+ */
+export class StackBuildError extends DeploymentError {
+ constructor(
+ message: string,
+ public readonly stackName?: string,
+ cause?: Error,
+ ) {
+ super(message, cause);
+ this.name = 'StackBuildError';
+ }
+}
+
+/**
+ * Error thrown when configuration validation fails
+ */
+export class ConfigValidationError extends DeploymentError {
+ constructor(
+ message: string,
+ public readonly validationErrors: string[],
+ ) {
+ super(message);
+ this.name = 'ConfigValidationError';
+ }
+}
diff --git a/src/iac/src/config/infrastructure/utilities/stringUtils.ts b/src/iac/src/config/infrastructure/utilities/stringUtils.ts
new file mode 100644
index 00000000..572c4eca
--- /dev/null
+++ b/src/iac/src/config/infrastructure/utilities/stringUtils.ts
@@ -0,0 +1,12 @@
+/**
+ * Convert a string to kebab-case
+ * e.g., "Minimal.Api" -> "minimal-api", "WorkerService" -> "worker-service"
+ * @param value The string to convert
+ * @returns The kebab-cased string
+ */
+export function toKebabCase(value: string): string {
+ return value
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
+ .replace(/[\s._]+/g, '-')
+ .toLowerCase();
+}
diff --git a/src/iac/src/infra/buildspecs/production/website.yml b/src/iac/src/infra/buildspecs/production/website.yml
new file mode 100644
index 00000000..d8d4e277
--- /dev/null
+++ b/src/iac/src/infra/buildspecs/production/website.yml
@@ -0,0 +1,31 @@
+version: 0.2
+
+phases:
+ install:
+ runtime-versions:
+ nodejs: 24
+
+ commands:
+ - echo "Install started on `date`"
+ - npm install -g aws-cdk
+ - npm install -g pnpm
+
+ pre_build:
+ commands:
+ - cd envilder
+ - pnpm install --frozen-lockfile
+ - pnpm --filter @envilder/website build
+
+ build:
+ commands:
+ - echo "Build started on `date`"
+ - cd src/iac
+ - cdk deploy envilder-envilder-Website-production-stack --require-approval never
+
+ post_build:
+ commands:
+ - echo "Build completed on `date`"
+
+cache:
+ paths:
+ - "/root/.local/share/pnpm/store/**/*"
diff --git a/src/iac/src/infra/buildspecs/test/iac.yml b/src/iac/src/infra/buildspecs/test/iac.yml
new file mode 100644
index 00000000..f76dfb22
--- /dev/null
+++ b/src/iac/src/infra/buildspecs/test/iac.yml
@@ -0,0 +1,28 @@
+version: 0.2
+
+phases:
+ install:
+ runtime-versions:
+ nodejs: 24
+
+ commands:
+ - echo "Install started on `date`"
+ - npm install -g pnpm
+
+ pre_build:
+ commands:
+ - cd envilder/src/iac
+ - pnpm install --frozen-lockfile
+
+ build:
+ commands:
+ - echo "Build started on `date`"
+ - pnpm test:ci
+
+ post_build:
+ commands:
+ - echo "Build completed on `date`"
+
+cache:
+ paths:
+ - "/root/.local/share/pnpm/store/**/*"
diff --git a/src/iac/src/infra/buildspecs/test/website.yml b/src/iac/src/infra/buildspecs/test/website.yml
new file mode 100644
index 00000000..9c62e05b
--- /dev/null
+++ b/src/iac/src/infra/buildspecs/test/website.yml
@@ -0,0 +1,28 @@
+version: 0.2
+
+phases:
+ install:
+ runtime-versions:
+ nodejs: 24
+
+ commands:
+ - echo "Install started on `date`"
+ - npm install -g pnpm
+
+ pre_build:
+ commands:
+ - cd envilder
+ - pnpm install --frozen-lockfile
+
+ build:
+ commands:
+ - echo "Build started on `date`"
+ - pnpm --filter @envilder/website build
+
+ post_build:
+ commands:
+ - echo "Build completed on `date`"
+
+cache:
+ paths:
+ - "/root/.local/share/pnpm/store/**/*"
diff --git a/src/iac/src/infra/config/frontendConfig.ts b/src/iac/src/infra/config/frontendConfig.ts
new file mode 100644
index 00000000..4fb85a78
--- /dev/null
+++ b/src/iac/src/infra/config/frontendConfig.ts
@@ -0,0 +1,11 @@
+import type { FrontendStackConfig } from '../../config/domain/model/stackConfig';
+
+export const frontendConfig: FrontendStackConfig = {
+ staticWebsites: [
+ {
+ name: 'Website',
+ subdomain: 'envilder',
+ projectPath: 'envilder/src/apps/website/dist',
+ },
+ ],
+};
diff --git a/src/iac/src/infra/config/sharedConfig.ts b/src/iac/src/infra/config/sharedConfig.ts
new file mode 100644
index 00000000..c5278f2c
--- /dev/null
+++ b/src/iac/src/infra/config/sharedConfig.ts
@@ -0,0 +1,16 @@
+import type { SharedStackConfig } from '../../config/domain/model/stackConfig';
+
+export const sharedConfig: SharedStackConfig = {
+ pipeline: [
+ {
+ manualApproval: false,
+ testBuildSpecs: [
+ 'envilder/src/iac/src/infra/buildspecs/test/iac.yml',
+ 'envilder/src/iac/src/infra/buildspecs/test/website.yml',
+ ],
+ deployBuildSpecs: [
+ 'envilder/src/iac/src/infra/buildspecs/production/website.yml',
+ ],
+ },
+ ],
+};
diff --git a/src/iac/src/infra/iac.ts b/src/iac/src/infra/iac.ts
new file mode 100644
index 00000000..196da9dd
--- /dev/null
+++ b/src/iac/src/infra/iac.ts
@@ -0,0 +1,24 @@
+#!/usr/bin/env node
+/**
+ * CDK Infrastructure Deployment Entry Point
+ */
+import { App } from 'aws-cdk-lib';
+import type { Environment } from 'aws-cdk-lib';
+import { DeployInfrastructureHandler } from '../config/application/deployInfrastructure/deployInfrastructureHandler';
+import type { IDeploymentConfig } from '../config/domain/model/deploymentConfig';
+import { iacConfig } from './iacConfig';
+
+const envFromCli: Environment = {
+ account: process.env.CDK_DEFAULT_ACCOUNT,
+ region: process.env.CDK_DEFAULT_REGION,
+};
+
+const config: IDeploymentConfig = iacConfig;
+
+const deployment = new DeployInfrastructureHandler(
+ new App(),
+ envFromCli,
+ config,
+);
+
+deployment.run();
diff --git a/src/iac/src/infra/iacConfig.ts b/src/iac/src/infra/iacConfig.ts
new file mode 100644
index 00000000..a8956d8e
--- /dev/null
+++ b/src/iac/src/infra/iacConfig.ts
@@ -0,0 +1,20 @@
+import type { IDeploymentConfig } from '../config/domain/model/deploymentConfig';
+import { AppEnvironment } from '../config/domain/model/appEnvironment';
+import { frontendConfig } from './config/frontendConfig';
+import { sharedConfig } from './config/sharedConfig';
+
+export const iacConfig: IDeploymentConfig = {
+ repoName: 'envilder',
+ branch: 'main',
+ vpcId: 'vpc-ee04cd97',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'envilder.io',
+ certificateId: 'be63062d-5316-47af-9f94-819c1dc02853',
+ hostedZoneId: 'Z0832486XTB67JEGNLMB',
+ },
+ stacks: {
+ frontend: frontendConfig,
+ shared: sharedConfig,
+ },
+};
diff --git a/src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap b/src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap
new file mode 100644
index 00000000..2413d6bf
--- /dev/null
+++ b/src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap
@@ -0,0 +1,8927 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PipelineStack Should_CreatePipelineStack_When_StackIsCalled: pipelineStackTest 1`] = `
+{
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "PipelineC660917D": {
+ "DependsOn": [
+ "RolepipelineDefaultPolicyB1AF7048",
+ "Rolepipeline86313131",
+ ],
+ "Properties": {
+ "ArtifactStore": {
+ "Location": "envilder-codepipeline-artifact",
+ "Type": "S3",
+ },
+ "Name": "envilder-test",
+ "PipelineType": "V2",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "Stages": [
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Source",
+ "Owner": "ThirdParty",
+ "Provider": "GitHub",
+ "Version": "1",
+ },
+ "Configuration": {
+ "Branch": "main",
+ "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ "Owner": "macalbert",
+ "PollForSourceChanges": false,
+ "Repo": "envilder",
+ },
+ "Name": "checkout-test-envilder",
+ "OutputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "test-pipeline-test-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "build-pipeline-deploy-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Deploy",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
+ "Properties": {
+ "Authentication": "GITHUB_HMAC",
+ "AuthenticationConfiguration": {
+ "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ },
+ "Filters": [
+ {
+ "JsonPath": "$.ref",
+ "MatchEquals": "refs/heads/{Branch}",
+ },
+ ],
+ "RegisterWithThirdParty": true,
+ "TargetAction": "checkout-test-envilder",
+ "TargetPipeline": {
+ "Ref": "PipelineC660917D",
+ },
+ "TargetPipelineVersion": 1,
+ },
+ "Type": "AWS::CodePipeline::Webhook",
+ },
+ "Roledeploy92E6FB77": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoledeployDefaultPolicy3EF570DF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "buildpipelineF72EB33D",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoledeployDefaultPolicy3EF570DF",
+ "Roles": [
+ {
+ "Ref": "Roledeploy92E6FB77",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Rolepipeline86313131": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RolepipelineDefaultPolicyB1AF7048": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
+ "Roles": [
+ {
+ "Ref": "Rolepipeline86313131",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Roletest8FE49675": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoletestDefaultPolicy62D11870": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "ec2:CreateNetworkInterfacePermission",
+ "Condition": {
+ "StringEquals": {
+ "ec2:AuthorizedService": "codebuild.amazonaws.com",
+ "ec2:Subnet": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ ],
+ },
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":network-interface/*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Testtestpipeline165C0FB1",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoletestDefaultPolicy62D11870",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Testtestpipeline165C0FB1": {
+ "DependsOn": [
+ "TesttestpipelinePolicyDocument696CEEF8",
+ ],
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "test-pipeline-test-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/test-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 15,
+ "VpcConfig": {
+ "SecurityGroupIds": [
+ {
+ "Fn::GetAtt": [
+ "TesttestpipelineSecurityGroup0D35C015",
+ "GroupId",
+ ],
+ },
+ ],
+ "Subnets": [
+ {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "TesttestpipelinePolicyDocument696CEEF8": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "ec2:CreateNetworkInterface",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DeleteNetworkInterface",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DescribeVpcs",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "TesttestpipelineSecurityGroup0D35C015": {
+ "Properties": {
+ "GroupDescription": "Automatic generated security group for CodeBuild pipelineStackTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineD4573B3B",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "buildpipelineF72EB33D": {
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "EnvironmentVariables": [
+ {
+ "Name": "SOME_KEY",
+ "Type": "PLAINTEXT",
+ "Value": "https://some-url-for-test",
+ },
+ {
+ "Name": "ASPNETCORE_ENVIRONMENT",
+ "Type": "PLAINTEXT",
+ "Value": "Test",
+ },
+ ],
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "build-pipeline-deploy-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/build-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 30,
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`PipelineStack Should_CreatePipelineWithFilteredPathsStack_When_StackIsCalled: pipelineWithFilterStackTest 1`] = `
+{
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "PipelineC660917D": {
+ "DependsOn": [
+ "RolepipelineDefaultPolicyB1AF7048",
+ "Rolepipeline86313131",
+ ],
+ "Properties": {
+ "ArtifactStore": {
+ "Location": "envilder-codepipeline-artifact",
+ "Type": "S3",
+ },
+ "Name": "envilder-production",
+ "PipelineType": "V2",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "Stages": [
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Source",
+ "Owner": "ThirdParty",
+ "Provider": "GitHub",
+ "Version": "1",
+ },
+ "Configuration": {
+ "Branch": "main",
+ "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ "Owner": "macalbert",
+ "PollForSourceChanges": false,
+ "Repo": "envilder",
+ },
+ "Name": "checkout-production-envilder",
+ "OutputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-production-envilder",
+ },
+ ],
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-production-envilder",
+ },
+ ],
+ "Name": "test-pipeline-test-envilder-production",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-production-envilder",
+ },
+ ],
+ "Name": "build-pipeline-deploy-envilder-production",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Deploy",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Production",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineSourcecheckoutproductionenvilderWebhookResource6C467C58": {
+ "Properties": {
+ "Authentication": "GITHUB_HMAC",
+ "AuthenticationConfiguration": {
+ "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ },
+ "Filters": [
+ {
+ "JsonPath": "$.ref",
+ "MatchEquals": "refs/heads/{Branch}",
+ },
+ ],
+ "RegisterWithThirdParty": true,
+ "TargetAction": "checkout-production-envilder",
+ "TargetPipeline": {
+ "Ref": "PipelineC660917D",
+ },
+ "TargetPipelineVersion": 1,
+ },
+ "Type": "AWS::CodePipeline::Webhook",
+ },
+ "Roledeploy92E6FB77": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Production)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Production",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoledeployDefaultPolicy3EF570DF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "buildpipelineF72EB33D",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoledeployDefaultPolicy3EF570DF",
+ "Roles": [
+ {
+ "Ref": "Roledeploy92E6FB77",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Rolepipeline86313131": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Production)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Production",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RolepipelineDefaultPolicyB1AF7048": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
+ "Roles": [
+ {
+ "Ref": "Rolepipeline86313131",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Roletest8FE49675": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Production)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Production",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoletestDefaultPolicy62D11870": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "ec2:CreateNetworkInterfacePermission",
+ "Condition": {
+ "StringEquals": {
+ "ec2:AuthorizedService": "codebuild.amazonaws.com",
+ "ec2:Subnet": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ ],
+ },
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":network-interface/*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Testtestpipeline165C0FB1",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoletestDefaultPolicy62D11870",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Testtestpipeline165C0FB1": {
+ "DependsOn": [
+ "TesttestpipelinePolicyDocument696CEEF8",
+ ],
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "test-pipeline-test-envilder-production",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/test-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Production",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
+ },
+ ],
+ "TimeoutInMinutes": 15,
+ "VpcConfig": {
+ "SecurityGroupIds": [
+ {
+ "Fn::GetAtt": [
+ "TesttestpipelineSecurityGroup0D35C015",
+ "GroupId",
+ ],
+ },
+ ],
+ "Subnets": [
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "TesttestpipelinePolicyDocument696CEEF8": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "ec2:CreateNetworkInterface",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DeleteNetworkInterface",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DescribeVpcs",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "TesttestpipelineSecurityGroup0D35C015": {
+ "Properties": {
+ "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithFilterStackTestmacalbertenvilderfrontendpipelinestackproductionstackTesttestpipelineE854AA65",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Production",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "buildpipelineF72EB33D": {
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "EnvironmentVariables": [
+ {
+ "Name": "SOME_KEY",
+ "Type": "PLAINTEXT",
+ "Value": "https://some-url-for-test",
+ },
+ {
+ "Name": "ASPNETCORE_ENVIRONMENT",
+ "Type": "PLAINTEXT",
+ "Value": "Production",
+ },
+ ],
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "build-pipeline-deploy-envilder-production",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/build-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Production",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
+ },
+ ],
+ "TimeoutInMinutes": 30,
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`PipelineStack Should_CreatePipelineWithLocalCache_When_CacheConfigIsLocal: pipelineWithLocalCache 1`] = `
+{
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "PipelineC660917D": {
+ "DependsOn": [
+ "RolepipelineDefaultPolicyB1AF7048",
+ "Rolepipeline86313131",
+ ],
+ "Properties": {
+ "ArtifactStore": {
+ "Location": "envilder-codepipeline-artifact",
+ "Type": "S3",
+ },
+ "Name": "envilder-test",
+ "PipelineType": "V2",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "Stages": [
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Source",
+ "Owner": "ThirdParty",
+ "Provider": "GitHub",
+ "Version": "1",
+ },
+ "Configuration": {
+ "Branch": "main",
+ "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ "Owner": "macalbert",
+ "PollForSourceChanges": false,
+ "Repo": "envilder",
+ },
+ "Name": "checkout-test-envilder",
+ "OutputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "test-pipeline-test-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "build-pipeline-deploy-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Deploy",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
+ "Properties": {
+ "Authentication": "GITHUB_HMAC",
+ "AuthenticationConfiguration": {
+ "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ },
+ "Filters": [
+ {
+ "JsonPath": "$.ref",
+ "MatchEquals": "refs/heads/{Branch}",
+ },
+ ],
+ "RegisterWithThirdParty": true,
+ "TargetAction": "checkout-test-envilder",
+ "TargetPipeline": {
+ "Ref": "PipelineC660917D",
+ },
+ "TargetPipelineVersion": 1,
+ },
+ "Type": "AWS::CodePipeline::Webhook",
+ },
+ "Roledeploy92E6FB77": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoledeployDefaultPolicy3EF570DF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "buildpipelineF72EB33D",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoledeployDefaultPolicy3EF570DF",
+ "Roles": [
+ {
+ "Ref": "Roledeploy92E6FB77",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Rolepipeline86313131": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RolepipelineDefaultPolicyB1AF7048": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
+ "Roles": [
+ {
+ "Ref": "Rolepipeline86313131",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Roletest8FE49675": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoletestDefaultPolicy62D11870": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "ec2:CreateNetworkInterfacePermission",
+ "Condition": {
+ "StringEquals": {
+ "ec2:AuthorizedService": "codebuild.amazonaws.com",
+ "ec2:Subnet": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ ],
+ },
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":network-interface/*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Testtestpipeline165C0FB1",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoletestDefaultPolicy62D11870",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Testtestpipeline165C0FB1": {
+ "DependsOn": [
+ "TesttestpipelinePolicyDocument696CEEF8",
+ ],
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Modes": [
+ "LOCAL_DOCKER_LAYER_CACHE",
+ "LOCAL_CUSTOM_CACHE",
+ ],
+ "Type": "LOCAL",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "test-pipeline-test-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/test-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 15,
+ "VpcConfig": {
+ "SecurityGroupIds": [
+ {
+ "Fn::GetAtt": [
+ "TesttestpipelineSecurityGroup0D35C015",
+ "GroupId",
+ ],
+ },
+ ],
+ "Subnets": [
+ {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "TesttestpipelinePolicyDocument696CEEF8": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "ec2:CreateNetworkInterface",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DeleteNetworkInterface",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DescribeVpcs",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "TesttestpipelineSecurityGroup0D35C015": {
+ "Properties": {
+ "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithLocalCacheTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineAA84A210",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "buildpipelineF72EB33D": {
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Modes": [
+ "LOCAL_DOCKER_LAYER_CACHE",
+ "LOCAL_CUSTOM_CACHE",
+ ],
+ "Type": "LOCAL",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "EnvironmentVariables": [
+ {
+ "Name": "SOME_KEY",
+ "Type": "PLAINTEXT",
+ "Value": "https://some-url-for-test",
+ },
+ {
+ "Name": "ASPNETCORE_ENVIRONMENT",
+ "Type": "PLAINTEXT",
+ "Value": "Test",
+ },
+ ],
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "build-pipeline-deploy-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/build-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 30,
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`PipelineStack Should_CreatePipelineWithManualApproval_When_StackIsCalled: pipelineWithManualApproval 1`] = `
+{
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "PipelineC660917D": {
+ "DependsOn": [
+ "RolepipelineDefaultPolicyB1AF7048",
+ "Rolepipeline86313131",
+ ],
+ "Properties": {
+ "ArtifactStore": {
+ "Location": "envilder-codepipeline-artifact",
+ "Type": "S3",
+ },
+ "Name": "envilder-test",
+ "PipelineType": "V2",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "Stages": [
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Source",
+ "Owner": "ThirdParty",
+ "Provider": "GitHub",
+ "Version": "1",
+ },
+ "Configuration": {
+ "Branch": "main",
+ "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ "Owner": "macalbert",
+ "PollForSourceChanges": false,
+ "Repo": "envilder",
+ },
+ "Name": "checkout-test-envilder",
+ "OutputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Approval",
+ "Owner": "AWS",
+ "Provider": "Manual",
+ "Version": "1",
+ },
+ "Name": "envilder-manualapproval-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "envilder-manualapproval-test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "test-pipeline-test-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "build-pipeline-deploy-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Deploy",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
+ "Properties": {
+ "Authentication": "GITHUB_HMAC",
+ "AuthenticationConfiguration": {
+ "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ },
+ "Filters": [
+ {
+ "JsonPath": "$.ref",
+ "MatchEquals": "refs/heads/{Branch}",
+ },
+ ],
+ "RegisterWithThirdParty": true,
+ "TargetAction": "checkout-test-envilder",
+ "TargetPipeline": {
+ "Ref": "PipelineC660917D",
+ },
+ "TargetPipelineVersion": 1,
+ },
+ "Type": "AWS::CodePipeline::Webhook",
+ },
+ "PipelineenvilderNotifyManualApprovalTest09846155": {
+ "Properties": {
+ "DetailType": "BASIC",
+ "EventTypeIds": [
+ "codepipeline-pipeline-manual-approval-failed",
+ "codepipeline-pipeline-manual-approval-needed",
+ "codepipeline-pipeline-manual-approval-succeeded",
+ ],
+ "Name": "envilder (test) - approval required (email)",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codepipeline:eu-west-1:account:",
+ {
+ "Ref": "PipelineC660917D",
+ },
+ ],
+ ],
+ },
+ "Tags": {
+ "Environment": "Test",
+ "Project": "envilder",
+ "StackId": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ "Targets": [
+ {
+ "TargetAddress": {
+ "Ref": "envilderManualApprovealEmailTest98B36C0F",
+ },
+ "TargetType": "SNS",
+ },
+ ],
+ },
+ "Type": "AWS::CodeStarNotifications::NotificationRule",
+ },
+ "Roledeploy92E6FB77": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoledeployDefaultPolicy3EF570DF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "buildpipelineF72EB33D",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoledeployDefaultPolicy3EF570DF",
+ "Roles": [
+ {
+ "Ref": "Roledeploy92E6FB77",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Rolepipeline86313131": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RolepipelineDefaultPolicyB1AF7048": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
+ "Roles": [
+ {
+ "Ref": "Rolepipeline86313131",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Roletest8FE49675": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoletestDefaultPolicy62D11870": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "ec2:CreateNetworkInterfacePermission",
+ "Condition": {
+ "StringEquals": {
+ "ec2:AuthorizedService": "codebuild.amazonaws.com",
+ "ec2:Subnet": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ ],
+ },
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":network-interface/*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Testtestpipeline165C0FB1",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoletestDefaultPolicy62D11870",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Testtestpipeline165C0FB1": {
+ "DependsOn": [
+ "TesttestpipelinePolicyDocument696CEEF8",
+ ],
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "test-pipeline-test-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/test-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 15,
+ "VpcConfig": {
+ "SecurityGroupIds": [
+ {
+ "Fn::GetAtt": [
+ "TesttestpipelineSecurityGroup0D35C015",
+ "GroupId",
+ ],
+ },
+ ],
+ "Subnets": [
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "TesttestpipelinePolicyDocument696CEEF8": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "ec2:CreateNetworkInterface",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DeleteNetworkInterface",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DescribeVpcs",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "TesttestpipelineSecurityGroup0D35C015": {
+ "Properties": {
+ "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithFilterStackTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineE937333C",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "buildpipelineF72EB33D": {
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "EnvironmentVariables": [
+ {
+ "Name": "SOME_KEY",
+ "Type": "PLAINTEXT",
+ "Value": "https://some-url-for-test",
+ },
+ {
+ "Name": "ASPNETCORE_ENVIRONMENT",
+ "Type": "PLAINTEXT",
+ "Value": "Test",
+ },
+ ],
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "build-pipeline-deploy-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/build-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 30,
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "envilderManualApprovealEmailTest98B36C0F": {
+ "Properties": {
+ "DisplayName": "⚠️ envilder [TEST] - Manual Approval Required",
+ "KmsMasterKeyId": {
+ "Fn::GetAtt": [
+ "keyenvildermanualapprovealemailtest45B438A1",
+ "Arn",
+ ],
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::SNS::Topic",
+ },
+ "envilderManualApprovealEmailTestPolicyEFE2DD3F": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sns:Publish",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "codestar-notifications.amazonaws.com",
+ },
+ "Resource": {
+ "Ref": "envilderManualApprovealEmailTest98B36C0F",
+ },
+ "Sid": "0",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Topics": [
+ {
+ "Ref": "envilderManualApprovealEmailTest98B36C0F",
+ },
+ ],
+ },
+ "Type": "AWS::SNS::TopicPolicy",
+ },
+ "envilderManualApprovealEmailTestmacalbertgmailcom7F647CD9": {
+ "Properties": {
+ "Endpoint": "mac.albert@gmail.com",
+ "Protocol": "email",
+ "TopicArn": {
+ "Ref": "envilderManualApprovealEmailTest98B36C0F",
+ },
+ },
+ "Type": "AWS::SNS::Subscription",
+ },
+ "keyenvildermanualapprovealemailtest45B438A1": {
+ "DeletionPolicy": "Retain",
+ "Properties": {
+ "KeyPolicy": {
+ "Statement": [
+ {
+ "Action": "kms:*",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::account:root",
+ ],
+ ],
+ },
+ },
+ "Resource": "*",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:GenerateDataKey*",
+ ],
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "codestar-notifications.amazonaws.com",
+ },
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::KMS::Key",
+ "UpdateReplacePolicy": "Retain",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`PipelineStack Should_CreatePipelineWithNoCache_When_CacheConfigIsUndefined: pipelineWithUndefinedCache 1`] = `
+{
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "PipelineC660917D": {
+ "DependsOn": [
+ "RolepipelineDefaultPolicyB1AF7048",
+ "Rolepipeline86313131",
+ ],
+ "Properties": {
+ "ArtifactStore": {
+ "Location": "envilder-codepipeline-artifact",
+ "Type": "S3",
+ },
+ "Name": "envilder-test",
+ "PipelineType": "V2",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "Stages": [
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Source",
+ "Owner": "ThirdParty",
+ "Provider": "GitHub",
+ "Version": "1",
+ },
+ "Configuration": {
+ "Branch": "main",
+ "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ "Owner": "macalbert",
+ "PollForSourceChanges": false,
+ "Repo": "envilder",
+ },
+ "Name": "checkout-test-envilder",
+ "OutputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "test-pipeline-test-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "build-pipeline-deploy-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Deploy",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
+ "Properties": {
+ "Authentication": "GITHUB_HMAC",
+ "AuthenticationConfiguration": {
+ "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ },
+ "Filters": [
+ {
+ "JsonPath": "$.ref",
+ "MatchEquals": "refs/heads/{Branch}",
+ },
+ ],
+ "RegisterWithThirdParty": true,
+ "TargetAction": "checkout-test-envilder",
+ "TargetPipeline": {
+ "Ref": "PipelineC660917D",
+ },
+ "TargetPipelineVersion": 1,
+ },
+ "Type": "AWS::CodePipeline::Webhook",
+ },
+ "Roledeploy92E6FB77": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoledeployDefaultPolicy3EF570DF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "buildpipelineF72EB33D",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoledeployDefaultPolicy3EF570DF",
+ "Roles": [
+ {
+ "Ref": "Roledeploy92E6FB77",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Rolepipeline86313131": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RolepipelineDefaultPolicyB1AF7048": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
+ "Roles": [
+ {
+ "Ref": "Rolepipeline86313131",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Roletest8FE49675": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoletestDefaultPolicy62D11870": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "ec2:CreateNetworkInterfacePermission",
+ "Condition": {
+ "StringEquals": {
+ "ec2:AuthorizedService": "codebuild.amazonaws.com",
+ "ec2:Subnet": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ ],
+ },
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":network-interface/*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Testtestpipeline165C0FB1",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoletestDefaultPolicy62D11870",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Testtestpipeline165C0FB1": {
+ "DependsOn": [
+ "TesttestpipelinePolicyDocument696CEEF8",
+ ],
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "test-pipeline-test-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/test-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 15,
+ "VpcConfig": {
+ "SecurityGroupIds": [
+ {
+ "Fn::GetAtt": [
+ "TesttestpipelineSecurityGroup0D35C015",
+ "GroupId",
+ ],
+ },
+ ],
+ "Subnets": [
+ {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "TesttestpipelinePolicyDocument696CEEF8": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "ec2:CreateNetworkInterface",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DeleteNetworkInterface",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DescribeVpcs",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "TesttestpipelineSecurityGroup0D35C015": {
+ "Properties": {
+ "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithUndefinedCacheTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipeline4900349B",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "buildpipelineF72EB33D": {
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Type": "NO_CACHE",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "EnvironmentVariables": [
+ {
+ "Name": "SOME_KEY",
+ "Type": "PLAINTEXT",
+ "Value": "https://some-url-for-test",
+ },
+ {
+ "Name": "ASPNETCORE_ENVIRONMENT",
+ "Type": "PLAINTEXT",
+ "Value": "Test",
+ },
+ ],
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "build-pipeline-deploy-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/build-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 30,
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`PipelineStack Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithCustomBucket: pipelineWithS3CacheCustom 1`] = `
+{
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "PipelineC660917D": {
+ "DependsOn": [
+ "RolepipelineDefaultPolicyB1AF7048",
+ "Rolepipeline86313131",
+ ],
+ "Properties": {
+ "ArtifactStore": {
+ "Location": "envilder-codepipeline-artifact",
+ "Type": "S3",
+ },
+ "Name": "envilder-test",
+ "PipelineType": "V2",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "Stages": [
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Source",
+ "Owner": "ThirdParty",
+ "Provider": "GitHub",
+ "Version": "1",
+ },
+ "Configuration": {
+ "Branch": "main",
+ "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ "Owner": "macalbert",
+ "PollForSourceChanges": false,
+ "Repo": "envilder",
+ },
+ "Name": "checkout-test-envilder",
+ "OutputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "test-pipeline-test-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "build-pipeline-deploy-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Deploy",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
+ "Properties": {
+ "Authentication": "GITHUB_HMAC",
+ "AuthenticationConfiguration": {
+ "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ },
+ "Filters": [
+ {
+ "JsonPath": "$.ref",
+ "MatchEquals": "refs/heads/{Branch}",
+ },
+ ],
+ "RegisterWithThirdParty": true,
+ "TargetAction": "checkout-test-envilder",
+ "TargetPipeline": {
+ "Ref": "PipelineC660917D",
+ },
+ "TargetPipelineVersion": 1,
+ },
+ "Type": "AWS::CodePipeline::Webhook",
+ },
+ "Roledeploy92E6FB77": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoledeployDefaultPolicy3EF570DF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::my-custom-cache-bucket",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::my-custom-cache-bucket/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "buildpipelineF72EB33D",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoledeployDefaultPolicy3EF570DF",
+ "Roles": [
+ {
+ "Ref": "Roledeploy92E6FB77",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Rolepipeline86313131": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RolepipelineDefaultPolicyB1AF7048": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
+ "Roles": [
+ {
+ "Ref": "Rolepipeline86313131",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Roletest8FE49675": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoletestDefaultPolicy62D11870": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::my-custom-cache-bucket",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::my-custom-cache-bucket/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "ec2:CreateNetworkInterfacePermission",
+ "Condition": {
+ "StringEquals": {
+ "ec2:AuthorizedService": "codebuild.amazonaws.com",
+ "ec2:Subnet": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ ],
+ },
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":network-interface/*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Testtestpipeline165C0FB1",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoletestDefaultPolicy62D11870",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Testtestpipeline165C0FB1": {
+ "DependsOn": [
+ "TesttestpipelinePolicyDocument696CEEF8",
+ ],
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Location": "my-custom-cache-bucket/envilder",
+ "Type": "S3",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "test-pipeline-test-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/test-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 15,
+ "VpcConfig": {
+ "SecurityGroupIds": [
+ {
+ "Fn::GetAtt": [
+ "TesttestpipelineSecurityGroup0D35C015",
+ "GroupId",
+ ],
+ },
+ ],
+ "Subnets": [
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "TesttestpipelinePolicyDocument696CEEF8": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "ec2:CreateNetworkInterface",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DeleteNetworkInterface",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DescribeVpcs",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "TesttestpipelineSecurityGroup0D35C015": {
+ "Properties": {
+ "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithS3CacheCustomTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineEDADE20A",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "buildpipelineF72EB33D": {
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Location": "my-custom-cache-bucket/envilder",
+ "Type": "S3",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "EnvironmentVariables": [
+ {
+ "Name": "SOME_KEY",
+ "Type": "PLAINTEXT",
+ "Value": "https://some-url-for-test",
+ },
+ {
+ "Name": "ASPNETCORE_ENVIRONMENT",
+ "Type": "PLAINTEXT",
+ "Value": "Test",
+ },
+ ],
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "build-pipeline-deploy-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/build-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 30,
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`PipelineStack Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithDefaultBucket: pipelineWithS3CacheDefault 1`] = `
+{
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "PipelineC660917D": {
+ "DependsOn": [
+ "RolepipelineDefaultPolicyB1AF7048",
+ "Rolepipeline86313131",
+ ],
+ "Properties": {
+ "ArtifactStore": {
+ "Location": "envilder-codepipeline-artifact",
+ "Type": "S3",
+ },
+ "Name": "envilder-test",
+ "PipelineType": "V2",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ "Stages": [
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Source",
+ "Owner": "ThirdParty",
+ "Provider": "GitHub",
+ "Version": "1",
+ },
+ "Configuration": {
+ "Branch": "main",
+ "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ "Owner": "macalbert",
+ "PollForSourceChanges": false,
+ "Repo": "envilder",
+ },
+ "Name": "checkout-test-envilder",
+ "OutputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Source",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "test-pipeline-test-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Test",
+ },
+ {
+ "Actions": [
+ {
+ "ActionTypeId": {
+ "Category": "Build",
+ "Owner": "AWS",
+ "Provider": "CodeBuild",
+ "Version": "1",
+ },
+ "Configuration": {
+ "ProjectName": {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ },
+ "InputArtifacts": [
+ {
+ "Name": "Artifact_Source_checkout-test-envilder",
+ },
+ ],
+ "Name": "build-pipeline-deploy-envilder-test",
+ "RoleArn": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "RunOrder": 1,
+ },
+ ],
+ "Name": "Deploy",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CodePipeline::Pipeline",
+ },
+ "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
+ "Properties": {
+ "Authentication": "GITHUB_HMAC",
+ "AuthenticationConfiguration": {
+ "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
+ },
+ "Filters": [
+ {
+ "JsonPath": "$.ref",
+ "MatchEquals": "refs/heads/{Branch}",
+ },
+ ],
+ "RegisterWithThirdParty": true,
+ "TargetAction": "checkout-test-envilder",
+ "TargetPipeline": {
+ "Ref": "PipelineC660917D",
+ },
+ "TargetPipelineVersion": 1,
+ },
+ "Type": "AWS::CodePipeline::Webhook",
+ },
+ "Roledeploy92E6FB77": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoledeployDefaultPolicy3EF570DF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::codebuild-eu-west-1-account",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::codebuild-eu-west-1-account/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "buildpipelineF72EB33D",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "buildpipelineF72EB33D",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoledeployDefaultPolicy3EF570DF",
+ "Roles": [
+ {
+ "Ref": "Roledeploy92E6FB77",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Rolepipeline86313131": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RolepipelineDefaultPolicyB1AF7048": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
+ "Roles": [
+ {
+ "Ref": "Rolepipeline86313131",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Roletest8FE49675": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": [
+ "lambda.amazonaws.com",
+ "codepipeline.amazonaws.com",
+ "codebuild.amazonaws.com",
+ ],
+ },
+ },
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "Rolepipeline86313131",
+ "Arn",
+ ],
+ },
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "Description": "Role for CD pipeline in repo envilder (Test)",
+ "Policies": [
+ {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::account:role/*",
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
+ },
+ {
+ "Action": [
+ "codebuild:BatchPutCodeCoverages",
+ "codebuild:BatchPutTestCases",
+ "codebuild:CreateReport",
+ "codebuild:CreateReportGroup",
+ "codebuild:UpdateReport",
+ "codebuild:StartBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
+ },
+ {
+ "Action": [
+ "s3:GetBucket*",
+ "s3:GetObject*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:s3:::*",
+ },
+ {
+ "Action": [
+ "secretsmanager:GetResourcePolicy",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:ListSecretVersionIds",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ {
+ "Action": "ses:SendEmail",
+ "Effect": "Allow",
+ "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
+ },
+ {
+ "Action": [
+ "kms:Decrypt",
+ "kms:DescribeKey",
+ "kms:Encrypt",
+ "kms:GenerateDataKey*",
+ "kms:ReEncrypt*",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:kms:eu-west-1:account:*",
+ },
+ {
+ "Action": "sqs:*",
+ "Effect": "Allow",
+ "Resource": "arn:aws:sqs:eu-west-1:account:*",
+ },
+ {
+ "Action": [
+ "ssm:GetParameter",
+ "ssm:GetParameters",
+ "ssm:GetParametersByPath",
+ ],
+ "Effect": "Allow",
+ "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "customApiPolicyDocument",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "RoletestDefaultPolicy62D11870": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::codebuild-eu-west-1-account",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::codebuild-eu-west-1-account/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "ec2:CreateNetworkInterfacePermission",
+ "Condition": {
+ "StringEquals": {
+ "ec2:AuthorizedService": "codebuild.amazonaws.com",
+ "ec2:Subnet": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":subnet/",
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ ],
+ },
+ ],
+ },
+ },
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":ec2:",
+ {
+ "Ref": "AWS::Region",
+ },
+ ":",
+ {
+ "Ref": "AWS::AccountId",
+ },
+ ":network-interface/*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":logs:eu-west-1:account:log-group:/aws/codebuild/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ ":*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "codebuild:CreateReportGroup",
+ "codebuild:CreateReport",
+ "codebuild:UpdateReport",
+ "codebuild:BatchPutTestCases",
+ "codebuild:BatchPutCodeCoverages",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":codebuild:eu-west-1:account:report-group/",
+ {
+ "Ref": "Testtestpipeline165C0FB1",
+ },
+ "-*",
+ ],
+ ],
+ },
+ },
+ {
+ "Action": [
+ "codebuild:BatchGetBuilds",
+ "codebuild:StartBuild",
+ "codebuild:StopBuild",
+ ],
+ "Effect": "Allow",
+ "Resource": {
+ "Fn::GetAtt": [
+ "Testtestpipeline165C0FB1",
+ "Arn",
+ ],
+ },
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::envilder-codepipeline-artifact/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "RoletestDefaultPolicy62D11870",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "Testtestpipeline165C0FB1": {
+ "DependsOn": [
+ "TesttestpipelinePolicyDocument696CEEF8",
+ ],
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Location": "codebuild-eu-west-1-account/envilder",
+ "Type": "S3",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "test-pipeline-test-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roletest8FE49675",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/test-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 15,
+ "VpcConfig": {
+ "SecurityGroupIds": [
+ {
+ "Fn::GetAtt": [
+ "TesttestpipelineSecurityGroup0D35C015",
+ "GroupId",
+ ],
+ },
+ ],
+ "Subnets": [
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
+ },
+ {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ "TesttestpipelinePolicyDocument696CEEF8": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "ec2:CreateNetworkInterface",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DeleteNetworkInterface",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DescribeVpcs",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
+ "Roles": [
+ {
+ "Ref": "Roletest8FE49675",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "TesttestpipelineSecurityGroup0D35C015": {
+ "Properties": {
+ "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithS3CacheDefaultTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineC3A57052",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcA2121C384D1B3CDE",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "buildpipelineF72EB33D": {
+ "Properties": {
+ "Artifacts": {
+ "Type": "CODEPIPELINE",
+ },
+ "Cache": {
+ "Location": "codebuild-eu-west-1-account/envilder",
+ "Type": "S3",
+ },
+ "EncryptionKey": "alias/aws/s3",
+ "Environment": {
+ "ComputeType": "BUILD_GENERAL1_SMALL",
+ "EnvironmentVariables": [
+ {
+ "Name": "SOME_KEY",
+ "Type": "PLAINTEXT",
+ "Value": "https://some-url-for-test",
+ },
+ {
+ "Name": "ASPNETCORE_ENVIRONMENT",
+ "Type": "PLAINTEXT",
+ "Value": "Test",
+ },
+ ],
+ "Image": "aws/codebuild/standard:7.0",
+ "ImagePullCredentialsType": "CODEBUILD",
+ "PrivilegedMode": true,
+ "Type": "LINUX_CONTAINER",
+ },
+ "Name": "build-pipeline-deploy-envilder-test",
+ "ServiceRole": {
+ "Fn::GetAtt": [
+ "Roledeploy92E6FB77",
+ "Arn",
+ ],
+ },
+ "Source": {
+ "BuildSpec": "path/build-pipeline.yml",
+ "Type": "CODEPIPELINE",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "envilder",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
+ },
+ ],
+ "TimeoutInMinutes": 30,
+ },
+ "Type": "AWS::CodeBuild::Project",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
diff --git a/src/iac/test/aws/developerTools/pipelineStack.test.ts b/src/iac/test/aws/developerTools/pipelineStack.test.ts
new file mode 100644
index 00000000..044df66a
--- /dev/null
+++ b/src/iac/test/aws/developerTools/pipelineStack.test.ts
@@ -0,0 +1,181 @@
+import { App, RemovalPolicy, Stack } from 'aws-cdk-lib';
+import { Template } from 'aws-cdk-lib/assertions';
+import { Vpc } from 'aws-cdk-lib/aws-ec2';
+import {
+ PipelineStack,
+ type PipelineStackProps,
+} from '../../../src/aws/developerTools/codepipeline/pipelineStack';
+import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+
+describe('PipelineStack', () => {
+ const env = {
+ account: 'account',
+ region: 'eu-west-1',
+ };
+
+ test('Should_CreatePipelineStack_When_StackIsCalled', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'pipelineStackTest', { env });
+ const props = createPipelineStackProps(stack);
+
+ // Act
+ const actual = new PipelineStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual);
+ expect(template.toJSON()).toMatchSnapshot('pipelineStackTest');
+ });
+
+ test('Should_CreatePipelineWithFilteredPathsStack_When_StackIsCalled', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'pipelineWithFilterStackTest', {
+ env,
+ });
+ const props = createPipelineStackProps(stack);
+ props.filterPaths = ['some/path'];
+ props.envName = AppEnvironment.Production;
+
+ // Act
+ const actual = new PipelineStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual);
+ expect(template.toJSON()).toMatchSnapshot('pipelineWithFilterStackTest');
+ });
+
+ test('Should_CreatePipelineWithManualApproval_When_StackIsCalled', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'pipelineWithFilterStackTest', {
+ env,
+ });
+ const props = createPipelineStackProps(stack);
+ props.manualApproval = true;
+
+ // Act
+ const actual = new PipelineStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual);
+ expect(template.toJSON()).toMatchSnapshot('pipelineWithManualApproval');
+ });
+
+ test('Should_CreatePipelineWithNoCache_When_CacheConfigIsUndefined', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'pipelineWithUndefinedCacheTest', {
+ env,
+ });
+ const props = createPipelineStackProps(stack);
+ // cacheConfig is undefined by default
+
+ // Act
+ const actual = new PipelineStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual);
+ expect(template.toJSON()).toMatchSnapshot('pipelineWithUndefinedCache');
+
+ // Verify deploy project has no cache configured (default behavior)
+ template.hasResourceProperties('AWS::CodeBuild::Project', {
+ Name: 'build-pipeline-deploy-envilder-test',
+ Cache: {
+ Type: 'NO_CACHE',
+ },
+ });
+ });
+
+ test('Should_CreatePipelineWithLocalCache_When_CacheConfigIsLocal', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'pipelineWithLocalCacheTest', { env });
+ const props = createPipelineStackProps(stack);
+ props.cacheConfig = { type: 'local' };
+
+ // Act
+ const actual = new PipelineStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual);
+ expect(template.toJSON()).toMatchSnapshot('pipelineWithLocalCache');
+
+ // Verify deploy project has local cache configured with Docker layer and custom modes
+ template.hasResourceProperties('AWS::CodeBuild::Project', {
+ Name: 'build-pipeline-deploy-envilder-test',
+ Cache: {
+ Type: 'LOCAL',
+ Modes: ['LOCAL_DOCKER_LAYER_CACHE', 'LOCAL_CUSTOM_CACHE'],
+ },
+ });
+ });
+
+ test('Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithDefaultBucket', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'pipelineWithS3CacheDefaultTest', {
+ env,
+ });
+ const props = createPipelineStackProps(stack);
+ props.cacheConfig = { type: 's3' };
+
+ // Act
+ const actual = new PipelineStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual);
+ expect(template.toJSON()).toMatchSnapshot('pipelineWithS3CacheDefault');
+
+ // Verify deploy project has S3 cache configured with default bucket
+ template.hasResourceProperties('AWS::CodeBuild::Project', {
+ Name: 'build-pipeline-deploy-envilder-test',
+ Cache: {
+ Type: 'S3',
+ Location: 'codebuild-eu-west-1-account/envilder',
+ },
+ });
+ });
+
+ test('Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithCustomBucket', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'pipelineWithS3CacheCustomTest', {
+ env,
+ });
+ const props = createPipelineStackProps(stack);
+ props.cacheConfig = { type: 's3', bucketName: 'my-custom-cache-bucket' };
+
+ // Act
+ const actual = new PipelineStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual);
+ expect(template.toJSON()).toMatchSnapshot('pipelineWithS3CacheCustom');
+
+ // Verify deploy project has S3 cache configured with custom bucket
+ template.hasResourceProperties('AWS::CodeBuild::Project', {
+ Name: 'build-pipeline-deploy-envilder-test',
+ Cache: {
+ Type: 'S3',
+ Location: 'my-custom-cache-bucket/envilder',
+ },
+ });
+ });
+
+ function createPipelineStackProps(app: Stack): PipelineStackProps {
+ return {
+ name: 'FrontendPipelineStack',
+ branch: 'main',
+ githubRepo: 'envilder',
+ envName: AppEnvironment.Test,
+ secretTokenArn: `arn:aws:secretsmanager:${env.region}:${env.account}:secret:github-token`,
+ deployBuildSpec: [`path/build-pipeline.yml`],
+ testBuildSpec: [`path/test-pipeline.yml`],
+ testProjectName: 'project-test',
+ vpc: new Vpc(app, 'vpc'),
+ env,
+ environment: {
+ SOME_KEY: {
+ value: 'https://some-url-for-test',
+ },
+ },
+ bucketRemovalPolicy: RemovalPolicy.DESTROY,
+ domain: 'envilder-test',
+ stackName: 'pipeline-stack',
+ };
+ }
+});
diff --git a/src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap b/src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap
new file mode 100644
index 00000000..d46e0f67
--- /dev/null
+++ b/src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap
@@ -0,0 +1,612 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`VpcStackTest Should_MatchSnapshotAndResources_When_VpcStackIsCreated: VpcStackTest 1`] = `
+{
+ "Outputs": {
+ "cfnOutputVpcId": {
+ "Description": "Created VPC ID",
+ "Export": {
+ "Name": "VpcStack:vpcId",
+ },
+ "Value": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ },
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "vpcId937700B3": {
+ "Properties": {
+ "CidrBlock": "22.0.0.0/16",
+ "EnableDnsHostnames": true,
+ "EnableDnsSupport": true,
+ "InstanceTenancy": "default",
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "private-CustomVpc-Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::VPC",
+ },
+ "vpcIdIGW108455B5": {
+ "Properties": {
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "private-CustomVpc-Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::InternetGateway",
+ },
+ "vpcIdPrivate1Subnet1DefaultRoute9D408128": {
+ "Properties": {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "NatGatewayId": {
+ "Ref": "vpcIdPublic1Subnet1NATGateway5EB16AC0",
+ },
+ "RouteTableId": {
+ "Ref": "vpcIdPrivate1Subnet1RouteTable42D8C801",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "vpcIdPrivate1Subnet1RouteTable42D8C801": {
+ "Properties": {
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet1",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "vpcIdPrivate1Subnet1RouteTableAssociation675EA1FB": {
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "vpcIdPrivate1Subnet1RouteTable42D8C801",
+ },
+ "SubnetId": {
+ "Ref": "vpcIdPrivate1Subnet1SubnetACE5346C",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "vpcIdPrivate1Subnet1SubnetACE5346C": {
+ "Properties": {
+ "AvailabilityZone": {
+ "Fn::Select": [
+ 0,
+ {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "22.0.32.0/20",
+ "MapPublicIpOnLaunch": false,
+ "Tags": [
+ {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Private1",
+ },
+ {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Private",
+ },
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet1",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "vpcIdPrivate1Subnet2DefaultRoute8F3C7EA8": {
+ "Properties": {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "NatGatewayId": {
+ "Ref": "vpcIdPublic1Subnet2NATGateway6CB106F1",
+ },
+ "RouteTableId": {
+ "Ref": "vpcIdPrivate1Subnet2RouteTable83AB5D28",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "vpcIdPrivate1Subnet2RouteTable83AB5D28": {
+ "Properties": {
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet2",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "vpcIdPrivate1Subnet2RouteTableAssociation08CCB002": {
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "vpcIdPrivate1Subnet2RouteTable83AB5D28",
+ },
+ "SubnetId": {
+ "Ref": "vpcIdPrivate1Subnet2Subnet91487ED7",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "vpcIdPrivate1Subnet2Subnet91487ED7": {
+ "Properties": {
+ "AvailabilityZone": {
+ "Fn::Select": [
+ 1,
+ {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "22.0.48.0/20",
+ "MapPublicIpOnLaunch": false,
+ "Tags": [
+ {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Private1",
+ },
+ {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Private",
+ },
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet2",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "vpcIdPublic1Subnet1DefaultRoute72228A8F": {
+ "DependsOn": [
+ "vpcIdVPCGW33ACD385",
+ ],
+ "Properties": {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "GatewayId": {
+ "Ref": "vpcIdIGW108455B5",
+ },
+ "RouteTableId": {
+ "Ref": "vpcIdPublic1Subnet1RouteTable31C18ABF",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "vpcIdPublic1Subnet1EIPDC296CEC": {
+ "Properties": {
+ "Domain": "vpc",
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::EIP",
+ },
+ "vpcIdPublic1Subnet1NATGateway5EB16AC0": {
+ "DependsOn": [
+ "vpcIdPublic1Subnet1DefaultRoute72228A8F",
+ "vpcIdPublic1Subnet1RouteTableAssociation055876F9",
+ ],
+ "Properties": {
+ "AllocationId": {
+ "Fn::GetAtt": [
+ "vpcIdPublic1Subnet1EIPDC296CEC",
+ "AllocationId",
+ ],
+ },
+ "SubnetId": {
+ "Ref": "vpcIdPublic1Subnet1SubnetD21C4A28",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::NatGateway",
+ },
+ "vpcIdPublic1Subnet1RouteTable31C18ABF": {
+ "Properties": {
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "vpcIdPublic1Subnet1RouteTableAssociation055876F9": {
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "vpcIdPublic1Subnet1RouteTable31C18ABF",
+ },
+ "SubnetId": {
+ "Ref": "vpcIdPublic1Subnet1SubnetD21C4A28",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "vpcIdPublic1Subnet1SubnetD21C4A28": {
+ "Properties": {
+ "AvailabilityZone": {
+ "Fn::Select": [
+ 0,
+ {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "22.0.0.0/20",
+ "MapPublicIpOnLaunch": true,
+ "Tags": [
+ {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Public1",
+ },
+ {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Public",
+ },
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "vpcIdPublic1Subnet2DefaultRouteE84FDE21": {
+ "DependsOn": [
+ "vpcIdVPCGW33ACD385",
+ ],
+ "Properties": {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "GatewayId": {
+ "Ref": "vpcIdIGW108455B5",
+ },
+ "RouteTableId": {
+ "Ref": "vpcIdPublic1Subnet2RouteTable6FCD1F9B",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "vpcIdPublic1Subnet2EIP15C5A5DD": {
+ "Properties": {
+ "Domain": "vpc",
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::EIP",
+ },
+ "vpcIdPublic1Subnet2NATGateway6CB106F1": {
+ "DependsOn": [
+ "vpcIdPublic1Subnet2DefaultRouteE84FDE21",
+ "vpcIdPublic1Subnet2RouteTableAssociation126B887D",
+ ],
+ "Properties": {
+ "AllocationId": {
+ "Fn::GetAtt": [
+ "vpcIdPublic1Subnet2EIP15C5A5DD",
+ "AllocationId",
+ ],
+ },
+ "SubnetId": {
+ "Ref": "vpcIdPublic1Subnet2SubnetA44E3D9B",
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::NatGateway",
+ },
+ "vpcIdPublic1Subnet2RouteTable6FCD1F9B": {
+ "Properties": {
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "vpcIdPublic1Subnet2RouteTableAssociation126B887D": {
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "vpcIdPublic1Subnet2RouteTable6FCD1F9B",
+ },
+ "SubnetId": {
+ "Ref": "vpcIdPublic1Subnet2SubnetA44E3D9B",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "vpcIdPublic1Subnet2SubnetA44E3D9B": {
+ "Properties": {
+ "AvailabilityZone": {
+ "Fn::Select": [
+ 1,
+ {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "22.0.16.0/20",
+ "MapPublicIpOnLaunch": true,
+ "Tags": [
+ {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Public1",
+ },
+ {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Public",
+ },
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Name",
+ "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
+ },
+ {
+ "Key": "Project",
+ "Value": "shared-test",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-shared-test-vpcstack-test-stack",
+ },
+ ],
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "vpcIdVPCGW33ACD385": {
+ "Properties": {
+ "InternetGatewayId": {
+ "Ref": "vpcIdIGW108455B5",
+ },
+ "VpcId": {
+ "Ref": "vpcId937700B3",
+ },
+ },
+ "Type": "AWS::EC2::VPCGatewayAttachment",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
diff --git a/src/iac/test/aws/network/vpcLookupStack.test.ts b/src/iac/test/aws/network/vpcLookupStack.test.ts
new file mode 100644
index 00000000..3df0de69
--- /dev/null
+++ b/src/iac/test/aws/network/vpcLookupStack.test.ts
@@ -0,0 +1,107 @@
+import { App } from 'aws-cdk-lib';
+import {
+ VpcLookupStack,
+ type VpcLookupStackProps,
+} from '../../../src/aws/network/vpcLookupStack';
+
+// Mock the Vpc.fromLookup to avoid actual AWS lookups in tests
+jest.mock('aws-cdk-lib/aws-ec2', () => {
+ const actual = jest.requireActual('aws-cdk-lib/aws-ec2');
+ return {
+ ...actual,
+ Vpc: {
+ ...actual.Vpc,
+ fromLookup: jest.fn((scope, _id, options) => ({
+ vpcId: options.vpcId,
+ node: scope.node,
+ })),
+ },
+ };
+});
+
+// Note: VPC lookup requires actual AWS VPC to exist, so we mock the lookup
+describe('VpcLookupStack', () => {
+ const env = {
+ account: '123456789012',
+ region: 'us-east-1',
+ };
+
+ function createVpcLookupStackProps(): VpcLookupStackProps {
+ return {
+ vpcId: 'vpc-12345678',
+ env,
+ };
+ }
+
+ test('Should_CreateStack_When_ValidPropsProvided', () => {
+ // Arrange
+ const app = new App();
+ const props = createVpcLookupStackProps();
+
+ // Act
+ const stack = new VpcLookupStack(app, props);
+
+ // Assert
+ expect(stack).toBeDefined();
+ expect(stack.vpc).toBeDefined();
+ });
+
+ test('Should_UseVpcId_When_StackCreated', () => {
+ // Arrange
+ const app = new App();
+ const props = createVpcLookupStackProps();
+
+ // Act
+ const stack = new VpcLookupStack(app, props);
+
+ // Assert
+ expect(stack.stackName).toBe(props.vpcId);
+ });
+
+ test('Should_PassEnvironment_When_PropsIncludeEnv', () => {
+ // Arrange
+ const app = new App();
+ const props = createVpcLookupStackProps();
+
+ // Act
+ const stack = new VpcLookupStack(app, props);
+
+ // Assert
+ expect(stack.account).toBe(env.account);
+ expect(stack.region).toBe(env.region);
+ });
+
+ test('Should_LookupVpc_When_StackConstructed', () => {
+ // Arrange
+ const app = new App();
+ const props = createVpcLookupStackProps();
+ const { Vpc } = jest.requireMock('aws-cdk-lib/aws-ec2');
+
+ // Act
+ new VpcLookupStack(app, props);
+
+ // Assert
+ expect(Vpc.fromLookup).toHaveBeenCalledWith(
+ expect.anything(),
+ 'VpcNetwork',
+ {
+ vpcId: props.vpcId,
+ },
+ );
+ });
+
+ test('Should_HandleMissingEnv_When_EnvNotProvided', () => {
+ // Arrange
+ const app = new App();
+ const propsWithoutEnv: VpcLookupStackProps = {
+ vpcId: 'vpc-87654321',
+ };
+
+ // Act
+ const stack = new VpcLookupStack(app, propsWithoutEnv);
+
+ // Assert
+ expect(stack).toBeDefined();
+ expect(stack.vpc).toBeDefined();
+ });
+});
diff --git a/src/iac/test/aws/network/vpcStack.test.ts b/src/iac/test/aws/network/vpcStack.test.ts
new file mode 100644
index 00000000..d78558ae
--- /dev/null
+++ b/src/iac/test/aws/network/vpcStack.test.ts
@@ -0,0 +1,61 @@
+import { Template } from 'aws-cdk-lib/assertions';
+import { SubnetType } from 'aws-cdk-lib/aws-ec2';
+import 'source-map-support/register';
+import { App, Stack } from 'aws-cdk-lib';
+import {
+ type VPCStackProps,
+ VpcStack,
+} from '../../../src/aws/network/vpcStack';
+import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+
+describe('VpcStackTest', () => {
+ const expected: VPCStackProps = {
+ name: 'VpcStack',
+ stackName: 'shared',
+ maxAzs: 2,
+ natGateways: 2,
+ enableDnsHostnames: true,
+ enableDnsSupport: true,
+ envName: AppEnvironment.Test,
+ vpcName: 'private-CustomVpc',
+ vpcCdir: '22.0.0.0/16',
+ subnetConfiguration: [
+ {
+ cidrMask: 20,
+ name: 'Public1',
+ subnetType: SubnetType.PUBLIC,
+ },
+ {
+ cidrMask: 20,
+ name: 'Private1',
+ subnetType: SubnetType.PRIVATE_WITH_EGRESS,
+ },
+ ],
+ githubRepo: 'shared-test',
+ };
+ const env = {
+ account: 'account',
+ region: 'eu-west-1',
+ };
+
+ test('Should_MatchSnapshotAndResources_When_VpcStackIsCreated', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'VpcStackTest', { env });
+
+ // Act
+ const vpcStack = new VpcStack(stack, expected);
+
+ // Assert
+ const template = Template.fromStack(vpcStack);
+ expect(template.toJSON()).toMatchSnapshot('VpcStackTest');
+ template.resourceCountIs('AWS::EC2::VPC', 1);
+ template.hasResourceProperties('AWS::EC2::VPC', {
+ EnableDnsSupport: expected.enableDnsSupport,
+ EnableDnsHostnames: expected.enableDnsHostnames,
+ CidrBlock: expected.vpcCdir,
+ });
+ template.resourceCountIs('AWS::EC2::InternetGateway', 1);
+ template.resourceCountIs('AWS::EC2::VPCGatewayAttachment', 1);
+ template.resourceCountIs('AWS::EC2::Subnet', 4);
+ });
+});
diff --git a/src/iac/test/aws/website/Dockerfile b/src/iac/test/aws/website/Dockerfile
new file mode 100644
index 00000000..e578165b
--- /dev/null
+++ b/src/iac/test/aws/website/Dockerfile
@@ -0,0 +1 @@
+# This is created only for test
\ No newline at end of file
diff --git a/src/iac/test/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap b/src/iac/test/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap
new file mode 100644
index 00000000..3612805f
--- /dev/null
+++ b/src/iac/test/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap
@@ -0,0 +1,948 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Static website Stack Should_CreateWebsite_When_StackIsCalled: staticWebsiteStackTest 1`] = `
+{
+ "Mappings": {
+ "AWSCloudFrontPartitionHostedZoneIdMap": {
+ "aws": {
+ "zoneId": "Z2FDTNDATAQYW2",
+ },
+ "aws-cn": {
+ "zoneId": "Z3RFFRIM2A3IF5",
+ },
+ },
+ },
+ "Outputs": {
+ "CloudFrontDistributionDomainName": {
+ "Description": "CloudFront distribution domain",
+ "Export": {
+ "Name": "test-website-Test-CdnDomainName",
+ },
+ "Value": {
+ "Fn::GetAtt": [
+ "distribution114A0A2A",
+ "DomainName",
+ ],
+ },
+ },
+ "DnsRecordName": {
+ "Description": "The DNS record name (primary)",
+ "Export": {
+ "Name": "test-website-Test-AliasRecord",
+ },
+ "Value": {
+ "Ref": "webDomainRecord0E1EA4C11",
+ },
+ },
+ },
+ "Parameters": {
+ "BootstrapVersion": {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": {
+ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536": {
+ "DependsOn": [
+ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF",
+ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265",
+ ],
+ "Properties": {
+ "Code": {
+ "S3Bucket": "cdk-hnb659fds-assets-account-eu-west-1",
+ },
+ "Environment": {
+ "Variables": {
+ "AWS_CA_BUNDLE": "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
+ },
+ },
+ "Handler": "index.handler",
+ "Layers": [
+ {
+ "Ref": "deploystaticwebsiteAwsCliLayer31B11195",
+ },
+ ],
+ "Role": {
+ "Fn::GetAtt": [
+ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265",
+ "Arn",
+ ],
+ },
+ "Runtime": "python3.13",
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "test-website",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-test-website-websitetest-test-stack",
+ },
+ ],
+ "Timeout": 900,
+ },
+ "Type": "AWS::Lambda::Function",
+ },
+ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "ManagedPolicyArns": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
+ ],
+ ],
+ },
+ ],
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "test-website",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-test-website-websitetest-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF": {
+ "Properties": {
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::cdk-hnb659fds-assets-account-eu-west-1",
+ ],
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ "arn:",
+ {
+ "Ref": "AWS::Partition",
+ },
+ ":s3:::cdk-hnb659fds-assets-account-eu-west-1/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ "s3:PutObject",
+ "s3:PutObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:Abort*",
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "cloudfront:GetInvalidation",
+ "cloudfront:CreateInvalidation",
+ ],
+ "Effect": "Allow",
+ "Resource": "*",
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "PolicyName": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF",
+ "Roles": [
+ {
+ "Ref": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Policy",
+ },
+ "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": {
+ "DependsOn": [
+ "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092",
+ ],
+ "Properties": {
+ "Code": {
+ "S3Bucket": "cdk-hnb659fds-assets-account-eu-west-1",
+ },
+ "Description": {
+ "Fn::Join": [
+ "",
+ [
+ "Lambda function for auto-deleting objects in ",
+ {
+ "Ref": "loggingbucketCEF80102",
+ },
+ " S3 bucket.",
+ ],
+ ],
+ },
+ "Handler": "index.handler",
+ "MemorySize": 128,
+ "Role": {
+ "Fn::GetAtt": [
+ "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092",
+ "Arn",
+ ],
+ },
+ "Runtime": "nodejs22.x",
+ "Timeout": 900,
+ },
+ "Type": "AWS::Lambda::Function",
+ },
+ "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": {
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "lambda.amazonaws.com",
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ "ManagedPolicyArns": [
+ {
+ "Fn::Sub": "arn:\${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
+ },
+ ],
+ },
+ "Type": "AWS::IAM::Role",
+ },
+ "deploystaticwebsiteAwsCliLayer31B11195": {
+ "Properties": {
+ "Content": {
+ "S3Bucket": "cdk-hnb659fds-assets-account-eu-west-1",
+ },
+ "Description": "/opt/awscli/aws",
+ },
+ "Type": "AWS::Lambda::LayerVersion",
+ },
+ "deploystaticwebsiteCustomResource7923FA82": {
+ "DeletionPolicy": "Delete",
+ "Properties": {
+ "DestinationBucketName": {
+ "Ref": "staticwebsitebucket7EF1E06C",
+ },
+ "DistributionId": {
+ "Ref": "distribution114A0A2A",
+ },
+ "DistributionPaths": [
+ "/*",
+ ],
+ "OutputObjectKeys": true,
+ "Prune": true,
+ "ServiceToken": {
+ "Fn::GetAtt": [
+ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536",
+ "Arn",
+ ],
+ },
+ "SourceBucketNames": [
+ "cdk-hnb659fds-assets-account-eu-west-1",
+ ],
+ "WaitForDistributionInvalidation": true,
+ },
+ "Type": "Custom::CDKBucketDeployment",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "distribution114A0A2A": {
+ "Properties": {
+ "DistributionConfig": {
+ "Aliases": [
+ "test.domain.com",
+ ],
+ "CustomErrorResponses": [
+ {
+ "ErrorCachingMinTTL": 10,
+ "ErrorCode": 403,
+ "ResponseCode": 200,
+ "ResponsePagePath": "/index.html",
+ },
+ {
+ "ErrorCachingMinTTL": 10,
+ "ErrorCode": 404,
+ "ResponseCode": 200,
+ "ResponsePagePath": "/index.html",
+ },
+ ],
+ "DefaultCacheBehavior": {
+ "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6",
+ "Compress": true,
+ "FunctionAssociations": [
+ {
+ "EventType": "viewer-request",
+ "FunctionARN": {
+ "Fn::GetAtt": [
+ "testdomaincomurlrewrite603CDF99",
+ "FunctionARN",
+ ],
+ },
+ },
+ ],
+ "TargetOriginId": "staticWebsiteStackTestmacalberttestwebsitewebsitetestteststackdistributionOrigin1CF9AF91F",
+ "ViewerProtocolPolicy": "redirect-to-https",
+ },
+ "DefaultRootObject": "index.html",
+ "Enabled": true,
+ "HttpVersion": "http2",
+ "IPV6Enabled": true,
+ "Logging": {
+ "Bucket": {
+ "Fn::GetAtt": [
+ "loggingbucketCEF80102",
+ "RegionalDomainName",
+ ],
+ },
+ "Prefix": "cloudfront-logs/",
+ },
+ "Origins": [
+ {
+ "DomainName": {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "RegionalDomainName",
+ ],
+ },
+ "Id": "staticWebsiteStackTestmacalberttestwebsitewebsitetestteststackdistributionOrigin1CF9AF91F",
+ "S3OriginConfig": {
+ "OriginAccessIdentity": {
+ "Fn::Join": [
+ "",
+ [
+ "origin-access-identity/cloudfront/",
+ {
+ "Ref": "originAccessIdentity402DAA30",
+ },
+ ],
+ ],
+ },
+ },
+ },
+ ],
+ "ViewerCertificate": {
+ "AcmCertificateArn": "arn:aws:acm:us-east-1:account:certificate/some-guid",
+ "MinimumProtocolVersion": "TLSv1.2_2021",
+ "SslSupportMethod": "sni-only",
+ },
+ },
+ "Tags": [
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "test-website",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-test-website-websitetest-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::CloudFront::Distribution",
+ },
+ "loggingbucketAutoDeleteObjectsCustomResourceB0A91080": {
+ "DeletionPolicy": "Delete",
+ "DependsOn": [
+ "loggingbucketPolicy7C540E5A",
+ ],
+ "Properties": {
+ "BucketName": {
+ "Ref": "loggingbucketCEF80102",
+ },
+ "ServiceToken": {
+ "Fn::GetAtt": [
+ "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F",
+ "Arn",
+ ],
+ },
+ },
+ "Type": "Custom::S3AutoDeleteObjects",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "loggingbucketCEF80102": {
+ "DeletionPolicy": "Delete",
+ "Properties": {
+ "AccessControl": "LogDeliveryWrite",
+ "BucketEncryption": {
+ "ServerSideEncryptionConfiguration": [
+ {
+ "ServerSideEncryptionByDefault": {
+ "SSEAlgorithm": "AES256",
+ },
+ },
+ ],
+ },
+ "BucketName": "test.domain.com-logs",
+ "LifecycleConfiguration": {
+ "Rules": [
+ {
+ "ExpirationInDays": 90,
+ "Id": "DeleteOldLogs",
+ "Status": "Enabled",
+ },
+ ],
+ },
+ "OwnershipControls": {
+ "Rules": [
+ {
+ "ObjectOwnership": "ObjectWriter",
+ },
+ ],
+ },
+ "PublicAccessBlockConfiguration": {
+ "BlockPublicAcls": true,
+ "BlockPublicPolicy": true,
+ "IgnorePublicAcls": true,
+ "RestrictPublicBuckets": true,
+ },
+ "Tags": [
+ {
+ "Key": "aws-cdk:auto-delete-objects",
+ "Value": "true",
+ },
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "test-website",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-test-website-websitetest-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::S3::Bucket",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "loggingbucketPolicy7C540E5A": {
+ "Properties": {
+ "Bucket": {
+ "Ref": "loggingbucketCEF80102",
+ },
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "s3:*",
+ "Condition": {
+ "Bool": {
+ "aws:SecureTransport": "false",
+ },
+ },
+ "Effect": "Deny",
+ "Principal": {
+ "AWS": "*",
+ },
+ "Resource": [
+ {
+ "Fn::GetAtt": [
+ "loggingbucketCEF80102",
+ "Arn",
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ {
+ "Fn::GetAtt": [
+ "loggingbucketCEF80102",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "s3:PutBucketPolicy",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ ],
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092",
+ "Arn",
+ ],
+ },
+ },
+ "Resource": [
+ {
+ "Fn::GetAtt": [
+ "loggingbucketCEF80102",
+ "Arn",
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ {
+ "Fn::GetAtt": [
+ "loggingbucketCEF80102",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::S3::BucketPolicy",
+ },
+ "originAccessIdentity402DAA30": {
+ "Properties": {
+ "CloudFrontOriginAccessIdentityConfig": {
+ "Comment": "Setup access from CloudFront to the bucket test.domain.com (read)",
+ },
+ },
+ "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity",
+ },
+ "staticwebsitebucket7EF1E06C": {
+ "DeletionPolicy": "Delete",
+ "Properties": {
+ "AccessControl": "Private",
+ "BucketEncryption": {
+ "ServerSideEncryptionConfiguration": [
+ {
+ "ServerSideEncryptionByDefault": {
+ "SSEAlgorithm": "AES256",
+ },
+ },
+ ],
+ },
+ "BucketName": "test.domain.com",
+ "CorsConfiguration": {
+ "CorsRules": [
+ {
+ "AllowedHeaders": [
+ "*",
+ ],
+ "AllowedMethods": [
+ "GET",
+ "HEAD",
+ ],
+ "AllowedOrigins": [
+ "*",
+ ],
+ },
+ ],
+ },
+ "LoggingConfiguration": {
+ "DestinationBucketName": {
+ "Ref": "loggingbucketCEF80102",
+ },
+ "LogFilePrefix": "s3-access-logs/",
+ },
+ "PublicAccessBlockConfiguration": {
+ "BlockPublicAcls": true,
+ "BlockPublicPolicy": true,
+ "IgnorePublicAcls": true,
+ "RestrictPublicBuckets": true,
+ },
+ "Tags": [
+ {
+ "Key": "aws-cdk:auto-delete-objects",
+ "Value": "true",
+ },
+ {
+ "Key": "aws-cdk:cr-owned:5a7fd527",
+ "Value": "true",
+ },
+ {
+ "Key": "Environment",
+ "Value": "Test",
+ },
+ {
+ "Key": "Project",
+ "Value": "test-website",
+ },
+ {
+ "Key": "StackId",
+ "Value": "macalbert-test-website-websitetest-test-stack",
+ },
+ ],
+ },
+ "Type": "AWS::S3::Bucket",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "staticwebsitebucketAutoDeleteObjectsCustomResource4931B7FC": {
+ "DeletionPolicy": "Delete",
+ "DependsOn": [
+ "staticwebsitebucketPolicy34945549",
+ ],
+ "Properties": {
+ "BucketName": {
+ "Ref": "staticwebsitebucket7EF1E06C",
+ },
+ "ServiceToken": {
+ "Fn::GetAtt": [
+ "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F",
+ "Arn",
+ ],
+ },
+ },
+ "Type": "Custom::S3AutoDeleteObjects",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "staticwebsitebucketPolicy34945549": {
+ "Properties": {
+ "Bucket": {
+ "Ref": "staticwebsitebucket7EF1E06C",
+ },
+ "PolicyDocument": {
+ "Statement": [
+ {
+ "Action": "s3:*",
+ "Condition": {
+ "Bool": {
+ "aws:SecureTransport": "false",
+ },
+ },
+ "Effect": "Deny",
+ "Principal": {
+ "AWS": "*",
+ },
+ "Resource": [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "s3:PutBucketPolicy",
+ "s3:GetBucket*",
+ "s3:List*",
+ "s3:DeleteObject*",
+ ],
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": {
+ "Fn::GetAtt": [
+ "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092",
+ "Arn",
+ ],
+ },
+ },
+ "Resource": [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": [
+ "s3:GetObject*",
+ "s3:GetBucket*",
+ "s3:List*",
+ ],
+ "Effect": "Allow",
+ "Principal": {
+ "CanonicalUser": {
+ "Fn::GetAtt": [
+ "originAccessIdentity402DAA30",
+ "S3CanonicalUserId",
+ ],
+ },
+ },
+ "Resource": [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ {
+ "Fn::Join": [
+ "",
+ [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ ],
+ },
+ {
+ "Action": "s3:GetObject",
+ "Effect": "Allow",
+ "Principal": {
+ "CanonicalUser": {
+ "Fn::GetAtt": [
+ "originAccessIdentity402DAA30",
+ "S3CanonicalUserId",
+ ],
+ },
+ },
+ "Resource": {
+ "Fn::Join": [
+ "",
+ [
+ {
+ "Fn::GetAtt": [
+ "staticwebsitebucket7EF1E06C",
+ "Arn",
+ ],
+ },
+ "/*",
+ ],
+ ],
+ },
+ },
+ ],
+ "Version": "2012-10-17",
+ },
+ },
+ "Type": "AWS::S3::BucketPolicy",
+ },
+ "testdomaincomurlrewrite603CDF99": {
+ "Properties": {
+ "AutoPublish": true,
+ "FunctionCode": "// CloudFront Function for URL rewriting
+// Compatible with CloudFront Functions runtime (ES5.1)
+// Query strings are automatically preserved by CloudFront
+
+function handler(event) {
+ var req = event.request;
+ var uri = req.uri;
+
+ // ES5.1 Helpers (without startsWith/endsWith or arrow functions)
+ function endsWith(str, suffix) {
+ if (str == null || suffix == null) return false;
+ var sl = str.length, su = suffix.length;
+ return sl >= su && str.substring(sl - su) === suffix;
+ }
+ function hasPrefix(str, prefix) {
+ if (str == null || prefix == null) return false;
+ return str.indexOf(prefix) === 0;
+ }
+
+ var staticExt = [
+ '.html', '.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg',
+ '.ico', '.woff', '.woff2', '.ttf', '.otf', '.eot', '.json', '.xml',
+ '.txt', '.map'
+ ];
+
+ function hasKnownExt(uLower) {
+ for (var i = 0; i < staticExt.length; i++) {
+ if (endsWith(uLower, staticExt[i])) return true;
+ }
+ return false;
+ }
+
+ // Exclude API routes
+ var lower = uri.toLowerCase();
+ if (hasPrefix(lower, '/api/')) {
+ return req; // no changes
+ }
+
+ // Remove trailing slash (except homepage)
+ if (uri !== '/' && endsWith(uri, '/')) {
+ uri = uri.substring(0, uri.length - 1);
+ lower = uri.toLowerCase(); // recompute after modifying uri
+ }
+
+ // Append .html if not homepage and no known extension
+ if (uri !== '/' && !hasKnownExt(lower)) {
+ // For /folder/index.html instead of /folder.html, use:
+ // uri += '/index.html';
+ uri += '.html';
+ }
+
+ req.uri = uri;
+ return req;
+}
+",
+ "FunctionConfig": {
+ "Comment": "eu-west-1test-web-apptestncom-url-rewrite979D13F7",
+ "Runtime": "cloudfront-js-1.0",
+ },
+ "Name": "eu-west-1test-web-apptestncom-url-rewrite979D13F7",
+ },
+ "Type": "AWS::CloudFront::Function",
+ },
+ "webDomainRecord0E1EA4C11": {
+ "Properties": {
+ "AliasTarget": {
+ "DNSName": {
+ "Fn::GetAtt": [
+ "distribution114A0A2A",
+ "DomainName",
+ ],
+ },
+ "HostedZoneId": {
+ "Fn::FindInMap": [
+ "AWSCloudFrontPartitionHostedZoneIdMap",
+ {
+ "Ref": "AWS::Partition",
+ },
+ "zoneId",
+ ],
+ },
+ },
+ "HostedZoneId": "123456789",
+ "Name": "test.domain.com.",
+ "Type": "A",
+ },
+ "Type": "AWS::Route53::RecordSet",
+ },
+ },
+ "Rules": {
+ "CheckBootstrapVersion": {
+ "Assertions": [
+ {
+ "Assert": {
+ "Fn::Not": [
+ {
+ "Fn::Contains": [
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
diff --git a/src/iac/test/aws/website/cloudfrontUrlRewrite.test.ts b/src/iac/test/aws/website/cloudfrontUrlRewrite.test.ts
new file mode 100644
index 00000000..19028390
--- /dev/null
+++ b/src/iac/test/aws/website/cloudfrontUrlRewrite.test.ts
@@ -0,0 +1,159 @@
+import { readFileSync } from 'node:fs';
+import { join } from 'node:path';
+
+describe('CloudFront URL Rewrite Function', () => {
+ // Read and execute the handler file
+ const handlerPath = join(
+ __dirname,
+ '../../../src/aws/website/cloudfront-url-rewrite.js',
+ );
+ const handlerCode = readFileSync(handlerPath, 'utf8');
+
+ // Create handler function from the source file
+ const handlerFunc = new Function(
+ 'event',
+ `${handlerCode}; return handler(event);`,
+ ) as (event: { request: { uri: string; querystring: string } }) => {
+ uri: string;
+ };
+
+ interface TestCase {
+ input: string;
+ expectedUri: string;
+ }
+
+ interface TestCaseWithQueryString {
+ input: string;
+ expectedVisible: string;
+ }
+
+ const testCases: TestCase[] = [
+ { input: '/', expectedUri: '/' },
+ { input: '/dashboard', expectedUri: '/dashboard.html' },
+ { input: '/dashboard/', expectedUri: '/dashboard.html' },
+ { input: '/groups', expectedUri: '/groups.html' },
+ { input: '/app.js', expectedUri: '/app.js' },
+ { input: '/styles/main.css', expectedUri: '/styles/main.css' },
+ { input: '/IMG/Photo.JPG', expectedUri: '/IMG/Photo.JPG' },
+ { input: '/IMG/photo.jpg', expectedUri: '/IMG/photo.jpg' },
+ { input: '/api/users', expectedUri: '/api/users' },
+ { input: '/api/users/123', expectedUri: '/api/users/123' },
+ { input: '/API/USERS', expectedUri: '/API/USERS' },
+ { input: '/folder/page', expectedUri: '/folder/page.html' },
+ { input: '/contact/', expectedUri: '/contact.html' },
+ { input: '/file.txt', expectedUri: '/file.txt' },
+ { input: '/source.map', expectedUri: '/source.map' },
+ ];
+
+ const testCasesWithQueryString: TestCaseWithQueryString[] = [
+ {
+ input: '/contact?utm_source=x',
+ expectedVisible: '/contact.html?utm_source=x',
+ },
+ {
+ input: '/styles/main.css?ver=123',
+ expectedVisible: '/styles/main.css?ver=123',
+ },
+ {
+ input: '/dashboard?param1=value1¶m2=value2',
+ expectedVisible: '/dashboard.html?param1=value1¶m2=value2',
+ },
+ ];
+
+ const apiRoutes: TestCase[] = [
+ { input: '/api/users', expectedUri: '/api/users' },
+ { input: '/API/data', expectedUri: '/API/data' },
+ { input: '/api/v1/endpoint', expectedUri: '/api/v1/endpoint' },
+ ];
+
+ const staticFiles: TestCase[] = [
+ { input: '/app.js', expectedUri: '/app.js' },
+ { input: '/styles.css', expectedUri: '/styles.css' },
+ { input: '/image.png', expectedUri: '/image.png' },
+ { input: '/font.woff2', expectedUri: '/font.woff2' },
+ { input: '/data.json', expectedUri: '/data.json' },
+ ];
+
+ test.each(testCases)('Should_RewriteUrlCorrectly_When_RequestedUrl_$input', ({
+ input,
+ expectedUri,
+ }) => {
+ // Arrange
+ const event = {
+ request: {
+ uri: input,
+ querystring: '',
+ },
+ };
+
+ // Act
+ const result = handlerFunc(event);
+
+ // Assert
+ expect(result.uri).toBe(expectedUri);
+ });
+
+ test.each(
+ testCasesWithQueryString,
+ )('Should_PreserveQueryStrings_When_UrlHasParameters_$input', ({
+ input,
+ expectedVisible,
+ }) => {
+ // Arrange
+ const uriPath = input.split('?')[0];
+ const qs = input.split('?')[1];
+
+ const event = {
+ request: {
+ uri: uriPath,
+ querystring: qs,
+ },
+ };
+
+ // Act
+ const result = handlerFunc(event);
+ const visible = `${result.uri}?${qs}`;
+ // Assert
+ expect(visible).toBe(expectedVisible);
+ });
+
+ test.each(apiRoutes)('Should_NotModifyUri_When_RequestIsApiRoute_$input', ({
+ input,
+ expectedUri,
+ }) => {
+ // Arrange
+ const event = {
+ request: {
+ uri: input,
+ querystring: '',
+ },
+ };
+
+ // Act
+ const result = handlerFunc(event);
+
+ // Assert
+ expect(result.uri).toBe(expectedUri);
+ });
+
+ test.each(
+ staticFiles,
+ )('Should_NotModifyUri_When_FileHasKnownExtension_$input', ({
+ input,
+ expectedUri,
+ }) => {
+ // Arrange
+ const event = {
+ request: {
+ uri: input,
+ querystring: '',
+ },
+ };
+
+ // Act
+ const result = handlerFunc(event);
+
+ // Assert
+ expect(result.uri).toBe(expectedUri);
+ });
+});
diff --git a/src/iac/test/aws/website/staticWebsiteStack.test.ts b/src/iac/test/aws/website/staticWebsiteStack.test.ts
new file mode 100644
index 00000000..ea11f6fd
--- /dev/null
+++ b/src/iac/test/aws/website/staticWebsiteStack.test.ts
@@ -0,0 +1,89 @@
+import * as fs from 'node:fs';
+import * as os from 'node:os';
+import * as path from 'node:path';
+import { App, Stack } from 'aws-cdk-lib';
+import { Template } from 'aws-cdk-lib/assertions';
+import {
+ StaticWebsiteStack,
+ type StaticWebsiteStackProps,
+} from '../../../src/aws/website/staticWebsiteStack';
+import type { DomainConfig } from '../../../src/config/domain/customStack';
+import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+
+describe('Static website Stack', () => {
+ const env = {
+ account: 'account',
+ region: 'eu-west-1',
+ };
+
+ let tmpDir: string;
+
+ beforeEach(() => {
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'static-website-test-'));
+ fs.writeFileSync(path.join(tmpDir, 'index.html'), '');
+ });
+
+ afterEach(() => {
+ fs.rmSync(tmpDir, { recursive: true, force: true });
+ });
+
+ test('Should_CreateWebsite_When_StackIsCalled', () => {
+ // Arrange
+ const stack = new Stack(new App(), 'staticWebsiteStackTest', {
+ env: env,
+ });
+ const props = createStaticWebsiteStackProps();
+
+ // Act
+ const actual = new StaticWebsiteStack(stack, props);
+
+ // Assert
+ const template = Template.fromStack(actual).toJSON();
+ normalizeStaticWebsiteTemplate(template);
+
+ expect(template).toMatchSnapshot('staticWebsiteStackTest');
+ });
+
+ // biome-ignore lint/suspicious/noExplicitAny: CDK template is untyped
+ function normalizeStaticWebsiteTemplate(template: Record): void {
+ for (const key in template.Resources) {
+ const resource = template.Resources[key];
+ if (resource.Properties.SourceObjectKeys) {
+ const { SourceObjectKeys: _SourceObjectKeys, ...otherProps } =
+ resource.Properties;
+ resource.Properties = otherProps;
+ }
+ if (resource.Properties.Content?.S3Key) {
+ const { S3Key: _S3Key, ...otherContentProps } =
+ resource.Properties.Content;
+ resource.Properties.Content = otherContentProps;
+ }
+ if (resource.Properties.Code?.S3Key) {
+ const { S3Key: _S3KeyCode, ...otherCodeProps } =
+ resource.Properties.Code;
+ resource.Properties.Code = otherCodeProps;
+ }
+ }
+ }
+
+ function createStaticWebsiteStackProps(): StaticWebsiteStackProps {
+ const domains: DomainConfig[] = [
+ {
+ subdomain: 'test',
+ domainName: 'domain.com',
+ hostedZoneId: '123456789',
+ certificateId: 'some-guid',
+ },
+ ];
+
+ return {
+ env: env,
+ name: 'websitetest',
+ domains: domains,
+ distFolderPath: tmpDir,
+ envName: AppEnvironment.Test,
+ githubRepo: 'test-website',
+ stackName: 'test-web-app',
+ };
+ }
+});
diff --git a/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts b/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
new file mode 100644
index 00000000..980ef2ad
--- /dev/null
+++ b/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
@@ -0,0 +1,118 @@
+import type { Environment } from 'aws-cdk-lib';
+import { App } from 'aws-cdk-lib';
+import { DeployInfrastructureHandler } from '../../../../src/config/application/deployInfrastructure/deployInfrastructureHandler';
+import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+import { ConfigValidationError } from '../../../../src/config/infrastructure/utilities/errors';
+
+// Mock AWS infrastructure (VPC + CDK Stacks)
+jest.mock('../../../../src/aws/developerTools/codepipeline/pipelineStack');
+jest.mock('../../../../src/aws/network/vpcLookupStack');
+jest.mock('../../../../src/aws/website/staticWebsiteStack');
+
+describe('DeployInfrastructureUseCase', () => {
+ let app: App;
+ let envFromCli: Environment;
+ let iacConfig: IDeploymentRequest;
+ let orchestrator: DeployInfrastructureHandler;
+ let consoleLogSpy: jest.SpyInstance;
+ let consoleErrorSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
+
+ app = new App({ outdir: '/tmp/cdk.out' });
+ jest.spyOn(app, 'synth').mockImplementation();
+
+ envFromCli = {
+ region: 'us-east-1',
+ account: '123456789012',
+ };
+
+ iacConfig = createValidConfig();
+
+ orchestrator = new DeployInfrastructureHandler(app, envFromCli, iacConfig);
+ });
+
+ afterEach(() => {
+ consoleLogSpy.mockRestore();
+ consoleErrorSpy.mockRestore();
+ });
+
+ function createValidConfig(): IDeploymentRequest {
+ return {
+ repoName: 'test-repo',
+ vpcId: 'vpc-12345678',
+ branch: 'main',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'example.com',
+ certificateId: 'cert-123456',
+ hostedZoneId: 'Z123456789',
+ },
+ stacks: {
+ frontend: {
+ staticWebsites: [],
+ },
+ shared: {
+ pipeline: [],
+ },
+ },
+ };
+ }
+
+ describe('run', () => {
+ it('Should_CompleteDeploymentSuccessfully_When_ConfigIsValid', () => {
+ // Arrange - default setup from beforeEach
+
+ // Act
+ orchestrator.run();
+
+ // Assert
+ expect(consoleLogSpy).toHaveBeenCalledWith(
+ expect.stringContaining('[test-repo]'),
+ );
+ });
+ });
+
+ describe('getProjectPathResolver', () => {
+ it('Should_ReturnProjectPathResolver_When_Called', () => {
+ // Arrange - default setup from beforeEach
+
+ // Act
+ const actual = orchestrator.getProjectPathResolver();
+
+ // Assert
+ expect(actual).toBeDefined();
+ expect(actual.getRootPath).toBeDefined();
+ expect(actual.resolveFullPath).toBeDefined();
+ });
+ });
+
+ describe('Error handling', () => {
+ it('Should_LogError_When_ValidationFails', () => {
+ // Arrange
+ const invalidConfig: IDeploymentRequest = {
+ ...iacConfig,
+ vpcId: '',
+ };
+ const invalidOrchestrator = new DeployInfrastructureHandler(
+ app,
+ envFromCli,
+ invalidConfig,
+ );
+
+ // Act
+ const action = () => invalidOrchestrator.run();
+
+ // Assert
+ expect(action).toThrow(ConfigValidationError);
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ expect.stringContaining('❌ Error:'),
+ );
+ });
+ });
+});
diff --git a/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts b/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
new file mode 100644
index 00000000..324b2483
--- /dev/null
+++ b/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
@@ -0,0 +1,124 @@
+import { App } from 'aws-cdk-lib';
+import type { IDeploymentRequest } from '../../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../../src/config/domain/model/appEnvironment';
+import { FrontendBuilder } from '../../../../../src/config/domain/builders/frontendBuilder';
+import { SharedBuilder } from '../../../../../src/config/domain/builders/sharedBuilder';
+import { StackBuilderFactory } from '../../../../../src/config/domain/builders/factories/stackBuilderFactory';
+
+describe('StackBuilderFactory', () => {
+ function createValidConfig(): IDeploymentRequest {
+ return {
+ repoName: 'test-repo',
+ vpcId: 'vpc-12345678',
+ branch: 'main',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'example.com',
+ certificateId: 'cert-123',
+ hostedZoneId: 'Z123',
+ },
+ stacks: {
+ frontend: {
+ staticWebsites: [],
+ },
+ shared: {
+ pipeline: [],
+ },
+ },
+ };
+ }
+
+ describe('createStackParts', () => {
+ test('Should_CreateBothStackParts_When_AllConfigsProvided', () => {
+ // Arrange
+ const app = new App();
+ const config = createValidConfig();
+
+ // Act
+ const result = StackBuilderFactory.createStackParts(app, config);
+
+ // Assert
+ expect(result).toHaveLength(2);
+ expect(result[0]).toBeInstanceOf(FrontendBuilder);
+ expect(result[1]).toBeInstanceOf(SharedBuilder);
+ });
+
+ test('Should_CreateFrontendBuilder_When_FrontendConfigProvided', () => {
+ // Arrange
+ const app = new App();
+ const config = createValidConfig();
+
+ // Act
+ const result = StackBuilderFactory.createStackParts(app, config);
+
+ // Assert
+ const frontendBuilder = result.find(
+ (part) => part instanceof FrontendBuilder,
+ );
+ expect(frontendBuilder).toBeDefined();
+ expect(frontendBuilder).toBeInstanceOf(FrontendBuilder);
+ });
+
+ test('Should_CreateSharedBuilder_When_SharedConfigProvided', () => {
+ // Arrange
+ const app = new App();
+ const config = createValidConfig();
+
+ // Act
+ const result = StackBuilderFactory.createStackParts(app, config);
+
+ // Assert
+ const sharedBuilder = result.find(
+ (part) => part instanceof SharedBuilder,
+ );
+ expect(sharedBuilder).toBeDefined();
+ expect(sharedBuilder).toBeInstanceOf(SharedBuilder);
+ });
+
+ test('Should_CreateOnlyFrontendBuilder_When_OnlyFrontendConfigProvided', () => {
+ // Arrange
+ const app = new App();
+ const config = createValidConfig();
+ // biome-ignore lint/suspicious/noExplicitAny: testing undefined config
+ config.stacks.shared = undefined as any;
+
+ // Act
+ const result = StackBuilderFactory.createStackParts(app, config);
+
+ // Assert
+ expect(result).toHaveLength(1);
+ expect(result[0]).toBeInstanceOf(FrontendBuilder);
+ });
+
+ test('Should_CreateOnlySharedBuilder_When_OnlySharedConfigProvided', () => {
+ // Arrange
+ const app = new App();
+ const config = createValidConfig();
+ // biome-ignore lint/suspicious/noExplicitAny: testing undefined config
+ config.stacks.frontend = undefined as any;
+
+ // Act
+ const result = StackBuilderFactory.createStackParts(app, config);
+
+ // Assert
+ expect(result).toHaveLength(1);
+ expect(result[0]).toBeInstanceOf(SharedBuilder);
+ });
+
+ test('Should_ReturnEmptyArray_When_NoStackConfigsProvided', () => {
+ // Arrange
+ const app = new App();
+ const config = createValidConfig();
+ // biome-ignore lint/suspicious/noExplicitAny: testing undefined config
+ config.stacks.frontend = undefined as any;
+ // biome-ignore lint/suspicious/noExplicitAny: testing undefined config
+ config.stacks.shared = undefined as any;
+
+ // Act
+ const result = StackBuilderFactory.createStackParts(app, config);
+
+ // Assert
+ expect(result).toHaveLength(0);
+ });
+ });
+});
diff --git a/src/iac/test/config/domain/builders/frontendBuilder.test.ts b/src/iac/test/config/domain/builders/frontendBuilder.test.ts
new file mode 100644
index 00000000..60eb3743
--- /dev/null
+++ b/src/iac/test/config/domain/builders/frontendBuilder.test.ts
@@ -0,0 +1,87 @@
+import { FrontendBuilder } from '../../../../src/config/domain/builders/frontendBuilder';
+import type { FrontendBuilderProps } from '../../../../src/config/domain/builders/frontendBuilder';
+import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+import type { IStackBuildContext } from '../../../../src/config/domain/iStackBuilder';
+import { App } from 'aws-cdk-lib';
+import type { IVpc } from 'aws-cdk-lib/aws-ec2';
+import { FileProjectPath } from '../../../../src/config/infrastructure/projectPath/fileProjectPath';
+
+jest.mock('../../../../src/aws/website/staticWebsiteStack');
+
+describe('FrontendBuilder', () => {
+ const mockVpc = {} as IVpc;
+ const mockEnv = { account: '123456789012', region: 'us-east-1' };
+
+ const createMinimalConfig = (): IDeploymentRequest => ({
+ repoName: 'test-repo',
+ branch: 'main',
+ vpcId: 'vpc-123',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'example.com',
+ certificateId: 'cert-123',
+ hostedZoneId: 'zone-123',
+ },
+ stacks: {
+ frontend: {
+ staticWebsites: [],
+ },
+ shared: {},
+ },
+ });
+
+ const createBuilderProps = (
+ iacConfig: IDeploymentRequest,
+ ): FrontendBuilderProps => ({
+ scope: new App(),
+ iacConfig,
+ stackName: 'test-stack',
+ projectPathResolver: new FileProjectPath(iacConfig.repoName),
+ });
+
+ const createBuildContext = (): IStackBuildContext => ({
+ vpc: mockVpc,
+ env: mockEnv,
+ environment: AppEnvironment.Production,
+ });
+
+ describe('build', () => {
+ it('Should_CreateStaticWebsiteStack_When_ValidConfigProvided', () => {
+ const config = createMinimalConfig();
+ config.stacks.frontend = {
+ staticWebsites: [
+ {
+ name: 'StaticSite',
+ subdomain: 'www.test',
+ projectPath: 'apps/website',
+ },
+ ],
+ };
+
+ const builder = new FrontendBuilder(createBuilderProps(config));
+
+ const actual = builder.build(createBuildContext());
+
+ expect(actual).toHaveLength(1);
+ });
+
+ it('Should_ReturnEmptyArray_When_NoWebsitesConfigured', () => {
+ const config = createMinimalConfig();
+ const builder = new FrontendBuilder(createBuilderProps(config));
+
+ const actual = builder.build(createBuildContext());
+
+ expect(actual).toEqual([]);
+ });
+
+ it('Should_ThrowError_When_MissingRequiredConfig', () => {
+ const config = createMinimalConfig();
+ delete (config.stacks as { frontend?: unknown }).frontend;
+
+ const action = () => new FrontendBuilder(createBuilderProps(config));
+
+ expect(action).toThrow('Frontend stack configuration is required');
+ });
+ });
+});
diff --git a/src/iac/test/config/domain/builders/sharedBuilder.test.ts b/src/iac/test/config/domain/builders/sharedBuilder.test.ts
new file mode 100644
index 00000000..5876a3bb
--- /dev/null
+++ b/src/iac/test/config/domain/builders/sharedBuilder.test.ts
@@ -0,0 +1,83 @@
+import { SharedBuilder } from '../../../../src/config/domain/builders/sharedBuilder';
+import type { SharedBuilderProps } from '../../../../src/config/domain/builders/sharedBuilder';
+import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+import type { IStackBuildContext } from '../../../../src/config/domain/iStackBuilder';
+import { App } from 'aws-cdk-lib';
+import type { IVpc } from 'aws-cdk-lib/aws-ec2';
+
+jest.mock('../../../../src/aws/developerTools/codepipeline/pipelineStack');
+
+describe('SharedBuilder', () => {
+ const mockVpc = {} as IVpc;
+ const mockEnv = { account: '123456789012', region: 'us-east-1' };
+
+ const createMinimalConfig = (): IDeploymentRequest => ({
+ repoName: 'test-repo',
+ branch: 'main',
+ vpcId: 'vpc-123',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'example.com',
+ certificateId: 'cert-123',
+ hostedZoneId: 'zone-123',
+ },
+ stacks: {
+ shared: {},
+ frontend: { staticWebsites: [] },
+ },
+ });
+
+ const createBuilderProps = (
+ iacConfig: IDeploymentRequest,
+ ): SharedBuilderProps => ({
+ scope: new App(),
+ iacConfig,
+ stackName: 'test-stack',
+ });
+
+ const createBuildContext = (): IStackBuildContext => ({
+ vpc: mockVpc,
+ env: mockEnv,
+ environment: AppEnvironment.Production,
+ });
+
+ describe('build', () => {
+ it('Should_CreatePipelineStack_When_PipelineConfigProvided', () => {
+ const config = createMinimalConfig();
+ config.stacks.shared = {
+ pipeline: [
+ {
+ testBuildSpecs: ['test.yml'],
+ deployBuildSpecs: ['deploy.yml'],
+ manualApproval: false,
+ },
+ ],
+ };
+
+ const builder = new SharedBuilder(createBuilderProps(config));
+
+ const actual = builder.build(createBuildContext());
+
+ expect(actual).toHaveLength(1);
+ });
+
+ it('Should_ReturnEmptyArray_When_NoSharedStacksConfigured', () => {
+ const config = createMinimalConfig();
+ const builder = new SharedBuilder(createBuilderProps(config));
+
+ const actual = builder.build(createBuildContext());
+
+ expect(actual).toEqual([]);
+ });
+
+ it('Should_ThrowError_When_MissingRequiredConfig', () => {
+ const config = createMinimalConfig();
+ delete (config.stacks as { shared?: unknown }).shared;
+
+ const action = () => new SharedBuilder(createBuilderProps(config));
+
+ expect(action).toThrow('Shared stack configuration is required');
+ });
+ });
+});
diff --git a/src/iac/test/config/domain/iStackBuilder.test.ts b/src/iac/test/config/domain/iStackBuilder.test.ts
new file mode 100644
index 00000000..61ab345c
--- /dev/null
+++ b/src/iac/test/config/domain/iStackBuilder.test.ts
@@ -0,0 +1,92 @@
+import {
+ IStackBuilder,
+ type IStackBuildProps,
+ type IStackBuildContext,
+} from '../../../src/config/domain/iStackBuilder';
+import type { IDeploymentRequest } from '../../../src/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+import type { Stack } from 'aws-cdk-lib';
+import { App } from 'aws-cdk-lib';
+import type { IVpc } from 'aws-cdk-lib/aws-ec2';
+
+class ConcreteStackBuilder extends IStackBuilder {
+ public context!: IStackBuildContext;
+
+ getIacConfig(): IDeploymentRequest {
+ return this.props.iacConfig;
+ }
+
+ formatRepoNameForCloudFormation(): string {
+ return this.props.iacConfig.repoName
+ .toLowerCase()
+ .replace(/[^a-z0-9-]/g, '-');
+ }
+
+ build(context: IStackBuildContext): Stack[] {
+ this.context = context;
+ return [];
+ }
+}
+
+describe('IStackBuilder', () => {
+ const createMockConfig = (): IDeploymentRequest => ({
+ repoName: 'test-repo',
+ branch: 'main',
+ vpcId: 'vpc-123',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'example.com',
+ certificateId: 'cert-123',
+ hostedZoneId: 'zone-123',
+ },
+ stacks: {
+ frontend: { staticWebsites: [] },
+ shared: {},
+ },
+ });
+
+ const createProps = (config: IDeploymentRequest): IStackBuildProps => ({
+ scope: new App(),
+ iacConfig: config,
+ stackName: 'test-stack',
+ });
+
+ describe('getIacConfig', () => {
+ it('Should_ReturnConfiguration_When_Called', () => {
+ const config = createMockConfig();
+ const stackPart = new ConcreteStackBuilder(createProps(config));
+
+ const actual = stackPart.getIacConfig();
+
+ expect(actual).toBe(config);
+ });
+ });
+
+ describe('formatRepoNameForCloudFormation', () => {
+ it('Should_FormatRepoName_When_SpecialCharactersPresent', () => {
+ const config = createMockConfig();
+ config.repoName = 'test-repo_name.with-special';
+ const stackPart = new ConcreteStackBuilder(createProps(config));
+
+ const actual = stackPart.formatRepoNameForCloudFormation();
+
+ expect(actual).toBe('test-repo-name-with-special');
+ });
+ });
+
+ describe('build', () => {
+ it('Should_BuildSuccessfully_When_ContextProvided', () => {
+ const config = createMockConfig();
+ const stackPart = new ConcreteStackBuilder(createProps(config));
+ const context: IStackBuildContext = {
+ vpc: {} as IVpc,
+ env: { account: '123456789012', region: 'us-east-1' },
+ environment: AppEnvironment.Production,
+ };
+
+ const actual = stackPart.build(context);
+
+ expect(actual).toEqual([]);
+ });
+ });
+});
diff --git a/src/iac/test/config/domain/m47Stack.test.ts b/src/iac/test/config/domain/m47Stack.test.ts
new file mode 100644
index 00000000..078e227e
--- /dev/null
+++ b/src/iac/test/config/domain/m47Stack.test.ts
@@ -0,0 +1,132 @@
+import { App } from 'aws-cdk-lib';
+import {
+ CustomStack,
+ type CustomStackProps,
+} from '../../../src/config/domain/customStack';
+import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+
+describe('CustomStack', () => {
+ function createCustomStackProps(): CustomStackProps {
+ return {
+ githubRepo: 'test-repo',
+ envName: AppEnvironment.Test,
+ name: 'test-stack',
+ stackName: 'test-stack-name',
+ };
+ }
+
+ test('Should_CreateStack_When_ValidPropsProvided', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+
+ // Act
+ const stack = new CustomStack(app, props);
+
+ // Assert
+ expect(stack).toBeDefined();
+ expect(stack.props).toEqual(props);
+ });
+
+ test('Should_GenerateStackId_When_GetStackIdCalled', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+ const stack = new CustomStack(app, props);
+
+ // Act
+ const stackId = stack.getStackId();
+
+ // Assert
+ expect(stackId).toContain('macalbert');
+ expect(stackId).toContain('test-repo');
+ expect(stackId).toContain('test-stack');
+ expect(stackId).toContain('test');
+ expect(stackId).toContain('stack');
+ });
+
+ test('Should_AddProjectTags_When_StackCreated', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+
+ // Act
+ const stack = new CustomStack(app, props);
+
+ // Assert
+ const tags = stack.tags;
+ expect(tags).toBeDefined();
+ });
+
+ test('Should_FormatRepoNameForCloudFormation_When_ToCloudFormationCalled', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+ props.githubRepo = 'My_Test_Repo';
+ const stack = new CustomStack(app, props);
+
+ // Act
+ const result = stack.toCloudFormation();
+
+ // Assert
+ expect(result).toBe('my-test-repo');
+ });
+
+ test('Should_HandleUppercaseRepo_When_StackCreated', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+ props.githubRepo = 'TEST-REPO';
+
+ // Act
+ const stack = new CustomStack(app, props);
+
+ // Assert
+ expect(stack.getStackId()).toContain('test-repo');
+ });
+
+ test('Should_HandleSpecialChars_When_RepoNameHasSpecialChars', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+ props.githubRepo = 'test_repo@123';
+
+ // Act
+ const stack = new CustomStack(app, props);
+ const cloudFormationName = stack.toCloudFormation();
+
+ // Assert
+ expect(cloudFormationName).toMatch(/^[a-z0-9-]+$/);
+ });
+
+ test('Should_UseDifferentEnvironments_When_EnvNameChanged', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+
+ // Act & Assert
+ props.envName = AppEnvironment.Production;
+ const prodStack = new CustomStack(app, props);
+ expect(prodStack.getStackId()).toContain('production');
+
+ props.envName = AppEnvironment.Development;
+ props.name = 'different-stack'; // Need different name to avoid conflict
+ const devStack = new CustomStack(app, props);
+ expect(devStack.getStackId()).toContain('development');
+ });
+
+ test('Should_GenerateLowercaseStackId_When_StackCreated', () => {
+ // Arrange
+ const app = new App();
+ const props = createCustomStackProps();
+ props.name = 'MyTestStack';
+ props.githubRepo = 'MyRepo';
+
+ // Act
+ const stack = new CustomStack(app, props);
+ const stackId = stack.getStackId();
+
+ // Assert
+ expect(stackId).toBe(stackId.toLowerCase());
+ });
+});
diff --git a/src/iac/test/config/domain/model/appEnvironment.test.ts b/src/iac/test/config/domain/model/appEnvironment.test.ts
new file mode 100644
index 00000000..be5e8f1b
--- /dev/null
+++ b/src/iac/test/config/domain/model/appEnvironment.test.ts
@@ -0,0 +1,90 @@
+import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+
+describe('AppEnvironment', () => {
+ test('Should_HaveProductionValue_When_EnumAccessed', () => {
+ // Arrange & Act
+ const value = AppEnvironment.Production;
+
+ // Assert
+ expect(value).toBe('Production');
+ });
+
+ test('Should_HaveDevelopmentValue_When_EnumAccessed', () => {
+ // Arrange & Act
+ const value = AppEnvironment.Development;
+
+ // Assert
+ expect(value).toBe('Development');
+ });
+
+ test('Should_HaveBetaValue_When_EnumAccessed', () => {
+ // Arrange & Act
+ const value = AppEnvironment.Beta;
+
+ // Assert
+ expect(value).toBe('Beta');
+ });
+
+ test('Should_HaveStagingValue_When_EnumAccessed', () => {
+ // Arrange & Act
+ const value = AppEnvironment.Staging;
+
+ // Assert
+ expect(value).toBe('Staging');
+ });
+
+ test('Should_HaveGithubActionValue_When_EnumAccessed', () => {
+ // Arrange & Act
+ const value = AppEnvironment.GithubAction;
+
+ // Assert
+ expect(value).toBe('GithubAction');
+ });
+
+ test('Should_HaveTestValue_When_EnumAccessed', () => {
+ // Arrange & Act
+ const value = AppEnvironment.Test;
+
+ // Assert
+ expect(value).toBe('Test');
+ });
+
+ test('Should_HaveAllSixValues_When_EnumIsChecked', () => {
+ // Arrange
+ const expectedValues = [
+ 'Production',
+ 'Development',
+ 'Beta',
+ 'Staging',
+ 'GithubAction',
+ 'Test',
+ ];
+
+ // Act
+ const actualValues = Object.values(AppEnvironment);
+
+ // Assert
+ expect(actualValues).toHaveLength(6);
+ expect(actualValues).toEqual(expect.arrayContaining(expectedValues));
+ });
+
+ test('Should_BeStringEnum_When_ValuesAreChecked', () => {
+ // Arrange & Act
+ const values = Object.values(AppEnvironment);
+
+ // Assert
+ for (const value of values) {
+ expect(typeof value).toBe('string');
+ }
+ });
+
+ test('Should_HaveMatchingKeysAndValues_When_EnumIsExamined', () => {
+ // Arrange & Act & Assert
+ expect(AppEnvironment.Production).toBe('Production');
+ expect(AppEnvironment.Development).toBe('Development');
+ expect(AppEnvironment.Beta).toBe('Beta');
+ expect(AppEnvironment.Staging).toBe('Staging');
+ expect(AppEnvironment.GithubAction).toBe('GithubAction');
+ expect(AppEnvironment.Test).toBe('Test');
+ });
+});
diff --git a/src/iac/test/config/domain/services/stackBuilderService.test.ts b/src/iac/test/config/domain/services/stackBuilderService.test.ts
new file mode 100644
index 00000000..59550fe3
--- /dev/null
+++ b/src/iac/test/config/domain/services/stackBuilderService.test.ts
@@ -0,0 +1,160 @@
+import type { Environment } from 'aws-cdk-lib';
+import type { IVpc } from 'aws-cdk-lib/aws-ec2';
+import type { Node } from 'constructs';
+import { ConsoleDeploymentLogger } from '../../../../src/config/infrastructure/logging/consoleDeploymentLogger';
+import {
+ IStackBuilder,
+ type IStackBuildProps,
+} from '../../../../src/config/domain/iStackBuilder';
+import { StackBuildError } from '../../../../src/config/infrastructure/utilities/errors';
+import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+import { StackBuilderService } from '../../../../src/config/domain/services/stackBuilderService';
+
+// Mock dependencies
+jest.mock(
+ '../../../../src/config/infrastructure/logging/consoleDeploymentLogger',
+);
+
+describe('StackBuilderService', () => {
+ let stackBuilderService: StackBuilderService;
+ let mockLogger: jest.Mocked;
+ let mockNode: jest.Mocked;
+ let mockVpc: jest.Mocked;
+ let env: Environment;
+
+ beforeEach(() => {
+ // Reset all mocks
+ jest.clearAllMocks();
+
+ // Create mock instances
+ mockLogger =
+ new ConsoleDeploymentLogger() as jest.Mocked;
+ mockLogger.logRepositoryInfo = jest.fn();
+ mockLogger.logRequestedStacks = jest.fn();
+
+ // Create mock node with tryGetContext method
+ mockNode = {
+ tryGetContext: jest.fn(),
+ } as unknown as jest.Mocked;
+
+ // Create mock VPC
+ mockVpc = {} as jest.Mocked;
+
+ // Create environment
+ env = {
+ region: 'us-east-1',
+ account: '123456789012',
+ };
+
+ // Create service instance
+ stackBuilderService = new StackBuilderService(
+ mockLogger,
+ 'test-repo',
+ env,
+ mockVpc,
+ mockNode,
+ AppEnvironment.Production,
+ );
+ });
+
+ describe('Happy Path Tests', () => {
+ test('Should_GetBranchNameFromContext_When_BranchExistsInContext', () => {
+ // Arrange
+ mockNode.tryGetContext = jest.fn().mockReturnValue('feature/test');
+
+ // Act
+ const actual = stackBuilderService.getBranchName();
+
+ // Assert
+ expect(actual).toBe('feature/test');
+ expect(mockNode.tryGetContext).toHaveBeenCalledWith('branch');
+ expect(mockLogger.logRepositoryInfo).toHaveBeenCalledWith(
+ 'test-repo',
+ 'feature/test',
+ );
+ });
+
+ test('Should_DefaultToMain_When_BranchNotInContext', () => {
+ // Arrange
+ mockNode.tryGetContext = jest.fn().mockReturnValue(undefined);
+
+ // Act
+ const actual = stackBuilderService.getBranchName();
+
+ // Assert
+ expect(actual).toBe('main');
+ expect(mockNode.tryGetContext).toHaveBeenCalledWith('branch');
+ expect(mockLogger.logRepositoryInfo).toHaveBeenCalledWith(
+ 'test-repo',
+ 'main',
+ );
+ });
+
+ test('Should_BuildAllStackParts_When_AllStacksValid', () => {
+ // Arrange
+ const stackParts: IStackBuilder[] = [];
+
+ // Act
+ const action = () => stackBuilderService.buildStackParts(stackParts);
+
+ // Assert
+ expect(action).not.toThrow();
+ expect(mockLogger.logRequestedStacks).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('Corner Case Tests', () => {
+ test('Should_IgnoreError_When_CannotFindAssetErrorOccurs', () => {
+ // Arrange
+ const mockStackPart = createMockStackPart('TestStack');
+ const assetError = new Error('Error: Cannot find asset at /some/path');
+
+ mockStackPart.build = jest.fn().mockImplementation(() => {
+ throw assetError;
+ });
+
+ const stackParts = [mockStackPart];
+
+ // Act
+ const action = () => stackBuilderService.buildStackParts(stackParts);
+
+ // Assert - should not throw
+ expect(action).not.toThrow();
+ expect(mockStackPart.build).toHaveBeenCalledTimes(1);
+ });
+
+ test('Should_ThrowStackBuildError_When_NonAssetErrorOccurs', () => {
+ // Arrange
+ const mockStackPart = createMockStackPart('FailingStack');
+ const buildError = new Error('Stack build failed: invalid config');
+
+ mockStackPart.build = jest.fn().mockImplementation(() => {
+ throw buildError;
+ });
+
+ const stackParts = [mockStackPart];
+
+ // Act
+ const action = () => stackBuilderService.buildStackParts(stackParts);
+
+ // Assert
+ expect(action).toThrow(StackBuildError);
+ expect(action).toThrow('Failed to build stack part: FailingStack');
+ });
+ });
+
+ /**
+ * Helper function to create a mock stack part
+ */
+ function createMockStackPart(name: string): IStackBuilder {
+ class MockStackBuilder extends IStackBuilder {
+ build = jest.fn().mockReturnValue([]);
+ getIacConfig = jest.fn();
+ formatRepoNameForCloudFormation = jest.fn().mockReturnValue(name);
+ }
+
+ Object.defineProperty(MockStackBuilder, 'name', { value: name });
+
+ return new MockStackBuilder({} as IStackBuildProps);
+ }
+});
diff --git a/src/iac/test/config/infrastructure/fileOperations/fileOperations.test.ts b/src/iac/test/config/infrastructure/fileOperations/fileOperations.test.ts
new file mode 100644
index 00000000..74777bd8
--- /dev/null
+++ b/src/iac/test/config/infrastructure/fileOperations/fileOperations.test.ts
@@ -0,0 +1,250 @@
+import fs from 'node:fs';
+import { FileOperationError } from '../../../../src/config/infrastructure/utilities/errors';
+import { FileOperations } from '../../../../src/config/infrastructure/fileOperations/fileOperations';
+
+// Mock fs module
+jest.mock('node:fs');
+
+describe('FileOperationsService', () => {
+ let fileOpsService: FileOperations;
+ let mockFs: jest.Mocked;
+
+ const originalEnv = process.env;
+
+ beforeEach(() => {
+ // Reset all mocks
+ jest.clearAllMocks();
+
+ // Reset environment variables
+ process.env = { ...originalEnv };
+ delete process.env.BUILDX_NO_DEFAULT_ATTESTATIONS;
+
+ // Get mocked fs module
+ mockFs = fs as jest.Mocked;
+
+ // Create service instance
+ fileOpsService = new FileOperations();
+ });
+
+ afterEach(() => {
+ // Restore environment
+ process.env = originalEnv;
+ });
+
+ describe('Happy Path Tests', () => {
+ test('Should_CopyFileSuccessfully_When_SourceAndDestinationValid', () => {
+ // Arrange
+ const sourcePath = '/path/to/source.txt';
+ const destPath = '/path/to/dest.txt';
+
+ mockFs.copyFileSync = jest.fn();
+
+ // Act
+ fileOpsService.copyFile(sourcePath, destPath);
+
+ // Assert
+ expect(mockFs.copyFileSync).toHaveBeenCalledWith(sourcePath, destPath);
+ expect(mockFs.copyFileSync).toHaveBeenCalledTimes(1);
+ });
+
+ test('Should_DeleteFileSuccessfully_When_FileExists', () => {
+ // Arrange
+ const filePath = '/path/to/file.txt';
+
+ mockFs.existsSync = jest.fn().mockReturnValue(true);
+ mockFs.unlinkSync = jest.fn();
+
+ // Act
+ fileOpsService.deleteFile(filePath);
+
+ // Assert
+ expect(mockFs.existsSync).toHaveBeenCalledWith(filePath);
+ expect(mockFs.unlinkSync).toHaveBeenCalledWith(filePath);
+ expect(mockFs.unlinkSync).toHaveBeenCalledTimes(1);
+ });
+
+ test('Should_NotThrowError_When_DeletingNonExistentFile', () => {
+ // Arrange
+ const filePath = '/path/to/nonexistent.txt';
+
+ mockFs.existsSync = jest.fn().mockReturnValue(false);
+ mockFs.unlinkSync = jest.fn();
+
+ // Act
+ const action = () => fileOpsService.deleteFile(filePath);
+
+ // Assert
+ expect(action).not.toThrow();
+ expect(mockFs.existsSync).toHaveBeenCalledWith(filePath);
+ expect(mockFs.unlinkSync).not.toHaveBeenCalled();
+ });
+
+ test('Should_ReturnTrue_When_FileExists', () => {
+ // Arrange
+ const filePath = '/path/to/existing.txt';
+
+ mockFs.existsSync = jest.fn().mockReturnValue(true);
+
+ // Act
+ const actual = fileOpsService.fileExists(filePath);
+
+ // Assert
+ expect(actual).toBe(true);
+ expect(mockFs.existsSync).toHaveBeenCalledWith(filePath);
+ });
+
+ test('Should_ReturnFalse_When_FileDoesNotExist', () => {
+ // Arrange
+ const filePath = '/path/to/missing.txt';
+
+ mockFs.existsSync = jest.fn().mockReturnValue(false);
+
+ // Act
+ const actual = fileOpsService.fileExists(filePath);
+
+ // Assert
+ expect(actual).toBe(false);
+ expect(mockFs.existsSync).toHaveBeenCalledWith(filePath);
+ });
+
+ test('Should_ReadFileSuccessfully_When_FileExists', () => {
+ // Arrange
+ const filePath = '/path/to/config.json';
+ const fileContent = '{"key": "value"}';
+
+ mockFs.readFileSync = jest.fn().mockReturnValue(fileContent);
+
+ // Act
+ const actual = fileOpsService.readFile(filePath);
+
+ // Assert
+ expect(actual).toBe(fileContent);
+ expect(mockFs.readFileSync).toHaveBeenCalledWith(filePath, 'utf-8');
+ });
+
+ test('Should_DisableBuildxAttestations_When_NotAlreadySet', () => {
+ // Arrange - env var not set
+
+ // Act
+ fileOpsService.disableBuildxAttestations();
+
+ // Assert
+ expect(process.env.BUILDX_NO_DEFAULT_ATTESTATIONS).toBe('1');
+ });
+ });
+
+ describe('Corner Case Tests', () => {
+ test('Should_ThrowFileOperationError_When_CopyFails', () => {
+ // Arrange
+ const sourcePath = '/path/to/source.txt';
+ const destPath = '/path/to/dest.txt';
+ const copyError = new Error('Permission denied');
+
+ mockFs.copyFileSync = jest.fn().mockImplementation(() => {
+ throw copyError;
+ });
+
+ // Act
+ const action = () => fileOpsService.copyFile(sourcePath, destPath);
+
+ // Assert
+ expect(action).toThrow(FileOperationError);
+ expect(action).toThrow(
+ `Failed to copy file from ${sourcePath} to ${destPath}`,
+ );
+ });
+
+ test('Should_ThrowFileOperationError_When_DeleteFails', () => {
+ // Arrange
+ const filePath = '/path/to/locked.txt';
+ const deleteError = new Error('File is locked');
+
+ mockFs.existsSync = jest.fn().mockReturnValue(true);
+ mockFs.unlinkSync = jest.fn().mockImplementation(() => {
+ throw deleteError;
+ });
+
+ // Act
+ const action = () => fileOpsService.deleteFile(filePath);
+
+ // Assert
+ expect(action).toThrow(FileOperationError);
+ expect(action).toThrow(`Failed to delete file ${filePath}`);
+ });
+
+ test('Should_ThrowFileOperationError_When_ReadFails', () => {
+ // Arrange
+ const filePath = '/path/to/missing.txt';
+ const readError = new Error('ENOENT: no such file or directory');
+
+ mockFs.readFileSync = jest.fn().mockImplementation(() => {
+ throw readError;
+ });
+
+ // Act
+ const action = () => fileOpsService.readFile(filePath);
+
+ // Assert
+ expect(action).toThrow(FileOperationError);
+ expect(action).toThrow(`Failed to read file ${filePath}`);
+ });
+
+ test('Should_NotOverrideEnvVar_When_BuildxAttestationsAlreadySet', () => {
+ // Arrange
+ process.env.BUILDX_NO_DEFAULT_ATTESTATIONS = '0';
+
+ // Act
+ fileOpsService.disableBuildxAttestations();
+
+ // Assert - should not override
+ expect(process.env.BUILDX_NO_DEFAULT_ATTESTATIONS).toBe('0');
+ });
+
+ test('Should_HandleNonErrorException_When_CopyThrowsNonError', () => {
+ // Arrange
+ const sourcePath = '/path/to/source.txt';
+ const destPath = '/path/to/dest.txt';
+
+ mockFs.copyFileSync = jest.fn().mockImplementation(() => {
+ throw 'String error'; // Non-Error exception
+ });
+
+ // Act
+ const action = () => fileOpsService.copyFile(sourcePath, destPath);
+
+ // Assert
+ expect(action).toThrow(FileOperationError);
+ });
+
+ test('Should_HandleNonErrorException_When_DeleteThrowsNonError', () => {
+ // Arrange
+ const filePath = '/path/to/file.txt';
+
+ mockFs.existsSync = jest.fn().mockReturnValue(true);
+ mockFs.unlinkSync = jest.fn().mockImplementation(() => {
+ throw { message: 'Object error' }; // Non-Error exception
+ });
+
+ // Act
+ const action = () => fileOpsService.deleteFile(filePath);
+
+ // Assert
+ expect(action).toThrow(FileOperationError);
+ });
+
+ test('Should_HandleNonErrorException_When_ReadThrowsNonError', () => {
+ // Arrange
+ const filePath = '/path/to/file.txt';
+
+ mockFs.readFileSync = jest.fn().mockImplementation(() => {
+ throw 123; // Non-Error exception
+ });
+
+ // Act
+ const action = () => fileOpsService.readFile(filePath);
+
+ // Assert
+ expect(action).toThrow(FileOperationError);
+ });
+ });
+});
diff --git a/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts b/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
new file mode 100644
index 00000000..6ba56840
--- /dev/null
+++ b/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
@@ -0,0 +1,99 @@
+import { ConsoleDeploymentLogger } from '../../../../src/config/infrastructure/logging/consoleDeploymentLogger';
+import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
+import type { IProjectPath } from '../../../../src/config/domain/ports/iProjectPath';
+import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+
+describe('ConsoleDeploymentLogger', () => {
+ let consoleLogSpy: jest.SpyInstance;
+ let consoleErrorSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
+ });
+
+ afterEach(() => {
+ consoleLogSpy.mockRestore();
+ consoleErrorSpy.mockRestore();
+ });
+
+ const createMockConfig = (): IDeploymentRequest => ({
+ repoName: 'test-repo',
+ branch: 'main',
+ vpcId: 'vpc-123',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'example.com',
+ certificateId: 'cert-123',
+ hostedZoneId: 'zone-123',
+ },
+ stacks: {
+ frontend: {
+ staticWebsites: [
+ {
+ name: 'Website',
+ subdomain: 'www.test',
+ projectPath: 'apps/website',
+ },
+ ],
+ },
+ shared: {},
+ },
+ });
+
+ const createMockPathResolver = (): IProjectPath => ({
+ getRootPath: () => '/root/project',
+ resolveFullPath: (path: string) => `/root/project/${path}`,
+ generateDockerfileDest: (path: string) => `${path}/Dockerfile`,
+ });
+
+ describe('displayDeploymentInfo', () => {
+ it('Should_LogAllStacksInformation_When_Called', () => {
+ const logger = new ConsoleDeploymentLogger();
+ const config = createMockConfig();
+ const pathResolver = createMockPathResolver();
+
+ logger.displayDeploymentInfo(
+ config,
+ pathResolver,
+ 'us-east-1',
+ '123456789012',
+ );
+
+ expect(consoleLogSpy).toHaveBeenCalledWith(
+ expect.stringContaining('[test-repo]'),
+ );
+ expect(consoleLogSpy).toHaveBeenCalledWith('Region: us-east-1');
+ expect(consoleLogSpy).toHaveBeenCalledWith('Account: ***9012');
+ });
+ });
+
+ describe('logRepositoryInfo', () => {
+ it('Should_LogRepositoryUrl_When_Called', () => {
+ const logger = new ConsoleDeploymentLogger();
+
+ logger.logRepositoryInfo('test-repo', 'feature-branch');
+
+ expect(consoleLogSpy).toHaveBeenCalledWith(
+ expect.stringContaining(
+ '🔌 Repository source https://github.com/macalbert/test-repo/tree/feature-branch',
+ ),
+ );
+ });
+ });
+
+ describe('logError', () => {
+ it('Should_LogFormattedError_When_Called', () => {
+ const logger = new ConsoleDeploymentLogger();
+ const error = new Error('Test error');
+ error.stack = 'Error: Test error\n at test.js:1:1';
+
+ logger.logError(error);
+
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ expect.stringContaining('❌ Error: Test error'),
+ );
+ expect(consoleErrorSpy).toHaveBeenCalledWith(error.stack);
+ });
+ });
+});
diff --git a/src/iac/test/config/infrastructure/projectPath/fileProjectPath.test.ts b/src/iac/test/config/infrastructure/projectPath/fileProjectPath.test.ts
new file mode 100644
index 00000000..88ca756d
--- /dev/null
+++ b/src/iac/test/config/infrastructure/projectPath/fileProjectPath.test.ts
@@ -0,0 +1,172 @@
+import { FileProjectPath } from '../../../../src/config/infrastructure/projectPath/fileProjectPath';
+
+describe('FileSystemPath', () => {
+ describe('constructor', () => {
+ test('Should_UseCustomRootPath_When_RootPathProvided', () => {
+ // Arrange
+ const customPath = '/custom/path';
+
+ // Act
+ const config = new FileProjectPath(customPath);
+
+ // Assert
+ expect(config.getRootPath()).toBe(customPath);
+ });
+ });
+
+ describe('getRootPath', () => {
+ test('Should_ReturnRootPath_When_Called', () => {
+ // Arrange
+ const rootPath = '/test/root';
+ const config = new FileProjectPath(rootPath);
+
+ // Act
+ const result = config.getRootPath();
+
+ // Assert
+ expect(result).toBe(rootPath);
+ });
+ });
+
+ describe('generateDockerfileDest', () => {
+ test('Should_GenerateKebabCaseName_When_StandardPathProvided', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src/apps/Minimal.Api/Dockerfile';
+
+ // Act
+ const result = config.generateDockerfileDest(projectPath);
+
+ // Assert
+ expect(result).toBe('Dockerfile.minimal-api');
+ });
+
+ test('Should_ConvertPascalCaseToKebabCase_When_AppNameInPascalCase', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src/apps/WorkerService/Dockerfile';
+
+ // Act
+ const result = config.generateDockerfileDest(projectPath);
+
+ // Assert
+ expect(result).toBe('Dockerfile.worker-service');
+ });
+
+ test('Should_HandleDotSeparators_When_AppNameContainsDots', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src/apps/My.Test.App/Dockerfile';
+
+ // Act
+ const result = config.generateDockerfileDest(projectPath);
+
+ // Assert
+ expect(result).toBe('Dockerfile.my-test-app');
+ });
+
+ test('Should_HandleUnderscores_When_AppNameContainsUnderscores', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src/apps/My_Test_App/Dockerfile';
+
+ // Act
+ const result = config.generateDockerfileDest(projectPath);
+
+ // Assert
+ expect(result).toBe('Dockerfile.my-test-app');
+ });
+
+ test('Should_HandleBackslashes_When_WindowsPathProvided', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src\\apps\\Minimal.Api\\Dockerfile';
+
+ // Act
+ const result = config.generateDockerfileDest(projectPath);
+
+ // Assert
+ expect(result).toBe('Dockerfile.minimal-api');
+ });
+
+ test('Should_ThrowError_When_AppsSegmentNotFound', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src/services/MyService/Dockerfile';
+
+ // Act & Assert
+ expect(() => config.generateDockerfileDest(projectPath)).toThrow(
+ 'Cannot extract app name from project path',
+ );
+ });
+
+ test('Should_ThrowError_When_AppsSegmentIsLast', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src/apps';
+
+ // Act & Assert
+ expect(() => config.generateDockerfileDest(projectPath)).toThrow(
+ 'Cannot extract app name from project path',
+ );
+ });
+
+ test('Should_HandleComplexAppName_When_MultipleCapitalLetters', () => {
+ // Arrange
+ const config = new FileProjectPath('test-repo');
+ const projectPath = 'src/apps/APIGatewayService/Dockerfile';
+
+ // Act
+ const result = config.generateDockerfileDest(projectPath);
+
+ // Assert
+ expect(result).toBe('Dockerfile.apigateway-service');
+ });
+ });
+
+ describe('resolveFullPath', () => {
+ test('Should_ResolveFullPath_When_RelativePathProvided', () => {
+ // Arrange
+ const rootPath = '/root/path';
+ const config = new FileProjectPath(rootPath);
+ const projectPath = 'ProjectDir/src/apps/frontend/dist';
+
+ // Act
+ const result = config.resolveFullPath(projectPath);
+ const normalizedResult = result.replace(/\\/g, '/');
+
+ // Assert
+ expect(normalizedResult).toBe(
+ '/root/path/ProjectDir/src/apps/frontend/dist',
+ );
+ });
+
+ test('Should_CombinePathsCorrectly_When_Called', () => {
+ // Arrange
+ const rootPath = '/custom/root';
+ const config = new FileProjectPath(rootPath);
+ const projectPath = 'ProjectDir/src/web/dist';
+
+ // Act
+ const result = config.resolveFullPath(projectPath);
+ const normalizedResult = result.replace(/\\/g, '/');
+
+ // Assert
+ expect(normalizedResult).toBe('/custom/root/ProjectDir/src/web/dist');
+ });
+
+ test('Should_HandleEmptyProjectPath_When_EmptyStringProvided', () => {
+ // Arrange
+ const rootPath = '/root';
+ const config = new FileProjectPath(rootPath);
+ const projectPath = '';
+
+ // Act
+ const result = config.resolveFullPath(projectPath);
+
+ // Assert
+ expect(result).toBeDefined();
+ expect(result.replace(/\\/g, '/')).toBe('/root');
+ });
+ });
+});
diff --git a/src/iac/test/config/infrastructure/utilities/cloudFormationUtils.test.ts b/src/iac/test/config/infrastructure/utilities/cloudFormationUtils.test.ts
new file mode 100644
index 00000000..26e5d112
--- /dev/null
+++ b/src/iac/test/config/infrastructure/utilities/cloudFormationUtils.test.ts
@@ -0,0 +1,176 @@
+import { formatRepoNameForCloudFormation } from '../../../../src/config/infrastructure/utilities/cloudFormationUtils';
+
+describe('cloudFormationUtils', () => {
+ describe('formatRepoNameForCloudFormation', () => {
+ test('Should_ReturnFormattedName_When_ValidRepoNameProvided', () => {
+ // Arrange
+ const repoName = 'my-test-repo';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('my-test-repo');
+ });
+
+ test('Should_ConvertToLowercase_When_UppercaseLettersProvided', () => {
+ // Arrange
+ const repoName = 'MyTestRepo';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('mytestrepo');
+ });
+
+ test('Should_ReplaceSpecialCharsWithHyphen_When_InvalidCharsPresent', () => {
+ // Arrange
+ const repoName = 'my_test@repo#2024';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('my-test-repo-2024');
+ });
+
+ test('Should_ReplaceMultipleHyphensWithSingle_When_ConsecutiveHyphensExist', () => {
+ // Arrange
+ const repoName = 'my---test---repo';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('my-test-repo');
+ });
+
+ test('Should_RemoveLeadingHyphen_When_NameStartsWithHyphen', () => {
+ // Arrange
+ const repoName = '-my-repo';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('my-repo');
+ });
+
+ test('Should_RemoveTrailingHyphen_When_NameEndsWithHyphen', () => {
+ // Arrange
+ const repoName = 'my-repo-';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('my-repo');
+ });
+
+ test('Should_PrefixWithR_When_RepoNameStartsWithNumber', () => {
+ // Arrange
+ const repoName = '123-repo';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('r-123-repo');
+ expect(result).toMatch(/^[A-Za-z]/);
+ });
+
+ test('Should_HandleComplexName_When_MultipleRulesApply', () => {
+ // Arrange
+ const repoName = '123_My@Test___Repo---2024!';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('r-123-my-test-repo-2024');
+ expect(result).toMatch(/^[A-Za-z][A-Za-z0-9-]*$/);
+ });
+
+ test('Should_HandleUnderscores_When_RepoNameContainsUnderscores', () => {
+ // Arrange
+ const repoName = 'my_awesome_repo';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('my-awesome-repo');
+ });
+
+ test('Should_HandleDots_When_RepoNameContainsDots', () => {
+ // Arrange
+ const repoName = 'my.test.repo';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('my-test-repo');
+ });
+
+ test('Should_ReturnValidCloudFormationName_When_AllRulesApplied', () => {
+ // Arrange
+ const repoName = '!!!Test___Repo@2024###';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toMatch(/^[A-Za-z][A-Za-z0-9-]*$/);
+ expect(result).toBe('test-repo-2024');
+ });
+
+ test('Should_HandleSingleCharacter_When_NameIsOneLetter', () => {
+ // Arrange
+ const repoName = 'A';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('a');
+ });
+
+ test('Should_HandleNumericOnly_When_NameIsAllNumbers', () => {
+ // Arrange
+ const repoName = '123456';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('r-123456');
+ expect(result).toMatch(/^[A-Za-z]/);
+ });
+
+ test('Should_HandleSpecialCharsOnly_When_NameHasNoAlphanumeric', () => {
+ // Arrange
+ const repoName = '@#$%^&*';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ // After removing all special chars and hyphens, we get an empty string
+ // which then gets prefixed with 'r-' since it doesn't start with a letter
+ expect(result).toBe('r-');
+ });
+
+ test('Should_HandleMixedCase_When_NameHasMixedCasing', () => {
+ // Arrange
+ const repoName = 'MyRepoName';
+
+ // Act
+ const result = formatRepoNameForCloudFormation(repoName);
+
+ // Assert
+ expect(result).toBe('myreponame');
+ });
+ });
+});
diff --git a/src/iac/test/config/infrastructure/utilities/errors.test.ts b/src/iac/test/config/infrastructure/utilities/errors.test.ts
new file mode 100644
index 00000000..316e7e80
--- /dev/null
+++ b/src/iac/test/config/infrastructure/utilities/errors.test.ts
@@ -0,0 +1,298 @@
+import {
+ DeploymentError,
+ FileOperationError,
+ EcrAuthError,
+ StackBuildError,
+ ConfigValidationError,
+} from '../../../../src/config/infrastructure/utilities/errors';
+
+describe('DeploymentError', () => {
+ test('Should_CreateDeploymentError_When_MessageProvided', () => {
+ // Arrange
+ const message = 'Deployment failed';
+
+ // Act
+ const error = new DeploymentError(message);
+
+ // Assert
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(DeploymentError);
+ expect(error.message).toBe(message);
+ expect(error.name).toBe('DeploymentError');
+ });
+
+ test('Should_HaveStackTrace_When_ErrorCreated', () => {
+ // Arrange
+ const message = 'Deployment failed';
+
+ // Act
+ const error = new DeploymentError(message);
+
+ // Assert
+ expect(error.stack).toBeDefined();
+ expect(error.stack).toContain('DeploymentError');
+ });
+
+ test('Should_CreateDeploymentError_When_CauseProvided', () => {
+ // Arrange
+ const message = 'Deployment failed';
+ const cause = new Error('Original error');
+
+ // Act
+ const error = new DeploymentError(message, cause);
+
+ // Assert
+ expect(error.message).toBe(message);
+ expect(error.name).toBe('DeploymentError');
+ expect(error.cause).toBe(cause);
+ });
+});
+
+describe('FileOperationError', () => {
+ test('Should_CreateFileOperationError_When_MessageAndFilePathProvided', () => {
+ // Arrange
+ const message = 'Failed to read file';
+ const filePath = '/path/to/file.txt';
+
+ // Act
+ const error = new FileOperationError(message, filePath);
+
+ // Assert
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(DeploymentError);
+ expect(error).toBeInstanceOf(FileOperationError);
+ expect(error.message).toBe(message);
+ expect(error.filePath).toBe(filePath);
+ expect(error.name).toBe('FileOperationError');
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_CreateFileOperationError_When_CauseProvided', () => {
+ // Arrange
+ const message = 'Failed to read file';
+ const filePath = '/path/to/file.txt';
+ const cause = new Error('ENOENT: no such file or directory');
+
+ // Act
+ const error = new FileOperationError(message, filePath, cause);
+
+ // Assert
+ expect(error.message).toBe(message);
+ expect(error.filePath).toBe(filePath);
+ expect(error.name).toBe('FileOperationError');
+ expect(error.cause).toBe(cause);
+ });
+
+ test('Should_StoreFilePath_When_ErrorCreated', () => {
+ // Arrange
+ const message = 'File operation failed';
+ const filePath = 'C:\\Users\\test\\file.json';
+
+ // Act
+ const error = new FileOperationError(message, filePath);
+
+ // Assert
+ expect(error.filePath).toBe(filePath);
+ });
+});
+
+describe('EcrAuthError', () => {
+ test('Should_CreateEcrAuthError_When_MessageProvided', () => {
+ // Arrange
+ const message = 'ECR authentication failed';
+
+ // Act
+ const error = new EcrAuthError(message);
+
+ // Assert
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(DeploymentError);
+ expect(error).toBeInstanceOf(EcrAuthError);
+ expect(error.message).toBe(message);
+ expect(error.name).toBe('EcrAuthError');
+ expect(error.region).toBeUndefined();
+ expect(error.account).toBeUndefined();
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_CreateEcrAuthError_When_RegionAndAccountProvided', () => {
+ // Arrange
+ const message = 'ECR authentication failed';
+ const region = 'us-east-1';
+ const account = '123456789012';
+
+ // Act
+ const error = new EcrAuthError(message, region, account);
+
+ // Assert
+ expect(error.message).toBe(message);
+ expect(error.region).toBe(region);
+ expect(error.account).toBe(account);
+ expect(error.name).toBe('EcrAuthError');
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_CreateEcrAuthError_When_CauseProvided', () => {
+ // Arrange
+ const message = 'ECR authentication failed';
+ const region = 'eu-west-1';
+ const account = '987654321098';
+ const cause = new Error('AWS CLI not found');
+
+ // Act
+ const error = new EcrAuthError(message, region, account, cause);
+
+ // Assert
+ expect(error.message).toBe(message);
+ expect(error.region).toBe(region);
+ expect(error.account).toBe(account);
+ expect(error.name).toBe('EcrAuthError');
+ expect(error.cause).toBe(cause);
+ });
+
+ test('Should_StoreRegionAndAccount_When_Provided', () => {
+ // Arrange
+ const message = 'Failed to authenticate';
+ const region = 'ap-southeast-1';
+ const account = '111222333444';
+
+ // Act
+ const error = new EcrAuthError(message, region, account);
+
+ // Assert
+ expect(error.region).toBe(region);
+ expect(error.account).toBe(account);
+ expect(error.cause).toBeUndefined();
+ });
+});
+
+describe('StackBuildError', () => {
+ test('Should_CreateStackBuildError_When_MessageProvided', () => {
+ // Arrange
+ const message = 'Stack build failed';
+
+ // Act
+ const error = new StackBuildError(message);
+
+ // Assert
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(DeploymentError);
+ expect(error).toBeInstanceOf(StackBuildError);
+ expect(error.message).toBe(message);
+ expect(error.name).toBe('StackBuildError');
+ expect(error.stackName).toBeUndefined();
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_CreateStackBuildError_When_StackNameProvided', () => {
+ // Arrange
+ const message = 'Failed to build stack';
+ const stackName = 'BackendStack-Lambda-Api';
+
+ // Act
+ const error = new StackBuildError(message, stackName);
+
+ // Assert
+ expect(error.message).toBe(message);
+ expect(error.stackName).toBe(stackName);
+ expect(error.name).toBe('StackBuildError');
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_CreateStackBuildError_When_CauseProvided', () => {
+ // Arrange
+ const message = 'Stack synthesis failed';
+ const stackName = 'FrontendStack-Website';
+ const cause = new Error('Invalid construct');
+
+ // Act
+ const error = new StackBuildError(message, stackName, cause);
+
+ // Assert
+ expect(error.message).toBe(message);
+ expect(error.stackName).toBe(stackName);
+ expect(error.name).toBe('StackBuildError');
+ expect(error.cause).toBe(cause);
+ });
+
+ test('Should_StoreStackName_When_Provided', () => {
+ // Arrange
+ const message = 'Build error';
+ const stackName = 'SharedStack-RDS';
+
+ // Act
+ const error = new StackBuildError(message, stackName);
+
+ // Assert
+ expect(error.stackName).toBe(stackName);
+ expect(error.cause).toBeUndefined();
+ });
+});
+
+describe('ConfigValidationError', () => {
+ test('Should_CreateConfigValidationError_When_MessageAndErrorsProvided', () => {
+ // Arrange
+ const message = 'Configuration validation failed';
+ const validationErrors = ['Field1 is required', 'Field2 is invalid'];
+
+ // Act
+ const error = new ConfigValidationError(message, validationErrors);
+
+ // Assert
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(DeploymentError);
+ expect(error).toBeInstanceOf(ConfigValidationError);
+ expect(error.message).toBe(message);
+ expect(error.validationErrors).toBe(validationErrors);
+ expect(error.name).toBe('ConfigValidationError');
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_StoreValidationErrors_When_ErrorCreated', () => {
+ // Arrange
+ const message = 'Validation failed with 3 errors';
+ const validationErrors = [
+ 'repoName is required',
+ 'vpcId is required',
+ 'domain.name is required',
+ ];
+
+ // Act
+ const error = new ConfigValidationError(message, validationErrors);
+
+ // Assert
+ expect(error.validationErrors).toEqual(validationErrors);
+ expect(error.validationErrors).toHaveLength(3);
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_CreateConfigValidationError_When_EmptyErrorsArray', () => {
+ // Arrange
+ const message = 'No errors';
+ const validationErrors: string[] = [];
+
+ // Act
+ const error = new ConfigValidationError(message, validationErrors);
+
+ // Assert
+ expect(error.validationErrors).toEqual([]);
+ expect(error.validationErrors).toHaveLength(0);
+ expect(error.cause).toBeUndefined();
+ });
+
+ test('Should_CreateConfigValidationError_When_SingleError', () => {
+ // Arrange
+ const message = 'Validation failed with 1 error';
+ const validationErrors = ['repoName is required and cannot be empty'];
+
+ // Act
+ const error = new ConfigValidationError(message, validationErrors);
+
+ // Assert
+ expect(error.validationErrors).toHaveLength(1);
+ expect(error.validationErrors[0]).toBe(
+ 'repoName is required and cannot be empty',
+ );
+ expect(error.cause).toBeUndefined();
+ });
+});
diff --git a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
new file mode 100644
index 00000000..c2c718d0
--- /dev/null
+++ b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
@@ -0,0 +1,160 @@
+import { Stack } from 'aws-cdk-lib';
+import { Template } from 'aws-cdk-lib/assertions';
+
+interface CloudFormationFunction {
+ 'Fn::Sub'?: string;
+ [key: string]: unknown;
+}
+
+interface LambdaFunctionCode {
+ ImageUri: string | CloudFormationFunction;
+ [key: string]: unknown;
+}
+
+interface LambdaFunctionProperties {
+ Code?: LambdaFunctionCode;
+ [key: string]: unknown;
+}
+
+interface CloudFormationResource {
+ Properties?: LambdaFunctionProperties;
+ Image?: string;
+ 'Fn::Join'?: [string, Array];
+ [key: string]: unknown;
+}
+
+export interface CloudFormationTemplate {
+ Resources?: Record;
+ [key: string]: unknown;
+}
+
+type CloudFormationValue =
+ | string
+ | number
+ | boolean
+ | null
+ | undefined
+ | CloudFormationObject
+ | CloudFormationArray;
+type CloudFormationObject = { [key: string]: CloudFormationValue };
+type CloudFormationArray = Array;
+
+export function normalizeDockerImageReferences(
+ input: Stack | Template | CloudFormationTemplate,
+): CloudFormationTemplate {
+ let templateJson: CloudFormationTemplate;
+
+ if (input instanceof Stack) {
+ templateJson = Template.fromStack(input).toJSON();
+ } else if (input instanceof Template) {
+ templateJson = input.toJSON();
+ } else {
+ templateJson = input;
+ }
+
+ const normalizedTemplate: CloudFormationTemplate = JSON.parse(
+ JSON.stringify(templateJson),
+ );
+
+ if (normalizedTemplate.Resources) {
+ for (const resourceKey in normalizedTemplate.Resources) {
+ const resource = normalizedTemplate.Resources[resourceKey];
+ normalizeImageUriIfPresent(resource);
+ normalizeAllDockerHashesRecursively(resource as CloudFormationObject);
+ }
+ }
+
+ return normalizedTemplate;
+}
+
+function normalizeImageUriIfPresent(
+ lambdaResource: CloudFormationResource,
+): void {
+ const properties = lambdaResource.Properties;
+ if (!properties?.Code?.ImageUri) {
+ return;
+ }
+
+ const imageUriContainer = properties.Code;
+
+ if (typeof imageUriContainer.ImageUri === 'string') {
+ imageUriContainer.ImageUri = 'IMAGE_URI_PLACEHOLDER';
+ } else if (imageUriContainer.ImageUri['Fn::Sub']) {
+ const normalizedEcrPath =
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: CloudFormation intrinsic function syntax
+ '${AWS::AccountId}.dkr.ecr.${AWS::Region}.${AWS::URLSuffix}/cdk-container-assets-NORMALIZED_HASH';
+ imageUriContainer.ImageUri['Fn::Sub'] = normalizedEcrPath;
+ }
+}
+
+function normalizeAllDockerHashesRecursively(
+ value: CloudFormationObject | CloudFormationArray,
+): void {
+ if (!value || typeof value !== 'object') {
+ return;
+ }
+
+ if (Array.isArray(value)) {
+ normalizeArrayValues(value);
+ } else {
+ normalizeObjectValues(value);
+ }
+}
+
+function normalizeArrayValues(array: CloudFormationArray): void {
+ for (let i = 0; i < array.length; i++) {
+ const item = array[i];
+
+ if (typeof item === 'string' && isDockerImageHash(item)) {
+ array[i] = ':NORMALIZED_DOCKER_HASH';
+ } else if (item && typeof item === 'object') {
+ normalizeAllDockerHashesRecursively(
+ item as CloudFormationObject | CloudFormationArray,
+ );
+ }
+ }
+}
+
+function normalizeObjectValues(obj: CloudFormationObject): void {
+ normalizeImageProperty(obj);
+ normalizeFnJoinExpression(obj);
+
+ for (const key in obj) {
+ if (Object.hasOwn(obj, key) && obj[key] && typeof obj[key] === 'object') {
+ normalizeAllDockerHashesRecursively(
+ obj[key] as CloudFormationObject | CloudFormationArray,
+ );
+ }
+ }
+}
+
+function normalizeImageProperty(obj: CloudFormationObject): void {
+ if (typeof obj.Image === 'string' && isContainerImage(obj.Image)) {
+ obj.Image = obj.Image.replace(/:[a-f0-9]{64}/i, ':NORMALIZED_HASH');
+ }
+}
+
+function normalizeFnJoinExpression(obj: CloudFormationObject): void {
+ const fnJoin = obj['Fn::Join'];
+ if (!fnJoin || !Array.isArray(fnJoin) || !Array.isArray(fnJoin[1])) {
+ return;
+ }
+
+ const joinParts = fnJoin[1];
+ for (let i = 0; i < joinParts.length; i++) {
+ const part = joinParts[i];
+
+ if (typeof part === 'string' && isDockerImageHash(part)) {
+ joinParts[i] = ':NORMALIZED_DOCKER_HASH';
+ }
+ }
+}
+
+function isDockerImageHash(value: string): boolean {
+ const dockerHashPattern = /^:[a-f0-9]{64}$/i;
+ return dockerHashPattern.test(value);
+}
+
+function isContainerImage(value: string): boolean {
+ return value.includes('dkr.ecr') && /:[a-f0-9]{64}/i.test(value);
+}
diff --git a/src/iac/test/config/infrastructure/validation/configValidator.test.ts b/src/iac/test/config/infrastructure/validation/configValidator.test.ts
new file mode 100644
index 00000000..bee08133
--- /dev/null
+++ b/src/iac/test/config/infrastructure/validation/configValidator.test.ts
@@ -0,0 +1,288 @@
+import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+import { ConfigValidator } from '../../../../src/config/domain/validation/configValidator';
+import { ConfigValidationError } from '../../../../src/config/infrastructure/utilities/errors';
+
+describe('ConfigValidator', () => {
+ let validator: ConfigValidator;
+
+ beforeEach(() => {
+ validator = new ConfigValidator();
+ });
+
+ function createValidConfig(): IDeploymentRequest {
+ return {
+ repoName: 'test-repo',
+ vpcId: 'vpc-12345678',
+ branch: 'main',
+ environment: AppEnvironment.Production,
+ domain: {
+ name: 'example.com',
+ certificateId: 'cert-123456',
+ hostedZoneId: 'Z123456789',
+ },
+ stacks: {
+ frontend: {
+ staticWebsites: [],
+ },
+ shared: {
+ pipeline: [],
+ },
+ },
+ };
+ }
+
+ test('Should_PassValidation_When_AllRequiredFieldsProvided', () => {
+ // Arrange
+ const config = createValidConfig();
+
+ // Act & Assert
+ expect(() => validator.validate(config)).not.toThrow();
+ });
+
+ test('Should_PassValidation_When_ValidConfigWithFrontendStacks', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.stacks.frontend.staticWebsites = [
+ { name: 'web-app', projectPath: './src/web', subdomain: 'www' },
+ ];
+
+ // Act & Assert
+ expect(() => validator.validate(config)).not.toThrow();
+ });
+
+ test('Should_ThrowConfigValidationError_When_RepoNameMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.repoName = '';
+
+ // Act & Assert
+ expect(() => validator.validate(config)).toThrow(ConfigValidationError);
+ expect(() => validator.validate(config)).toThrow(
+ 'Configuration validation failed with 1 error(s)',
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_VpcIdMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.vpcId = '';
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'vpcId is required and cannot be empty',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_BranchMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.branch = ' ';
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'branch is required and cannot be empty',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_DomainConfigMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ // biome-ignore lint/suspicious/noExplicitAny: testing null config
+ config.domain = null as any;
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'domain configuration is required',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_DomainNameMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.domain.name = '';
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'domain.name is required and cannot be empty',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_DomainCertificateIdMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.domain.certificateId = '';
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'domain.certificateId is required and cannot be empty',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_DomainHostedZoneIdMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.domain.hostedZoneId = '';
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'domain.hostedZoneId is required and cannot be empty',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_StacksConfigMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ // biome-ignore lint/suspicious/noExplicitAny: testing null config
+ config.stacks = null as any;
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'stacks configuration is required',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_FrontendConfigMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ // biome-ignore lint/suspicious/noExplicitAny: testing null config
+ config.stacks.frontend = null as any;
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'stacks.frontend is required',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_StaticWebsiteNameMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.stacks.frontend.staticWebsites = [
+ { name: '', projectPath: './src/web', subdomain: 'www' },
+ ];
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'frontend.staticWebsites[0].name is required',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_StaticWebsiteSubdomainMissing', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.stacks.frontend.staticWebsites = [
+ { name: 'web', projectPath: './src/web', subdomain: '' },
+ ];
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'frontend.staticWebsites[0].subdomain is required',
+ ]),
+ }),
+ );
+ });
+
+ test('Should_ThrowConfigValidationError_When_MultipleErrorsExist', () => {
+ // Arrange
+ const config = createValidConfig();
+ config.repoName = '';
+ config.vpcId = '';
+ config.branch = '';
+ config.domain.name = '';
+
+ // Act
+ const act = () => validator.validate(config);
+
+ // Assert
+ expect(act).toThrow(ConfigValidationError);
+ expect(act).toThrow('Configuration validation failed with 4 error(s)');
+ expect(act).toThrow(
+ expect.objectContaining({
+ validationErrors: expect.arrayContaining([
+ 'repoName is required and cannot be empty',
+ 'vpcId is required and cannot be empty',
+ 'branch is required and cannot be empty',
+ 'domain.name is required and cannot be empty',
+ ]),
+ }),
+ );
+ });
+});
diff --git a/src/iac/tsconfig.json b/src/iac/tsconfig.json
new file mode 100644
index 00000000..1462ee0b
--- /dev/null
+++ b/src/iac/tsconfig.json
@@ -0,0 +1,55 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "Node16",
+ "lib": [
+ "es2020",
+ "dom"
+ ],
+ "removeComments": true,
+ "declaration": true,
+ "strict": true,
+ "noImplicitAny": true,
+ "strictNullChecks": true,
+ "noImplicitThis": true,
+ "alwaysStrict": true,
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": false,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "experimentalDecorators": true,
+ "strictPropertyInitialization": false,
+ "typeRoots": [
+ "../../node_modules/@types",
+ "./node_modules/@types"
+ ],
+ "types": [
+ "node",
+ "jest"
+ ],
+ "outDir": "dist",
+ "esModuleInterop": true,
+ "composite": true,
+ "paths": {
+ "@envilder/shared-iac": [
+ "./node_modules/@envilder/shared-iac"
+ ]
+ },
+ "resolveJsonModule": true,
+ "moduleResolution": "node16",
+ "isolatedModules": true,
+ "skipLibCheck": true
+ },
+ "include": [
+ "bin",
+ "lib",
+ "**/*.ts"
+ ],
+ "exclude": [
+ "node_modules",
+ "cdk.out",
+ "dist"
+ ]
+}
\ No newline at end of file
From 915e0f9aa46b3e410185a5c1082181cc2e94f57a Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 15:04:00 +0100
Subject: [PATCH 03/49] refactor(tests): Remove shared stack references from
tests
Removed references to shared stacks in various test files to simplify the test structure and focus on frontend stack configurations.
---
.../codepipeline/pipelineStack.ts | 579 --
.../models/deploymentRequest.ts | 12 +-
.../builders/factories/stackBuilderFactory.ts | 11 -
.../config/domain/builders/sharedBuilder.ts | 65 -
.../config/domain/model/deploymentConfig.ts | 3 +-
.../src/config/domain/model/stackConfig.ts | 15 -
src/iac/src/infra/buildspecs/test/iac.yml | 28 -
src/iac/src/infra/config/sharedConfig.ts | 16 -
src/iac/src/infra/iacConfig.ts | 2 -
.../__snapshots__/pipelineStack.test.ts.snap | 8927 -----------------
.../aws/developerTools/pipelineStack.test.ts | 181 -
.../deployInfrastructureHandler.test.ts | 4 -
.../factories/stackBuilderFactory.test.ts | 71 +-
.../domain/builders/frontendBuilder.test.ts | 1 -
.../domain/builders/sharedBuilder.test.ts | 83 -
.../test/config/domain/iStackBuilder.test.ts | 1 -
.../logging/consoleDeploymentLogger.test.ts | 1 -
.../utilities/templateNormalizer.ts | 6 +-
.../validation/configValidator.test.ts | 3 -
19 files changed, 8 insertions(+), 10001 deletions(-)
delete mode 100644 src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts
delete mode 100644 src/iac/src/config/domain/builders/sharedBuilder.ts
delete mode 100644 src/iac/src/infra/buildspecs/test/iac.yml
delete mode 100644 src/iac/src/infra/config/sharedConfig.ts
delete mode 100644 src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap
delete mode 100644 src/iac/test/aws/developerTools/pipelineStack.test.ts
delete mode 100644 src/iac/test/config/domain/builders/sharedBuilder.test.ts
diff --git a/src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts b/src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts
deleted file mode 100644
index d66d0d24..00000000
--- a/src/iac/src/aws/developerTools/codepipeline/pipelineStack.ts
+++ /dev/null
@@ -1,579 +0,0 @@
-import * as path from 'node:path';
-import {
- Duration,
- type Environment,
- type RemovalPolicy,
- SecretValue,
- aws_codebuild,
-} from 'aws-cdk-lib';
-import {
- BuildSpec,
- LinuxBuildImage,
- PipelineProject,
-} from 'aws-cdk-lib/aws-codebuild';
-import {
- Artifact,
- Pipeline,
- PipelineType,
- type StageProps,
-} from 'aws-cdk-lib/aws-codepipeline';
-import {
- CodeBuildAction,
- GitHubSourceAction,
- GitHubTrigger,
- ManualApprovalAction,
-} from 'aws-cdk-lib/aws-codepipeline-actions';
-import { DetailType } from 'aws-cdk-lib/aws-codestarnotifications';
-import type { IVpc } from 'aws-cdk-lib/aws-ec2';
-import {
- ArnPrincipal,
- PolicyDocument,
- PolicyStatement,
- Role,
- ServicePrincipal,
-} from 'aws-cdk-lib/aws-iam';
-import { SlackChannelConfiguration } from 'aws-cdk-lib/aws-chatbot';
-import { Key } from 'aws-cdk-lib/aws-kms';
-import { Bucket } from 'aws-cdk-lib/aws-s3';
-import { Topic } from 'aws-cdk-lib/aws-sns';
-import { EmailSubscription } from 'aws-cdk-lib/aws-sns-subscriptions';
-import type { Construct } from 'constructs';
-import type { AppEnvironment } from '../../../config/domain/model/appEnvironment';
-import { formatRepoNameForCloudFormation } from '../../../config/infrastructure/utilities/cloudFormationUtils';
-import {
- type CustomStackProps,
- CustomStack,
-} from '../../../config/domain/customStack';
-
-/**
- * Cache configuration types for CodeBuild projects
- */
-export type CacheConfig =
- | { type: 'none' }
- | { type: 'local' }
- | { type: 's3'; bucketName?: string };
-
-export interface PipelineStackProps extends CustomStackProps {
- branch: string;
- githubRepo: string;
- envName: AppEnvironment;
- domain: string;
- secretTokenArn: string;
- deployBuildSpec: string[];
- testBuildSpec: string[];
- vpc: IVpc;
- testProjectName: string;
- bucketRemovalPolicy: RemovalPolicy;
- environment?: object;
- filterPaths?: string[];
- manualApproval?: boolean;
- emailNotification?: string;
- slackChannelConfigurationName?: string;
- cacheConfig?: CacheConfig;
-}
-
-/**
- * PipelineStack defines a complete CI/CD pipeline using AWS CodePipeline, CodeBuild, and CodeDeploy.
- *
- * The stack creates source actions from GitHub, test and deploy actions based on provided buildspec files,
- * and configures notifications for pipeline state changes. It also creates the necessary IAM roles for pipeline,
- * test, and deploy stages, and sets up Slack and email notifications based on manual approval settings.
- *
- * @example
- * const pipelineStack = new PipelineStack(app, {
- * branch: "main",
- * githubRepo: "my-repo",
- * envName: AppEnvironment.PROD,
- * domain: "example.com",
- * secretTokenArn: "arn:aws:secretsmanager:...",
- * deployBuildSpec: ["deploy/buildspec.yml"],
- * testBuildSpec: ["test/buildspec.yml"],
- * vpc: myVpc,
- * testProjectName: "MyTestProject",
- * bucketRemovalPolicy: RemovalPolicy.DESTROY,
- * environment: { CUSTOM_VAR: { value: "value" } },
- * filterPaths: ["src/**"],
- * manualApproval: true,
- * // plus additional CustomStackProps...
- * });
- */
-export class PipelineStack extends CustomStack {
- readonly githubOwner: string = 'macalbert';
-
- /**
- * Constructs a new instance of PipelineStack.
- *
- * The constructor sets up the pipeline by creating the source, test, deploy stages, and notifications.
- * It creates separate IAM roles for the pipeline, test, and deploy actions, and uses a pre-existing artifact bucket.
- *
- * @param scope - The scope in which this stack is defined.
- * @param props - The properties for configuring the pipeline.
- */
- constructor(scope: Construct, props: PipelineStackProps) {
- super(scope, props);
-
- const pipelineRole = this.createPipelineRole(props, 'pipeline');
-
- const pipelineRoleTest = this.createPipelineRole(
- props,
- 'test',
- new ArnPrincipal(pipelineRole.roleArn),
- );
- const pipelineRoleDeploy = this.createPipelineRole(
- props,
- 'deploy',
- new ArnPrincipal(pipelineRole.roleArn),
- );
-
- const sourceOutput = new Artifact();
-
- const sourceAction = new GitHubSourceAction({
- actionName: `checkout-${props.envName}-${props.githubRepo}`.toLowerCase(),
- owner: this.githubOwner,
- repo: props.githubRepo,
- branch: props.branch,
- output: sourceOutput,
- oauthToken: SecretValue.secretsManager(props.secretTokenArn),
- trigger: GitHubTrigger.WEBHOOK,
- });
-
- const testActions = props.testBuildSpec.map((buildspec) =>
- this.createTestAction(sourceOutput, props, buildspec, pipelineRoleTest),
- );
-
- const deployActions = props.deployBuildSpec.map((buildspec) =>
- this.createDeployAction(
- sourceOutput,
- props,
- buildspec,
- pipelineRoleDeploy,
- ),
- );
-
- const stages: StageProps[] = this.createStages(
- sourceAction,
- testActions,
- props,
- pipelineRole,
- deployActions,
- );
-
- const artifactBucket = Bucket.fromBucketName(
- this,
- 'envilder-codepipeline-artifact',
- 'envilder-codepipeline-artifact',
- );
-
- const pipeline = new Pipeline(this, 'Pipeline', {
- pipelineType: PipelineType.V2,
- role: pipelineRole,
- pipelineName: `${props.githubRepo}-${props.envName}`.toLowerCase(),
- stages: stages,
- artifactBucket: artifactBucket,
- });
-
- this.createNotifications(props, pipeline);
- }
-
- /**
- * Configures notifications for pipeline state changes and manual approvals.
- *
- * Uses an existing AWS Chatbot Slack configuration as the notification target.
- *
- * @param props - The pipeline properties.
- * @param pipeline - The CodePipeline instance.
- */
- private createNotifications(props: PipelineStackProps, pipeline: Pipeline) {
- if (props.slackChannelConfigurationName) {
- // Import the existing Slack channel configuration
- const slackChannelConfigurationArn = `arn:aws:chatbot::${this.props.env?.account}:chat-configuration/slack-channel/${props.slackChannelConfigurationName}`;
- const slackTarget =
- SlackChannelConfiguration.fromSlackChannelConfigurationArn(
- this,
- 'SlackChannelConfig',
- slackChannelConfigurationArn,
- );
-
- // Create notification rule for pipeline state changes
- pipeline.notifyOnExecutionStateChange(
- `${formatRepoNameForCloudFormation(props.githubRepo)}-PipelineNotifications-${props.envName}`,
- slackTarget,
- {
- detailType: DetailType.BASIC,
- notificationRuleName: `${props.githubRepo}-${props.envName}-pipeline-updates`,
- },
- );
-
- if (props.manualApproval === true) {
- // Create notification rule for manual approval state changes
- pipeline.notifyOnAnyManualApprovalStateChange(
- `${formatRepoNameForCloudFormation(props.githubRepo)}-ManualApproval-${props.envName}`,
- slackTarget,
- {
- detailType: DetailType.FULL,
- notificationRuleName: `${props.githubRepo}-${props.envName}-manual-approval`,
- },
- );
- }
- }
-
- if (props.manualApproval === true) {
- const emailTopic = new Topic(
- this,
- `${formatRepoNameForCloudFormation(props.githubRepo)}_ManualApprovealEmail_${props.envName}`,
- {
- displayName: `⚠️ ${props.githubRepo} [${props.envName.toUpperCase()}] - Manual Approval Required`,
- masterKey: new Key(
- this,
- `Key-${formatRepoNameForCloudFormation(props.githubRepo)}-ManualApprovealEmail-${props.envName}`.toLowerCase(),
- ),
- },
- );
- emailTopic.addSubscription(new EmailSubscription('mac.albert@gmail.com'));
-
- pipeline.notifyOnAnyManualApprovalStateChange(
- `${formatRepoNameForCloudFormation(props.githubRepo)}-NotifyManualApproval-${props.envName}`,
- emailTopic,
- {
- detailType: DetailType.BASIC,
- notificationRuleName:
- `${props.githubRepo} (${props.envName}) - Approval Required (Email)`.toLowerCase(),
- },
- );
- }
- }
-
- /**
- * Creates an IAM role for a specific pipeline component.
- *
- * The role is created with an inline policy document based on the provided domain and environment,
- * and additional assume role permissions for Lambda, CodePipeline, and CodeBuild.
- *
- * @param props - The pipeline properties.
- * @param roleType - A string representing the type of role (e.g., "pipeline", "deploy", or "test").
- * @returns The created IAM role.
- */
- private createPipelineRole(
- props: PipelineStackProps,
- roleType: string,
- additionalPrincipal?: ArnPrincipal,
- ): Role {
- const policyDocument = this.getPolicyDocument(props.domain, props.env);
-
- const pipelineRole = new Role(this, `Role-${roleType}`, {
- assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
- description: `Role for CD pipeline in repo ${props.githubRepo} (${props.envName})`,
- inlinePolicies: { customApiPolicyDocument: policyDocument },
- });
-
- pipelineRole.assumeRolePolicy?.addStatements(
- new PolicyStatement({
- principals: [
- new ServicePrincipal('lambda.amazonaws.com'),
- new ServicePrincipal('codepipeline.amazonaws.com'),
- new ServicePrincipal('codebuild.amazonaws.com'),
- ],
- actions: ['sts:AssumeRole'],
- }),
- );
-
- if (additionalPrincipal) {
- pipelineRole.assumeRolePolicy?.addStatements(
- new PolicyStatement({
- principals: [additionalPrincipal],
- actions: ['sts:AssumeRole'],
- }),
- );
- }
-
- return pipelineRole;
- }
-
- /**
- * Creates the stages for the CodePipeline.
- *
- * This method defines the stages for source, manual approval (if enabled), test, and deploy actions.
- *
- * @param sourceAction - The GitHub source action.
- * @param testAction - An array of CodeBuild actions for testing.
- * @param props - The pipeline properties.
- * @param pipelineRole - The IAM role for the pipeline.
- * @param deployAction - An array of CodeBuild actions for deployment.
- * @returns An array of StageProps defining the pipeline stages.
- */
- private createStages(
- sourceAction: GitHubSourceAction,
- testAction: CodeBuildAction[],
- props: PipelineStackProps,
- pipelineRole: Role,
- deployAction: CodeBuildAction[],
- ): StageProps[] {
- const stages: StageProps[] = [
- { actions: [sourceAction], stageName: 'Source' },
- ];
-
- if (props.manualApproval) {
- const manualApprovalAction = new ManualApprovalAction({
- actionName:
- `${props.githubRepo}-ManualApproval-${props.envName}`.toLowerCase(),
- role: pipelineRole,
- });
-
- stages.push({
- actions: [manualApprovalAction],
- stageName:
- `${props.githubRepo}-ManualApproval-${props.envName}`.toLowerCase(),
- });
- }
-
- stages.push({ actions: testAction, stageName: 'Test' });
- stages.push({ actions: deployAction, stageName: 'Deploy' });
-
- return stages;
- }
-
- /**
- * Creates a CodeBuild action for testing.
- *
- * This method creates a PipelineProject for testing using the provided buildspec file.
- * It configures the project environment with a Linux build image and returns a CodeBuildAction.
- *
- * @param sourceOutput - The source artifact from GitHub.
- * @param props - The pipeline properties.
- * @param buildspec - The filename of the test buildspec.
- * @param pipelineRole - The IAM role to use for the test project.
- * @returns The created CodeBuildAction for testing.
- */
- private createTestAction(
- sourceOutput: Artifact,
- props: PipelineStackProps,
- buildspec: string,
- pipelineRole: Role,
- ): CodeBuildAction {
- const fileName = path.parse(path.basename(buildspec)).name;
- const projectName =
- `${fileName}-test-${formatRepoNameForCloudFormation(props.githubRepo)}-${props.envName}`.toLowerCase();
-
- const project = new PipelineProject(this, `Test-${fileName}`, {
- environment: {
- buildImage: LinuxBuildImage.STANDARD_7_0,
- privileged: true,
- computeType: aws_codebuild.ComputeType.SMALL,
- },
- timeout: Duration.minutes(15),
- environmentVariables: {},
- buildSpec: BuildSpec.fromSourceFilename(buildspec),
- role: pipelineRole,
- vpc: props.vpc,
- projectName: projectName,
- cache: this.resolveCache(props.cacheConfig, `test-${fileName}`, props),
- });
-
- return new CodeBuildAction({
- input: sourceOutput,
- actionName: projectName,
- project: project,
- role: pipelineRole,
- });
- }
-
- /**
- * Creates a CodeBuild action for deployment.
- *
- * This method creates a PipelineProject for deployment using the provided buildspec file.
- * It configures the environment variables and returns a CodeBuildAction for the deployment stage.
- *
- * @param sourceOutput - The source artifact from GitHub.
- * @param props - The pipeline properties.
- * @param buildspec - The filename of the deploy buildspec.
- * @param pipelineRole - The IAM role to use for the deploy project.
- * @returns The created CodeBuildAction for deployment.
- */
- private createDeployAction(
- sourceOutput: Artifact,
- props: PipelineStackProps,
- buildspec: string,
- pipelineRole: Role,
- ): CodeBuildAction {
- const fileName = path.parse(path.basename(buildspec)).name;
- const projectName =
- `${fileName}-deploy-${formatRepoNameForCloudFormation(props.githubRepo)}-${props.envName}`.toLowerCase();
-
- const project = new PipelineProject(this, fileName, {
- environment: {
- buildImage: LinuxBuildImage.STANDARD_7_0,
- privileged: true,
- computeType: aws_codebuild.ComputeType.SMALL,
- },
- timeout: Duration.minutes(30),
- environmentVariables: this.getEnvironmentVariables(props),
- buildSpec: BuildSpec.fromSourceFilename(buildspec),
- role: pipelineRole,
- projectName: projectName,
- cache: this.resolveCache(props.cacheConfig, `deploy-${fileName}`, props),
- });
-
- return new CodeBuildAction({
- input: sourceOutput,
- actionName: projectName,
- project: project,
- role: pipelineRole,
- });
- }
-
- /**
- * Resolves the cache configuration for CodeBuild projects.
- *
- * @param cacheConfig - The cache configuration (none, local, or S3).
- * @param cacheBucketSuffix - Suffix for the cache bucket identifier (e.g., "test-filename" or "deploy-filename").
- * @param props - The pipeline properties for generating cache prefixes.
- * @returns The resolved CodeBuild cache configuration or undefined if disabled.
- */
- private resolveCache(
- cacheConfig: CacheConfig | undefined,
- cacheBucketSuffix: string,
- props: PipelineStackProps,
- ): aws_codebuild.Cache | undefined {
- if (!cacheConfig) {
- return undefined;
- }
-
- switch (cacheConfig.type) {
- case 'local':
- return aws_codebuild.Cache.local(
- aws_codebuild.LocalCacheMode.DOCKER_LAYER,
- aws_codebuild.LocalCacheMode.CUSTOM,
- );
-
- case 's3': {
- const bucketName =
- cacheConfig.bucketName ||
- `codebuild-${this.props.env?.region}-${this.props.env?.account}`;
- const cacheBucket = Bucket.fromBucketName(
- this,
- `CodeBuildCacheBucket-${cacheBucketSuffix}`,
- bucketName,
- );
- const prefix = `${props.githubRepo}`;
- return aws_codebuild.Cache.bucket(cacheBucket, { prefix });
- }
- default:
- return undefined;
- }
- }
-
- /**
- * Retrieves and merges environment variables for the deploy project.
- *
- * By default, it includes ASPNETCORE_ENVIRONMENT set to the environment name.
- * If additional environment variables are provided, they are merged.
- *
- * @param props - The pipeline properties.
- * @returns An object containing the environment variables.
- */
- private getEnvironmentVariables(props: PipelineStackProps) {
- let environmentVariables = {
- ASPNETCORE_ENVIRONMENT: { value: props.envName },
- };
-
- if (props.environment !== null) {
- environmentVariables = {
- ...props.environment,
- ...{ ASPNETCORE_ENVIRONMENT: { value: props.envName } },
- };
- }
-
- return environmentVariables;
- }
-
- /**
- * Constructs a policy document for the pipeline role.
- *
- * The policy document includes permissions for assuming roles, CloudWatch logging,
- * CodeBuild reporting, S3 access, Secrets Manager, SES, KMS, SQS, and SSM.
- *
- * @param domain - The domain for SES email sending.
- * @param env - The AWS environment information.
- * @returns A PolicyDocument object in JSON format.
- */
- private getPolicyDocument(domain: string, env?: Environment) {
- return PolicyDocument.fromJson({
- Version: '2012-10-17',
- Statement: [
- {
- Action: ['sts:AssumeRole'],
- Resource: [`arn:aws:iam::${env?.account}:role/*`],
- Effect: 'Allow',
- },
- {
- Action: [
- 'logs:CreateLogGroup',
- 'logs:CreateLogStream',
- 'logs:PutLogEvents',
- ],
- Resource: [`arn:aws:logs:${env?.region}:${env?.account}:log-group:*`],
- Effect: 'Allow',
- },
- {
- Action: [
- 'codebuild:BatchPutCodeCoverages',
- 'codebuild:BatchPutTestCases',
- 'codebuild:CreateReport',
- 'codebuild:CreateReportGroup',
- 'codebuild:UpdateReport',
- 'codebuild:StartBuild',
- ],
- Resource: `arn:aws:codebuild:${env?.region}:${env?.account}:project/*`,
- Effect: 'Allow',
- },
- {
- Action: ['s3:GetBucket*', 's3:GetObject*', 's3:List*'],
- Resource: ['arn:aws:s3:::*'],
- Effect: 'Allow',
- },
- {
- Action: [
- 'secretsmanager:GetResourcePolicy',
- 'secretsmanager:GetSecretValue',
- 'secretsmanager:DescribeSecret',
- 'secretsmanager:ListSecretVersionIds',
- ],
- Resource: ['*'],
- Effect: 'Allow',
- },
- {
- Action: ['ses:SendEmail'],
- Resource: [
- `arn:aws:ses:${env?.region}:${env?.account}:identity/${domain}`,
- ],
- Effect: 'Allow',
- },
- {
- Action: [
- 'kms:Decrypt',
- 'kms:DescribeKey',
- 'kms:Encrypt',
- 'kms:GenerateDataKey*',
- 'kms:ReEncrypt*',
- ],
- Resource: `arn:aws:kms:${env?.region}:${env?.account}:*`,
- Effect: 'Allow',
- },
- {
- Action: ['sqs:*'],
- Resource: `arn:aws:sqs:${env?.region}:${env?.account}:*`,
- Effect: 'Allow',
- },
- {
- Action: [
- 'ssm:GetParameter',
- 'ssm:GetParameters',
- 'ssm:GetParametersByPath',
- ],
- Resource: [`arn:aws:ssm:${env?.region}:${env?.account}:parameter/*`],
- Effect: 'Allow',
- },
- ],
- });
- }
-}
diff --git a/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts b/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
index 7c7a4aa9..05bb24e1 100644
--- a/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
+++ b/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
@@ -1,8 +1,5 @@
import type { AppEnvironment } from '../../../domain/model/appEnvironment';
-import type {
- FrontendStackConfig,
- SharedStackConfig,
-} from '../../../domain/model/stackConfig';
+import type { FrontendStackConfig } from '../../../domain/model/stackConfig';
/**
* IAC Domain configuration interface
@@ -21,7 +18,6 @@ export interface IacDomainConfig {
*/
export interface StacksConfig {
frontend: FrontendStackConfig;
- shared: SharedStackConfig;
}
/**
@@ -46,12 +42,6 @@ export interface IDeploymentRequest {
/** Stacks configuration */
stacks: StacksConfig;
- /**
- * GitHub secret ARN for pipeline authentication
- * @optional If not provided, a default pattern will be used
- */
- githubSecretArn?: string;
-
/**
* Root path for project resolution
* @optional Defaults to process.cwd()/../../../ if not specified
diff --git a/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts b/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts
index 3ebaaf08..aa22ebe1 100644
--- a/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts
+++ b/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts
@@ -4,7 +4,6 @@ import { FileProjectPath } from '../../../infrastructure/projectPath/fileProject
import type { IStackBuilder } from '../../iStackBuilder';
import type { IProjectPath } from '../../ports/iProjectPath';
import { FrontendBuilder } from '../frontendBuilder';
-import { SharedBuilder } from '../sharedBuilder';
/**
* Factory for creating stack builders based on configuration
@@ -32,16 +31,6 @@ export class StackBuilderFactory {
);
}
- if (config.stacks.shared) {
- stackParts.push(
- new SharedBuilder({
- stackName: 'SharedStack',
- scope: app,
- iacConfig: config,
- }),
- );
- }
-
return stackParts;
}
}
diff --git a/src/iac/src/config/domain/builders/sharedBuilder.ts b/src/iac/src/config/domain/builders/sharedBuilder.ts
deleted file mode 100644
index a11e4409..00000000
--- a/src/iac/src/config/domain/builders/sharedBuilder.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { RemovalPolicy, type Stack } from 'aws-cdk-lib';
-import type { PipelineStackProps } from '../../../aws/developerTools/codepipeline/pipelineStack';
-import { PipelineStack } from '../../../aws/developerTools/codepipeline/pipelineStack';
-import type { IacDomainConfig } from '../../application/deployInfrastructure/models/deploymentRequest';
-import type { IStackBuildContext, IStackBuildProps } from '../iStackBuilder';
-import { IStackBuilder } from '../iStackBuilder';
-import type { SharedStackConfig } from '../model/stackConfig';
-
-export type SharedBuilderProps = IStackBuildProps;
-
-export class SharedBuilder extends IStackBuilder {
- private readonly sharedConfig: SharedStackConfig;
- private readonly domain: IacDomainConfig;
- private readonly repoName: string;
-
- constructor(sharedProps: SharedBuilderProps) {
- super(sharedProps);
- if (!sharedProps.iacConfig.stacks.shared) {
- throw new Error('Shared stack configuration is required');
- }
- this.sharedConfig = sharedProps.iacConfig.stacks.shared;
- this.domain = sharedProps.iacConfig.domain;
- this.repoName = sharedProps.iacConfig.repoName;
- }
-
- build(context: IStackBuildContext): Stack[] {
- this.context = context;
- const stacks: Stack[] = [];
-
- if (this.sharedConfig.pipeline) {
- for (const pipelineConfig of this.sharedConfig.pipeline) {
- stacks.push(this.createPipelineStack(pipelineConfig));
- }
- }
-
- return stacks;
- }
-
- private createPipelineStack(
- config: NonNullable[number],
- ): PipelineStack {
- const pipeline: PipelineStackProps = {
- name: 'Pipeline',
- branch: this.props.iacConfig.branch,
- githubRepo: this.repoName,
- envName: this.context.environment,
- secretTokenArn:
- this.props.iacConfig.githubSecretArn ??
- `arn:aws:secretsmanager:${this.context.env.region}:${this.context.env.account}:secret:github-access-token-secret-maOkMI`,
- testBuildSpec: [...config.testBuildSpecs],
- deployBuildSpec: [...config.deployBuildSpecs],
- testProjectName: `${this.repoName}-Tests`,
- vpc: this.context.vpc,
- env: this.context.env,
- bucketRemovalPolicy: RemovalPolicy.DESTROY,
- domain: this.domain.name,
- stackName: `${this.repoName}-CodePipeline`,
- manualApproval: config.manualApproval,
- slackChannelConfigurationName: config.slackChannelConfigurationName,
- cacheConfig: { type: 's3' },
- };
-
- return new PipelineStack(this.props.scope, pipeline);
- }
-}
diff --git a/src/iac/src/config/domain/model/deploymentConfig.ts b/src/iac/src/config/domain/model/deploymentConfig.ts
index b1169c8e..84bf7c96 100644
--- a/src/iac/src/config/domain/model/deploymentConfig.ts
+++ b/src/iac/src/config/domain/model/deploymentConfig.ts
@@ -1,5 +1,5 @@
import type { AppEnvironment } from './appEnvironment';
-import type { FrontendStackConfig, SharedStackConfig } from './stackConfig';
+import type { FrontendStackConfig } from './stackConfig';
/**
* Main deployment configuration interface for IAC projects
@@ -16,6 +16,5 @@ export interface IDeploymentConfig {
};
stacks: {
frontend: FrontendStackConfig;
- shared: SharedStackConfig;
};
}
diff --git a/src/iac/src/config/domain/model/stackConfig.ts b/src/iac/src/config/domain/model/stackConfig.ts
index d848eda2..b6bd700e 100644
--- a/src/iac/src/config/domain/model/stackConfig.ts
+++ b/src/iac/src/config/domain/model/stackConfig.ts
@@ -14,18 +14,3 @@ export interface StaticWebsiteConfig extends ModulePathConfig {
export interface FrontendStackConfig {
staticWebsites: readonly StaticWebsiteConfig[];
}
-
-// ============================================================================
-// SHARED TYPES
-// ============================================================================
-
-export interface PipelineConfig {
- manualApproval: boolean;
- slackChannelConfigurationName?: string;
- testBuildSpecs: readonly string[];
- deployBuildSpecs: readonly string[];
-}
-
-export interface SharedStackConfig {
- pipeline?: readonly PipelineConfig[];
-}
diff --git a/src/iac/src/infra/buildspecs/test/iac.yml b/src/iac/src/infra/buildspecs/test/iac.yml
deleted file mode 100644
index f76dfb22..00000000
--- a/src/iac/src/infra/buildspecs/test/iac.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-version: 0.2
-
-phases:
- install:
- runtime-versions:
- nodejs: 24
-
- commands:
- - echo "Install started on `date`"
- - npm install -g pnpm
-
- pre_build:
- commands:
- - cd envilder/src/iac
- - pnpm install --frozen-lockfile
-
- build:
- commands:
- - echo "Build started on `date`"
- - pnpm test:ci
-
- post_build:
- commands:
- - echo "Build completed on `date`"
-
-cache:
- paths:
- - "/root/.local/share/pnpm/store/**/*"
diff --git a/src/iac/src/infra/config/sharedConfig.ts b/src/iac/src/infra/config/sharedConfig.ts
deleted file mode 100644
index c5278f2c..00000000
--- a/src/iac/src/infra/config/sharedConfig.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { SharedStackConfig } from '../../config/domain/model/stackConfig';
-
-export const sharedConfig: SharedStackConfig = {
- pipeline: [
- {
- manualApproval: false,
- testBuildSpecs: [
- 'envilder/src/iac/src/infra/buildspecs/test/iac.yml',
- 'envilder/src/iac/src/infra/buildspecs/test/website.yml',
- ],
- deployBuildSpecs: [
- 'envilder/src/iac/src/infra/buildspecs/production/website.yml',
- ],
- },
- ],
-};
diff --git a/src/iac/src/infra/iacConfig.ts b/src/iac/src/infra/iacConfig.ts
index a8956d8e..681d0d5d 100644
--- a/src/iac/src/infra/iacConfig.ts
+++ b/src/iac/src/infra/iacConfig.ts
@@ -1,7 +1,6 @@
import type { IDeploymentConfig } from '../config/domain/model/deploymentConfig';
import { AppEnvironment } from '../config/domain/model/appEnvironment';
import { frontendConfig } from './config/frontendConfig';
-import { sharedConfig } from './config/sharedConfig';
export const iacConfig: IDeploymentConfig = {
repoName: 'envilder',
@@ -15,6 +14,5 @@ export const iacConfig: IDeploymentConfig = {
},
stacks: {
frontend: frontendConfig,
- shared: sharedConfig,
},
};
diff --git a/src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap b/src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap
deleted file mode 100644
index 2413d6bf..00000000
--- a/src/iac/test/aws/developerTools/__snapshots__/pipelineStack.test.ts.snap
+++ /dev/null
@@ -1,8927 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`PipelineStack Should_CreatePipelineStack_When_StackIsCalled: pipelineStackTest 1`] = `
-{
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value",
- },
- },
- "Resources": {
- "PipelineC660917D": {
- "DependsOn": [
- "RolepipelineDefaultPolicyB1AF7048",
- "Rolepipeline86313131",
- ],
- "Properties": {
- "ArtifactStore": {
- "Location": "envilder-codepipeline-artifact",
- "Type": "S3",
- },
- "Name": "envilder-test",
- "PipelineType": "V2",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "Stages": [
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Source",
- "Owner": "ThirdParty",
- "Provider": "GitHub",
- "Version": "1",
- },
- "Configuration": {
- "Branch": "main",
- "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- "Owner": "macalbert",
- "PollForSourceChanges": false,
- "Repo": "envilder",
- },
- "Name": "checkout-test-envilder",
- "OutputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "RunOrder": 1,
- },
- ],
- "Name": "Source",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "Testtestpipeline165C0FB1",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "test-pipeline-test-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "buildpipelineF72EB33D",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "build-pipeline-deploy-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Deploy",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::CodePipeline::Pipeline",
- },
- "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
- "Properties": {
- "Authentication": "GITHUB_HMAC",
- "AuthenticationConfiguration": {
- "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- },
- "Filters": [
- {
- "JsonPath": "$.ref",
- "MatchEquals": "refs/heads/{Branch}",
- },
- ],
- "RegisterWithThirdParty": true,
- "TargetAction": "checkout-test-envilder",
- "TargetPipeline": {
- "Ref": "PipelineC660917D",
- },
- "TargetPipelineVersion": 1,
- },
- "Type": "AWS::CodePipeline::Webhook",
- },
- "Roledeploy92E6FB77": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoledeployDefaultPolicy3EF570DF": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "buildpipelineF72EB33D",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoledeployDefaultPolicy3EF570DF",
- "Roles": [
- {
- "Ref": "Roledeploy92E6FB77",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Rolepipeline86313131": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RolepipelineDefaultPolicyB1AF7048": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
- "Roles": [
- {
- "Ref": "Rolepipeline86313131",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Roletest8FE49675": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoletestDefaultPolicy62D11870": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "ec2:CreateNetworkInterfacePermission",
- "Condition": {
- "StringEquals": {
- "ec2:AuthorizedService": "codebuild.amazonaws.com",
- "ec2:Subnet": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- ],
- },
- ],
- },
- },
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":network-interface/*",
- ],
- ],
- },
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Testtestpipeline165C0FB1",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoletestDefaultPolicy62D11870",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Testtestpipeline165C0FB1": {
- "DependsOn": [
- "TesttestpipelinePolicyDocument696CEEF8",
- ],
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "test-pipeline-test-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/test-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 15,
- "VpcConfig": {
- "SecurityGroupIds": [
- {
- "Fn::GetAtt": [
- "TesttestpipelineSecurityGroup0D35C015",
- "GroupId",
- ],
- },
- ],
- "Subnets": [
- {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "TesttestpipelinePolicyDocument696CEEF8": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "ec2:CreateNetworkInterface",
- "ec2:DescribeNetworkInterfaces",
- "ec2:DeleteNetworkInterface",
- "ec2:DescribeSubnets",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeDhcpOptions",
- "ec2:DescribeVpcs",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "TesttestpipelineSecurityGroup0D35C015": {
- "Properties": {
- "GroupDescription": "Automatic generated security group for CodeBuild pipelineStackTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineD4573B3B",
- "SecurityGroupEgress": [
- {
- "CidrIp": "0.0.0.0/0",
- "Description": "Allow all outbound traffic by default",
- "IpProtocol": "-1",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- "Type": "AWS::EC2::SecurityGroup",
- },
- "buildpipelineF72EB33D": {
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "EnvironmentVariables": [
- {
- "Name": "SOME_KEY",
- "Type": "PLAINTEXT",
- "Value": "https://some-url-for-test",
- },
- {
- "Name": "ASPNETCORE_ENVIRONMENT",
- "Type": "PLAINTEXT",
- "Value": "Test",
- },
- ],
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "build-pipeline-deploy-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/build-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 30,
- },
- "Type": "AWS::CodeBuild::Project",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
-
-exports[`PipelineStack Should_CreatePipelineWithFilteredPathsStack_When_StackIsCalled: pipelineWithFilterStackTest 1`] = `
-{
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value",
- },
- },
- "Resources": {
- "PipelineC660917D": {
- "DependsOn": [
- "RolepipelineDefaultPolicyB1AF7048",
- "Rolepipeline86313131",
- ],
- "Properties": {
- "ArtifactStore": {
- "Location": "envilder-codepipeline-artifact",
- "Type": "S3",
- },
- "Name": "envilder-production",
- "PipelineType": "V2",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "Stages": [
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Source",
- "Owner": "ThirdParty",
- "Provider": "GitHub",
- "Version": "1",
- },
- "Configuration": {
- "Branch": "main",
- "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- "Owner": "macalbert",
- "PollForSourceChanges": false,
- "Repo": "envilder",
- },
- "Name": "checkout-production-envilder",
- "OutputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-production-envilder",
- },
- ],
- "RunOrder": 1,
- },
- ],
- "Name": "Source",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "Testtestpipeline165C0FB1",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-production-envilder",
- },
- ],
- "Name": "test-pipeline-test-envilder-production",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "buildpipelineF72EB33D",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-production-envilder",
- },
- ],
- "Name": "build-pipeline-deploy-envilder-production",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Deploy",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Production",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
- },
- ],
- },
- "Type": "AWS::CodePipeline::Pipeline",
- },
- "PipelineSourcecheckoutproductionenvilderWebhookResource6C467C58": {
- "Properties": {
- "Authentication": "GITHUB_HMAC",
- "AuthenticationConfiguration": {
- "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- },
- "Filters": [
- {
- "JsonPath": "$.ref",
- "MatchEquals": "refs/heads/{Branch}",
- },
- ],
- "RegisterWithThirdParty": true,
- "TargetAction": "checkout-production-envilder",
- "TargetPipeline": {
- "Ref": "PipelineC660917D",
- },
- "TargetPipelineVersion": 1,
- },
- "Type": "AWS::CodePipeline::Webhook",
- },
- "Roledeploy92E6FB77": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Production)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Production",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoledeployDefaultPolicy3EF570DF": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "buildpipelineF72EB33D",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoledeployDefaultPolicy3EF570DF",
- "Roles": [
- {
- "Ref": "Roledeploy92E6FB77",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Rolepipeline86313131": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Production)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Production",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RolepipelineDefaultPolicyB1AF7048": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
- "Roles": [
- {
- "Ref": "Rolepipeline86313131",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Roletest8FE49675": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Production)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Production",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoletestDefaultPolicy62D11870": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "ec2:CreateNetworkInterfacePermission",
- "Condition": {
- "StringEquals": {
- "ec2:AuthorizedService": "codebuild.amazonaws.com",
- "ec2:Subnet": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- ],
- },
- ],
- },
- },
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":network-interface/*",
- ],
- ],
- },
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Testtestpipeline165C0FB1",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoletestDefaultPolicy62D11870",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Testtestpipeline165C0FB1": {
- "DependsOn": [
- "TesttestpipelinePolicyDocument696CEEF8",
- ],
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "test-pipeline-test-envilder-production",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/test-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Production",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
- },
- ],
- "TimeoutInMinutes": 15,
- "VpcConfig": {
- "SecurityGroupIds": [
- {
- "Fn::GetAtt": [
- "TesttestpipelineSecurityGroup0D35C015",
- "GroupId",
- ],
- },
- ],
- "Subnets": [
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "TesttestpipelinePolicyDocument696CEEF8": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "ec2:CreateNetworkInterface",
- "ec2:DescribeNetworkInterfaces",
- "ec2:DeleteNetworkInterface",
- "ec2:DescribeSubnets",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeDhcpOptions",
- "ec2:DescribeVpcs",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "TesttestpipelineSecurityGroup0D35C015": {
- "Properties": {
- "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithFilterStackTestmacalbertenvilderfrontendpipelinestackproductionstackTesttestpipelineE854AA65",
- "SecurityGroupEgress": [
- {
- "CidrIp": "0.0.0.0/0",
- "Description": "Allow all outbound traffic by default",
- "IpProtocol": "-1",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Production",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- "Type": "AWS::EC2::SecurityGroup",
- },
- "buildpipelineF72EB33D": {
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "EnvironmentVariables": [
- {
- "Name": "SOME_KEY",
- "Type": "PLAINTEXT",
- "Value": "https://some-url-for-test",
- },
- {
- "Name": "ASPNETCORE_ENVIRONMENT",
- "Type": "PLAINTEXT",
- "Value": "Production",
- },
- ],
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "build-pipeline-deploy-envilder-production",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/build-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Production",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-production-stack",
- },
- ],
- "TimeoutInMinutes": 30,
- },
- "Type": "AWS::CodeBuild::Project",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
-
-exports[`PipelineStack Should_CreatePipelineWithLocalCache_When_CacheConfigIsLocal: pipelineWithLocalCache 1`] = `
-{
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value",
- },
- },
- "Resources": {
- "PipelineC660917D": {
- "DependsOn": [
- "RolepipelineDefaultPolicyB1AF7048",
- "Rolepipeline86313131",
- ],
- "Properties": {
- "ArtifactStore": {
- "Location": "envilder-codepipeline-artifact",
- "Type": "S3",
- },
- "Name": "envilder-test",
- "PipelineType": "V2",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "Stages": [
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Source",
- "Owner": "ThirdParty",
- "Provider": "GitHub",
- "Version": "1",
- },
- "Configuration": {
- "Branch": "main",
- "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- "Owner": "macalbert",
- "PollForSourceChanges": false,
- "Repo": "envilder",
- },
- "Name": "checkout-test-envilder",
- "OutputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "RunOrder": 1,
- },
- ],
- "Name": "Source",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "Testtestpipeline165C0FB1",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "test-pipeline-test-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "buildpipelineF72EB33D",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "build-pipeline-deploy-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Deploy",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::CodePipeline::Pipeline",
- },
- "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
- "Properties": {
- "Authentication": "GITHUB_HMAC",
- "AuthenticationConfiguration": {
- "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- },
- "Filters": [
- {
- "JsonPath": "$.ref",
- "MatchEquals": "refs/heads/{Branch}",
- },
- ],
- "RegisterWithThirdParty": true,
- "TargetAction": "checkout-test-envilder",
- "TargetPipeline": {
- "Ref": "PipelineC660917D",
- },
- "TargetPipelineVersion": 1,
- },
- "Type": "AWS::CodePipeline::Webhook",
- },
- "Roledeploy92E6FB77": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoledeployDefaultPolicy3EF570DF": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "buildpipelineF72EB33D",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoledeployDefaultPolicy3EF570DF",
- "Roles": [
- {
- "Ref": "Roledeploy92E6FB77",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Rolepipeline86313131": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RolepipelineDefaultPolicyB1AF7048": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
- "Roles": [
- {
- "Ref": "Rolepipeline86313131",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Roletest8FE49675": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoletestDefaultPolicy62D11870": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "ec2:CreateNetworkInterfacePermission",
- "Condition": {
- "StringEquals": {
- "ec2:AuthorizedService": "codebuild.amazonaws.com",
- "ec2:Subnet": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- ],
- },
- ],
- },
- },
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":network-interface/*",
- ],
- ],
- },
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Testtestpipeline165C0FB1",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoletestDefaultPolicy62D11870",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Testtestpipeline165C0FB1": {
- "DependsOn": [
- "TesttestpipelinePolicyDocument696CEEF8",
- ],
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Modes": [
- "LOCAL_DOCKER_LAYER_CACHE",
- "LOCAL_CUSTOM_CACHE",
- ],
- "Type": "LOCAL",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "test-pipeline-test-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/test-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 15,
- "VpcConfig": {
- "SecurityGroupIds": [
- {
- "Fn::GetAtt": [
- "TesttestpipelineSecurityGroup0D35C015",
- "GroupId",
- ],
- },
- ],
- "Subnets": [
- {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "TesttestpipelinePolicyDocument696CEEF8": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "ec2:CreateNetworkInterface",
- "ec2:DescribeNetworkInterfaces",
- "ec2:DeleteNetworkInterface",
- "ec2:DescribeSubnets",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeDhcpOptions",
- "ec2:DescribeVpcs",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "TesttestpipelineSecurityGroup0D35C015": {
- "Properties": {
- "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithLocalCacheTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineAA84A210",
- "SecurityGroupEgress": [
- {
- "CidrIp": "0.0.0.0/0",
- "Description": "Allow all outbound traffic by default",
- "IpProtocol": "-1",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithLocalCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- "Type": "AWS::EC2::SecurityGroup",
- },
- "buildpipelineF72EB33D": {
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Modes": [
- "LOCAL_DOCKER_LAYER_CACHE",
- "LOCAL_CUSTOM_CACHE",
- ],
- "Type": "LOCAL",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "EnvironmentVariables": [
- {
- "Name": "SOME_KEY",
- "Type": "PLAINTEXT",
- "Value": "https://some-url-for-test",
- },
- {
- "Name": "ASPNETCORE_ENVIRONMENT",
- "Type": "PLAINTEXT",
- "Value": "Test",
- },
- ],
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "build-pipeline-deploy-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/build-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 30,
- },
- "Type": "AWS::CodeBuild::Project",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
-
-exports[`PipelineStack Should_CreatePipelineWithManualApproval_When_StackIsCalled: pipelineWithManualApproval 1`] = `
-{
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value",
- },
- },
- "Resources": {
- "PipelineC660917D": {
- "DependsOn": [
- "RolepipelineDefaultPolicyB1AF7048",
- "Rolepipeline86313131",
- ],
- "Properties": {
- "ArtifactStore": {
- "Location": "envilder-codepipeline-artifact",
- "Type": "S3",
- },
- "Name": "envilder-test",
- "PipelineType": "V2",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "Stages": [
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Source",
- "Owner": "ThirdParty",
- "Provider": "GitHub",
- "Version": "1",
- },
- "Configuration": {
- "Branch": "main",
- "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- "Owner": "macalbert",
- "PollForSourceChanges": false,
- "Repo": "envilder",
- },
- "Name": "checkout-test-envilder",
- "OutputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "RunOrder": 1,
- },
- ],
- "Name": "Source",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Approval",
- "Owner": "AWS",
- "Provider": "Manual",
- "Version": "1",
- },
- "Name": "envilder-manualapproval-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "envilder-manualapproval-test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "Testtestpipeline165C0FB1",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "test-pipeline-test-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "buildpipelineF72EB33D",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "build-pipeline-deploy-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Deploy",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::CodePipeline::Pipeline",
- },
- "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
- "Properties": {
- "Authentication": "GITHUB_HMAC",
- "AuthenticationConfiguration": {
- "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- },
- "Filters": [
- {
- "JsonPath": "$.ref",
- "MatchEquals": "refs/heads/{Branch}",
- },
- ],
- "RegisterWithThirdParty": true,
- "TargetAction": "checkout-test-envilder",
- "TargetPipeline": {
- "Ref": "PipelineC660917D",
- },
- "TargetPipelineVersion": 1,
- },
- "Type": "AWS::CodePipeline::Webhook",
- },
- "PipelineenvilderNotifyManualApprovalTest09846155": {
- "Properties": {
- "DetailType": "BASIC",
- "EventTypeIds": [
- "codepipeline-pipeline-manual-approval-failed",
- "codepipeline-pipeline-manual-approval-needed",
- "codepipeline-pipeline-manual-approval-succeeded",
- ],
- "Name": "envilder (test) - approval required (email)",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codepipeline:eu-west-1:account:",
- {
- "Ref": "PipelineC660917D",
- },
- ],
- ],
- },
- "Tags": {
- "Environment": "Test",
- "Project": "envilder",
- "StackId": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- "Targets": [
- {
- "TargetAddress": {
- "Ref": "envilderManualApprovealEmailTest98B36C0F",
- },
- "TargetType": "SNS",
- },
- ],
- },
- "Type": "AWS::CodeStarNotifications::NotificationRule",
- },
- "Roledeploy92E6FB77": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoledeployDefaultPolicy3EF570DF": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "buildpipelineF72EB33D",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoledeployDefaultPolicy3EF570DF",
- "Roles": [
- {
- "Ref": "Roledeploy92E6FB77",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Rolepipeline86313131": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RolepipelineDefaultPolicyB1AF7048": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
- "Roles": [
- {
- "Ref": "Rolepipeline86313131",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Roletest8FE49675": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoletestDefaultPolicy62D11870": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "ec2:CreateNetworkInterfacePermission",
- "Condition": {
- "StringEquals": {
- "ec2:AuthorizedService": "codebuild.amazonaws.com",
- "ec2:Subnet": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- ],
- },
- ],
- },
- },
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":network-interface/*",
- ],
- ],
- },
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Testtestpipeline165C0FB1",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoletestDefaultPolicy62D11870",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Testtestpipeline165C0FB1": {
- "DependsOn": [
- "TesttestpipelinePolicyDocument696CEEF8",
- ],
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "test-pipeline-test-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/test-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 15,
- "VpcConfig": {
- "SecurityGroupIds": [
- {
- "Fn::GetAtt": [
- "TesttestpipelineSecurityGroup0D35C015",
- "GroupId",
- ],
- },
- ],
- "Subnets": [
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "TesttestpipelinePolicyDocument696CEEF8": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "ec2:CreateNetworkInterface",
- "ec2:DescribeNetworkInterfaces",
- "ec2:DeleteNetworkInterface",
- "ec2:DescribeSubnets",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeDhcpOptions",
- "ec2:DescribeVpcs",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "TesttestpipelineSecurityGroup0D35C015": {
- "Properties": {
- "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithFilterStackTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineE937333C",
- "SecurityGroupEgress": [
- {
- "CidrIp": "0.0.0.0/0",
- "Description": "Allow all outbound traffic by default",
- "IpProtocol": "-1",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithFilterStackTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- "Type": "AWS::EC2::SecurityGroup",
- },
- "buildpipelineF72EB33D": {
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "EnvironmentVariables": [
- {
- "Name": "SOME_KEY",
- "Type": "PLAINTEXT",
- "Value": "https://some-url-for-test",
- },
- {
- "Name": "ASPNETCORE_ENVIRONMENT",
- "Type": "PLAINTEXT",
- "Value": "Test",
- },
- ],
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "build-pipeline-deploy-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/build-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 30,
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "envilderManualApprovealEmailTest98B36C0F": {
- "Properties": {
- "DisplayName": "⚠️ envilder [TEST] - Manual Approval Required",
- "KmsMasterKeyId": {
- "Fn::GetAtt": [
- "keyenvildermanualapprovealemailtest45B438A1",
- "Arn",
- ],
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::SNS::Topic",
- },
- "envilderManualApprovealEmailTestPolicyEFE2DD3F": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sns:Publish",
- "Effect": "Allow",
- "Principal": {
- "Service": "codestar-notifications.amazonaws.com",
- },
- "Resource": {
- "Ref": "envilderManualApprovealEmailTest98B36C0F",
- },
- "Sid": "0",
- },
- ],
- "Version": "2012-10-17",
- },
- "Topics": [
- {
- "Ref": "envilderManualApprovealEmailTest98B36C0F",
- },
- ],
- },
- "Type": "AWS::SNS::TopicPolicy",
- },
- "envilderManualApprovealEmailTestmacalbertgmailcom7F647CD9": {
- "Properties": {
- "Endpoint": "mac.albert@gmail.com",
- "Protocol": "email",
- "TopicArn": {
- "Ref": "envilderManualApprovealEmailTest98B36C0F",
- },
- },
- "Type": "AWS::SNS::Subscription",
- },
- "keyenvildermanualapprovealemailtest45B438A1": {
- "DeletionPolicy": "Retain",
- "Properties": {
- "KeyPolicy": {
- "Statement": [
- {
- "Action": "kms:*",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":iam::account:root",
- ],
- ],
- },
- },
- "Resource": "*",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:GenerateDataKey*",
- ],
- "Effect": "Allow",
- "Principal": {
- "Service": "codestar-notifications.amazonaws.com",
- },
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::KMS::Key",
- "UpdateReplacePolicy": "Retain",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
-
-exports[`PipelineStack Should_CreatePipelineWithNoCache_When_CacheConfigIsUndefined: pipelineWithUndefinedCache 1`] = `
-{
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value",
- },
- },
- "Resources": {
- "PipelineC660917D": {
- "DependsOn": [
- "RolepipelineDefaultPolicyB1AF7048",
- "Rolepipeline86313131",
- ],
- "Properties": {
- "ArtifactStore": {
- "Location": "envilder-codepipeline-artifact",
- "Type": "S3",
- },
- "Name": "envilder-test",
- "PipelineType": "V2",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "Stages": [
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Source",
- "Owner": "ThirdParty",
- "Provider": "GitHub",
- "Version": "1",
- },
- "Configuration": {
- "Branch": "main",
- "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- "Owner": "macalbert",
- "PollForSourceChanges": false,
- "Repo": "envilder",
- },
- "Name": "checkout-test-envilder",
- "OutputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "RunOrder": 1,
- },
- ],
- "Name": "Source",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "Testtestpipeline165C0FB1",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "test-pipeline-test-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "buildpipelineF72EB33D",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "build-pipeline-deploy-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Deploy",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::CodePipeline::Pipeline",
- },
- "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
- "Properties": {
- "Authentication": "GITHUB_HMAC",
- "AuthenticationConfiguration": {
- "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- },
- "Filters": [
- {
- "JsonPath": "$.ref",
- "MatchEquals": "refs/heads/{Branch}",
- },
- ],
- "RegisterWithThirdParty": true,
- "TargetAction": "checkout-test-envilder",
- "TargetPipeline": {
- "Ref": "PipelineC660917D",
- },
- "TargetPipelineVersion": 1,
- },
- "Type": "AWS::CodePipeline::Webhook",
- },
- "Roledeploy92E6FB77": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoledeployDefaultPolicy3EF570DF": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "buildpipelineF72EB33D",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoledeployDefaultPolicy3EF570DF",
- "Roles": [
- {
- "Ref": "Roledeploy92E6FB77",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Rolepipeline86313131": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RolepipelineDefaultPolicyB1AF7048": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
- "Roles": [
- {
- "Ref": "Rolepipeline86313131",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Roletest8FE49675": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoletestDefaultPolicy62D11870": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "ec2:CreateNetworkInterfacePermission",
- "Condition": {
- "StringEquals": {
- "ec2:AuthorizedService": "codebuild.amazonaws.com",
- "ec2:Subnet": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- ],
- },
- ],
- },
- },
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":network-interface/*",
- ],
- ],
- },
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Testtestpipeline165C0FB1",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoletestDefaultPolicy62D11870",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Testtestpipeline165C0FB1": {
- "DependsOn": [
- "TesttestpipelinePolicyDocument696CEEF8",
- ],
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "test-pipeline-test-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/test-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 15,
- "VpcConfig": {
- "SecurityGroupIds": [
- {
- "Fn::GetAtt": [
- "TesttestpipelineSecurityGroup0D35C015",
- "GroupId",
- ],
- },
- ],
- "Subnets": [
- {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "TesttestpipelinePolicyDocument696CEEF8": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "ec2:CreateNetworkInterface",
- "ec2:DescribeNetworkInterfaces",
- "ec2:DeleteNetworkInterface",
- "ec2:DescribeSubnets",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeDhcpOptions",
- "ec2:DescribeVpcs",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "TesttestpipelineSecurityGroup0D35C015": {
- "Properties": {
- "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithUndefinedCacheTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipeline4900349B",
- "SecurityGroupEgress": [
- {
- "CidrIp": "0.0.0.0/0",
- "Description": "Allow all outbound traffic by default",
- "IpProtocol": "-1",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithUndefinedCacheTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- "Type": "AWS::EC2::SecurityGroup",
- },
- "buildpipelineF72EB33D": {
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Type": "NO_CACHE",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "EnvironmentVariables": [
- {
- "Name": "SOME_KEY",
- "Type": "PLAINTEXT",
- "Value": "https://some-url-for-test",
- },
- {
- "Name": "ASPNETCORE_ENVIRONMENT",
- "Type": "PLAINTEXT",
- "Value": "Test",
- },
- ],
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "build-pipeline-deploy-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/build-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 30,
- },
- "Type": "AWS::CodeBuild::Project",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
-
-exports[`PipelineStack Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithCustomBucket: pipelineWithS3CacheCustom 1`] = `
-{
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value",
- },
- },
- "Resources": {
- "PipelineC660917D": {
- "DependsOn": [
- "RolepipelineDefaultPolicyB1AF7048",
- "Rolepipeline86313131",
- ],
- "Properties": {
- "ArtifactStore": {
- "Location": "envilder-codepipeline-artifact",
- "Type": "S3",
- },
- "Name": "envilder-test",
- "PipelineType": "V2",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "Stages": [
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Source",
- "Owner": "ThirdParty",
- "Provider": "GitHub",
- "Version": "1",
- },
- "Configuration": {
- "Branch": "main",
- "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- "Owner": "macalbert",
- "PollForSourceChanges": false,
- "Repo": "envilder",
- },
- "Name": "checkout-test-envilder",
- "OutputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "RunOrder": 1,
- },
- ],
- "Name": "Source",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "Testtestpipeline165C0FB1",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "test-pipeline-test-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "buildpipelineF72EB33D",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "build-pipeline-deploy-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Deploy",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::CodePipeline::Pipeline",
- },
- "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
- "Properties": {
- "Authentication": "GITHUB_HMAC",
- "AuthenticationConfiguration": {
- "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- },
- "Filters": [
- {
- "JsonPath": "$.ref",
- "MatchEquals": "refs/heads/{Branch}",
- },
- ],
- "RegisterWithThirdParty": true,
- "TargetAction": "checkout-test-envilder",
- "TargetPipeline": {
- "Ref": "PipelineC660917D",
- },
- "TargetPipelineVersion": 1,
- },
- "Type": "AWS::CodePipeline::Webhook",
- },
- "Roledeploy92E6FB77": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoledeployDefaultPolicy3EF570DF": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::my-custom-cache-bucket",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::my-custom-cache-bucket/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "buildpipelineF72EB33D",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoledeployDefaultPolicy3EF570DF",
- "Roles": [
- {
- "Ref": "Roledeploy92E6FB77",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Rolepipeline86313131": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RolepipelineDefaultPolicyB1AF7048": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
- "Roles": [
- {
- "Ref": "Rolepipeline86313131",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Roletest8FE49675": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoletestDefaultPolicy62D11870": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::my-custom-cache-bucket",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::my-custom-cache-bucket/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "ec2:CreateNetworkInterfacePermission",
- "Condition": {
- "StringEquals": {
- "ec2:AuthorizedService": "codebuild.amazonaws.com",
- "ec2:Subnet": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- ],
- },
- ],
- },
- },
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":network-interface/*",
- ],
- ],
- },
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Testtestpipeline165C0FB1",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoletestDefaultPolicy62D11870",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Testtestpipeline165C0FB1": {
- "DependsOn": [
- "TesttestpipelinePolicyDocument696CEEF8",
- ],
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Location": "my-custom-cache-bucket/envilder",
- "Type": "S3",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "test-pipeline-test-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/test-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 15,
- "VpcConfig": {
- "SecurityGroupIds": [
- {
- "Fn::GetAtt": [
- "TesttestpipelineSecurityGroup0D35C015",
- "GroupId",
- ],
- },
- ],
- "Subnets": [
- {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "TesttestpipelinePolicyDocument696CEEF8": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "ec2:CreateNetworkInterface",
- "ec2:DescribeNetworkInterfaces",
- "ec2:DeleteNetworkInterface",
- "ec2:DescribeSubnets",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeDhcpOptions",
- "ec2:DescribeVpcs",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "TesttestpipelineSecurityGroup0D35C015": {
- "Properties": {
- "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithS3CacheCustomTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineEDADE20A",
- "SecurityGroupEgress": [
- {
- "CidrIp": "0.0.0.0/0",
- "Description": "Allow all outbound traffic by default",
- "IpProtocol": "-1",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithS3CacheCustomTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- "Type": "AWS::EC2::SecurityGroup",
- },
- "buildpipelineF72EB33D": {
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Location": "my-custom-cache-bucket/envilder",
- "Type": "S3",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "EnvironmentVariables": [
- {
- "Name": "SOME_KEY",
- "Type": "PLAINTEXT",
- "Value": "https://some-url-for-test",
- },
- {
- "Name": "ASPNETCORE_ENVIRONMENT",
- "Type": "PLAINTEXT",
- "Value": "Test",
- },
- ],
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "build-pipeline-deploy-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/build-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 30,
- },
- "Type": "AWS::CodeBuild::Project",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
-
-exports[`PipelineStack Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithDefaultBucket: pipelineWithS3CacheDefault 1`] = `
-{
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value",
- },
- },
- "Resources": {
- "PipelineC660917D": {
- "DependsOn": [
- "RolepipelineDefaultPolicyB1AF7048",
- "Rolepipeline86313131",
- ],
- "Properties": {
- "ArtifactStore": {
- "Location": "envilder-codepipeline-artifact",
- "Type": "S3",
- },
- "Name": "envilder-test",
- "PipelineType": "V2",
- "RoleArn": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- "Stages": [
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Source",
- "Owner": "ThirdParty",
- "Provider": "GitHub",
- "Version": "1",
- },
- "Configuration": {
- "Branch": "main",
- "OAuthToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- "Owner": "macalbert",
- "PollForSourceChanges": false,
- "Repo": "envilder",
- },
- "Name": "checkout-test-envilder",
- "OutputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "RunOrder": 1,
- },
- ],
- "Name": "Source",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "Testtestpipeline165C0FB1",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "test-pipeline-test-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Test",
- },
- {
- "Actions": [
- {
- "ActionTypeId": {
- "Category": "Build",
- "Owner": "AWS",
- "Provider": "CodeBuild",
- "Version": "1",
- },
- "Configuration": {
- "ProjectName": {
- "Ref": "buildpipelineF72EB33D",
- },
- },
- "InputArtifacts": [
- {
- "Name": "Artifact_Source_checkout-test-envilder",
- },
- ],
- "Name": "build-pipeline-deploy-envilder-test",
- "RoleArn": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "RunOrder": 1,
- },
- ],
- "Name": "Deploy",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::CodePipeline::Pipeline",
- },
- "PipelineSourcecheckouttestenvilderWebhookResourceACD2B841": {
- "Properties": {
- "Authentication": "GITHUB_HMAC",
- "AuthenticationConfiguration": {
- "SecretToken": "{{resolve:secretsmanager:arn:aws:secretsmanager:eu-west-1:account:secret:github-token:SecretString:::}}",
- },
- "Filters": [
- {
- "JsonPath": "$.ref",
- "MatchEquals": "refs/heads/{Branch}",
- },
- ],
- "RegisterWithThirdParty": true,
- "TargetAction": "checkout-test-envilder",
- "TargetPipeline": {
- "Ref": "PipelineC660917D",
- },
- "TargetPipelineVersion": 1,
- },
- "Type": "AWS::CodePipeline::Webhook",
- },
- "Roledeploy92E6FB77": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoledeployDefaultPolicy3EF570DF": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::codebuild-eu-west-1-account",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::codebuild-eu-west-1-account/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "buildpipelineF72EB33D",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "buildpipelineF72EB33D",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoledeployDefaultPolicy3EF570DF",
- "Roles": [
- {
- "Ref": "Roledeploy92E6FB77",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Rolepipeline86313131": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RolepipelineDefaultPolicyB1AF7048": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RolepipelineDefaultPolicyB1AF7048",
- "Roles": [
- {
- "Ref": "Rolepipeline86313131",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Roletest8FE49675": {
- "Properties": {
- "AssumeRolePolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": "lambda.amazonaws.com",
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "Service": [
- "lambda.amazonaws.com",
- "codepipeline.amazonaws.com",
- "codebuild.amazonaws.com",
- ],
- },
- },
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Principal": {
- "AWS": {
- "Fn::GetAtt": [
- "Rolepipeline86313131",
- "Arn",
- ],
- },
- },
- },
- ],
- "Version": "2012-10-17",
- },
- "Description": "Role for CD pipeline in repo envilder (Test)",
- "Policies": [
- {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Effect": "Allow",
- "Resource": "arn:aws:iam::account:role/*",
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:logs:eu-west-1:account:log-group:*",
- },
- {
- "Action": [
- "codebuild:BatchPutCodeCoverages",
- "codebuild:BatchPutTestCases",
- "codebuild:CreateReport",
- "codebuild:CreateReportGroup",
- "codebuild:UpdateReport",
- "codebuild:StartBuild",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:codebuild:eu-west-1:account:project/*",
- },
- {
- "Action": [
- "s3:GetBucket*",
- "s3:GetObject*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:s3:::*",
- },
- {
- "Action": [
- "secretsmanager:GetResourcePolicy",
- "secretsmanager:GetSecretValue",
- "secretsmanager:DescribeSecret",
- "secretsmanager:ListSecretVersionIds",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- {
- "Action": "ses:SendEmail",
- "Effect": "Allow",
- "Resource": "arn:aws:ses:eu-west-1:account:identity/envilder-test",
- },
- {
- "Action": [
- "kms:Decrypt",
- "kms:DescribeKey",
- "kms:Encrypt",
- "kms:GenerateDataKey*",
- "kms:ReEncrypt*",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:kms:eu-west-1:account:*",
- },
- {
- "Action": "sqs:*",
- "Effect": "Allow",
- "Resource": "arn:aws:sqs:eu-west-1:account:*",
- },
- {
- "Action": [
- "ssm:GetParameter",
- "ssm:GetParameters",
- "ssm:GetParametersByPath",
- ],
- "Effect": "Allow",
- "Resource": "arn:aws:ssm:eu-west-1:account:parameter/*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "customApiPolicyDocument",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- },
- "Type": "AWS::IAM::Role",
- },
- "RoletestDefaultPolicy62D11870": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- "s3:DeleteObject*",
- "s3:PutObject",
- "s3:PutObjectLegalHold",
- "s3:PutObjectRetention",
- "s3:PutObjectTagging",
- "s3:PutObjectVersionTagging",
- "s3:Abort*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::codebuild-eu-west-1-account",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::codebuild-eu-west-1-account/*",
- ],
- ],
- },
- ],
- },
- {
- "Action": "ec2:CreateNetworkInterfacePermission",
- "Condition": {
- "StringEquals": {
- "ec2:AuthorizedService": "codebuild.amazonaws.com",
- "ec2:Subnet": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":subnet/",
- {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- ],
- },
- ],
- },
- },
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":ec2:",
- {
- "Ref": "AWS::Region",
- },
- ":",
- {
- "Ref": "AWS::AccountId",
- },
- ":network-interface/*",
- ],
- ],
- },
- },
- {
- "Action": [
- "logs:CreateLogGroup",
- "logs:CreateLogStream",
- "logs:PutLogEvents",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":logs:eu-west-1:account:log-group:/aws/codebuild/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- ":*",
- ],
- ],
- },
- ],
- },
- {
- "Action": [
- "codebuild:CreateReportGroup",
- "codebuild:CreateReport",
- "codebuild:UpdateReport",
- "codebuild:BatchPutTestCases",
- "codebuild:BatchPutCodeCoverages",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":codebuild:eu-west-1:account:report-group/",
- {
- "Ref": "Testtestpipeline165C0FB1",
- },
- "-*",
- ],
- ],
- },
- },
- {
- "Action": [
- "codebuild:BatchGetBuilds",
- "codebuild:StartBuild",
- "codebuild:StopBuild",
- ],
- "Effect": "Allow",
- "Resource": {
- "Fn::GetAtt": [
- "Testtestpipeline165C0FB1",
- "Arn",
- ],
- },
- },
- {
- "Action": [
- "s3:GetObject*",
- "s3:GetBucket*",
- "s3:List*",
- ],
- "Effect": "Allow",
- "Resource": [
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact",
- ],
- ],
- },
- {
- "Fn::Join": [
- "",
- [
- "arn:",
- {
- "Ref": "AWS::Partition",
- },
- ":s3:::envilder-codepipeline-artifact/*",
- ],
- ],
- },
- ],
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "RoletestDefaultPolicy62D11870",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "Testtestpipeline165C0FB1": {
- "DependsOn": [
- "TesttestpipelinePolicyDocument696CEEF8",
- ],
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Location": "codebuild-eu-west-1-account/envilder",
- "Type": "S3",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "test-pipeline-test-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roletest8FE49675",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/test-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 15,
- "VpcConfig": {
- "SecurityGroupIds": [
- {
- "Fn::GetAtt": [
- "TesttestpipelineSecurityGroup0D35C015",
- "GroupId",
- ],
- },
- ],
- "Subnets": [
- {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet1Subnet934893E8236E2271",
- },
- {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet2Subnet7031C2BA60DCB1EE",
- },
- {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcPrivateSubnet3Subnet985AC459F9514491",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- },
- "Type": "AWS::CodeBuild::Project",
- },
- "TesttestpipelinePolicyDocument696CEEF8": {
- "Properties": {
- "PolicyDocument": {
- "Statement": [
- {
- "Action": [
- "ec2:CreateNetworkInterface",
- "ec2:DescribeNetworkInterfaces",
- "ec2:DeleteNetworkInterface",
- "ec2:DescribeSubnets",
- "ec2:DescribeSecurityGroups",
- "ec2:DescribeDhcpOptions",
- "ec2:DescribeVpcs",
- ],
- "Effect": "Allow",
- "Resource": "*",
- },
- ],
- "Version": "2012-10-17",
- },
- "PolicyName": "TesttestpipelinePolicyDocument696CEEF8",
- "Roles": [
- {
- "Ref": "Roletest8FE49675",
- },
- ],
- },
- "Type": "AWS::IAM::Policy",
- },
- "TesttestpipelineSecurityGroup0D35C015": {
- "Properties": {
- "GroupDescription": "Automatic generated security group for CodeBuild pipelineWithS3CacheDefaultTestmacalbertenvilderfrontendpipelinestackteststackTesttestpipelineC3A57052",
- "SecurityGroupEgress": [
- {
- "CidrIp": "0.0.0.0/0",
- "Description": "Allow all outbound traffic by default",
- "IpProtocol": "-1",
- },
- ],
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "VpcId": {
- "Fn::ImportValue": "pipelineWithS3CacheDefaultTest:ExportsOutputRefvpcA2121C384D1B3CDE",
- },
- },
- "Type": "AWS::EC2::SecurityGroup",
- },
- "buildpipelineF72EB33D": {
- "Properties": {
- "Artifacts": {
- "Type": "CODEPIPELINE",
- },
- "Cache": {
- "Location": "codebuild-eu-west-1-account/envilder",
- "Type": "S3",
- },
- "EncryptionKey": "alias/aws/s3",
- "Environment": {
- "ComputeType": "BUILD_GENERAL1_SMALL",
- "EnvironmentVariables": [
- {
- "Name": "SOME_KEY",
- "Type": "PLAINTEXT",
- "Value": "https://some-url-for-test",
- },
- {
- "Name": "ASPNETCORE_ENVIRONMENT",
- "Type": "PLAINTEXT",
- "Value": "Test",
- },
- ],
- "Image": "aws/codebuild/standard:7.0",
- "ImagePullCredentialsType": "CODEBUILD",
- "PrivilegedMode": true,
- "Type": "LINUX_CONTAINER",
- },
- "Name": "build-pipeline-deploy-envilder-test",
- "ServiceRole": {
- "Fn::GetAtt": [
- "Roledeploy92E6FB77",
- "Arn",
- ],
- },
- "Source": {
- "BuildSpec": "path/build-pipeline.yml",
- "Type": "CODEPIPELINE",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Project",
- "Value": "envilder",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-envilder-frontendpipelinestack-test-stack",
- },
- ],
- "TimeoutInMinutes": 30,
- },
- "Type": "AWS::CodeBuild::Project",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
diff --git a/src/iac/test/aws/developerTools/pipelineStack.test.ts b/src/iac/test/aws/developerTools/pipelineStack.test.ts
deleted file mode 100644
index 044df66a..00000000
--- a/src/iac/test/aws/developerTools/pipelineStack.test.ts
+++ /dev/null
@@ -1,181 +0,0 @@
-import { App, RemovalPolicy, Stack } from 'aws-cdk-lib';
-import { Template } from 'aws-cdk-lib/assertions';
-import { Vpc } from 'aws-cdk-lib/aws-ec2';
-import {
- PipelineStack,
- type PipelineStackProps,
-} from '../../../src/aws/developerTools/codepipeline/pipelineStack';
-import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
-
-describe('PipelineStack', () => {
- const env = {
- account: 'account',
- region: 'eu-west-1',
- };
-
- test('Should_CreatePipelineStack_When_StackIsCalled', () => {
- // Arrange
- const stack = new Stack(new App(), 'pipelineStackTest', { env });
- const props = createPipelineStackProps(stack);
-
- // Act
- const actual = new PipelineStack(stack, props);
-
- // Assert
- const template = Template.fromStack(actual);
- expect(template.toJSON()).toMatchSnapshot('pipelineStackTest');
- });
-
- test('Should_CreatePipelineWithFilteredPathsStack_When_StackIsCalled', () => {
- // Arrange
- const stack = new Stack(new App(), 'pipelineWithFilterStackTest', {
- env,
- });
- const props = createPipelineStackProps(stack);
- props.filterPaths = ['some/path'];
- props.envName = AppEnvironment.Production;
-
- // Act
- const actual = new PipelineStack(stack, props);
-
- // Assert
- const template = Template.fromStack(actual);
- expect(template.toJSON()).toMatchSnapshot('pipelineWithFilterStackTest');
- });
-
- test('Should_CreatePipelineWithManualApproval_When_StackIsCalled', () => {
- // Arrange
- const stack = new Stack(new App(), 'pipelineWithFilterStackTest', {
- env,
- });
- const props = createPipelineStackProps(stack);
- props.manualApproval = true;
-
- // Act
- const actual = new PipelineStack(stack, props);
-
- // Assert
- const template = Template.fromStack(actual);
- expect(template.toJSON()).toMatchSnapshot('pipelineWithManualApproval');
- });
-
- test('Should_CreatePipelineWithNoCache_When_CacheConfigIsUndefined', () => {
- // Arrange
- const stack = new Stack(new App(), 'pipelineWithUndefinedCacheTest', {
- env,
- });
- const props = createPipelineStackProps(stack);
- // cacheConfig is undefined by default
-
- // Act
- const actual = new PipelineStack(stack, props);
-
- // Assert
- const template = Template.fromStack(actual);
- expect(template.toJSON()).toMatchSnapshot('pipelineWithUndefinedCache');
-
- // Verify deploy project has no cache configured (default behavior)
- template.hasResourceProperties('AWS::CodeBuild::Project', {
- Name: 'build-pipeline-deploy-envilder-test',
- Cache: {
- Type: 'NO_CACHE',
- },
- });
- });
-
- test('Should_CreatePipelineWithLocalCache_When_CacheConfigIsLocal', () => {
- // Arrange
- const stack = new Stack(new App(), 'pipelineWithLocalCacheTest', { env });
- const props = createPipelineStackProps(stack);
- props.cacheConfig = { type: 'local' };
-
- // Act
- const actual = new PipelineStack(stack, props);
-
- // Assert
- const template = Template.fromStack(actual);
- expect(template.toJSON()).toMatchSnapshot('pipelineWithLocalCache');
-
- // Verify deploy project has local cache configured with Docker layer and custom modes
- template.hasResourceProperties('AWS::CodeBuild::Project', {
- Name: 'build-pipeline-deploy-envilder-test',
- Cache: {
- Type: 'LOCAL',
- Modes: ['LOCAL_DOCKER_LAYER_CACHE', 'LOCAL_CUSTOM_CACHE'],
- },
- });
- });
-
- test('Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithDefaultBucket', () => {
- // Arrange
- const stack = new Stack(new App(), 'pipelineWithS3CacheDefaultTest', {
- env,
- });
- const props = createPipelineStackProps(stack);
- props.cacheConfig = { type: 's3' };
-
- // Act
- const actual = new PipelineStack(stack, props);
-
- // Assert
- const template = Template.fromStack(actual);
- expect(template.toJSON()).toMatchSnapshot('pipelineWithS3CacheDefault');
-
- // Verify deploy project has S3 cache configured with default bucket
- template.hasResourceProperties('AWS::CodeBuild::Project', {
- Name: 'build-pipeline-deploy-envilder-test',
- Cache: {
- Type: 'S3',
- Location: 'codebuild-eu-west-1-account/envilder',
- },
- });
- });
-
- test('Should_CreatePipelineWithS3Cache_When_CacheConfigIsS3WithCustomBucket', () => {
- // Arrange
- const stack = new Stack(new App(), 'pipelineWithS3CacheCustomTest', {
- env,
- });
- const props = createPipelineStackProps(stack);
- props.cacheConfig = { type: 's3', bucketName: 'my-custom-cache-bucket' };
-
- // Act
- const actual = new PipelineStack(stack, props);
-
- // Assert
- const template = Template.fromStack(actual);
- expect(template.toJSON()).toMatchSnapshot('pipelineWithS3CacheCustom');
-
- // Verify deploy project has S3 cache configured with custom bucket
- template.hasResourceProperties('AWS::CodeBuild::Project', {
- Name: 'build-pipeline-deploy-envilder-test',
- Cache: {
- Type: 'S3',
- Location: 'my-custom-cache-bucket/envilder',
- },
- });
- });
-
- function createPipelineStackProps(app: Stack): PipelineStackProps {
- return {
- name: 'FrontendPipelineStack',
- branch: 'main',
- githubRepo: 'envilder',
- envName: AppEnvironment.Test,
- secretTokenArn: `arn:aws:secretsmanager:${env.region}:${env.account}:secret:github-token`,
- deployBuildSpec: [`path/build-pipeline.yml`],
- testBuildSpec: [`path/test-pipeline.yml`],
- testProjectName: 'project-test',
- vpc: new Vpc(app, 'vpc'),
- env,
- environment: {
- SOME_KEY: {
- value: 'https://some-url-for-test',
- },
- },
- bucketRemovalPolicy: RemovalPolicy.DESTROY,
- domain: 'envilder-test',
- stackName: 'pipeline-stack',
- };
- }
-});
diff --git a/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts b/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
index 980ef2ad..010e1766 100644
--- a/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
+++ b/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
@@ -6,7 +6,6 @@ import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironme
import { ConfigValidationError } from '../../../../src/config/infrastructure/utilities/errors';
// Mock AWS infrastructure (VPC + CDK Stacks)
-jest.mock('../../../../src/aws/developerTools/codepipeline/pipelineStack');
jest.mock('../../../../src/aws/network/vpcLookupStack');
jest.mock('../../../../src/aws/website/staticWebsiteStack');
@@ -57,9 +56,6 @@ describe('DeployInfrastructureUseCase', () => {
frontend: {
staticWebsites: [],
},
- shared: {
- pipeline: [],
- },
},
};
}
diff --git a/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts b/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
index 324b2483..ebf5b6cf 100644
--- a/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
+++ b/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
@@ -2,7 +2,6 @@ import { App } from 'aws-cdk-lib';
import type { IDeploymentRequest } from '../../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
import { AppEnvironment } from '../../../../../src/config/domain/model/appEnvironment';
import { FrontendBuilder } from '../../../../../src/config/domain/builders/frontendBuilder';
-import { SharedBuilder } from '../../../../../src/config/domain/builders/sharedBuilder';
import { StackBuilderFactory } from '../../../../../src/config/domain/builders/factories/stackBuilderFactory';
describe('StackBuilderFactory', () => {
@@ -21,28 +20,11 @@ describe('StackBuilderFactory', () => {
frontend: {
staticWebsites: [],
},
- shared: {
- pipeline: [],
- },
},
};
}
describe('createStackParts', () => {
- test('Should_CreateBothStackParts_When_AllConfigsProvided', () => {
- // Arrange
- const app = new App();
- const config = createValidConfig();
-
- // Act
- const result = StackBuilderFactory.createStackParts(app, config);
-
- // Assert
- expect(result).toHaveLength(2);
- expect(result[0]).toBeInstanceOf(FrontendBuilder);
- expect(result[1]).toBeInstanceOf(SharedBuilder);
- });
-
test('Should_CreateFrontendBuilder_When_FrontendConfigProvided', () => {
// Arrange
const app = new App();
@@ -51,46 +33,12 @@ describe('StackBuilderFactory', () => {
// Act
const result = StackBuilderFactory.createStackParts(app, config);
- // Assert
- const frontendBuilder = result.find(
- (part) => part instanceof FrontendBuilder,
- );
- expect(frontendBuilder).toBeDefined();
- expect(frontendBuilder).toBeInstanceOf(FrontendBuilder);
- });
-
- test('Should_CreateSharedBuilder_When_SharedConfigProvided', () => {
- // Arrange
- const app = new App();
- const config = createValidConfig();
-
- // Act
- const result = StackBuilderFactory.createStackParts(app, config);
-
- // Assert
- const sharedBuilder = result.find(
- (part) => part instanceof SharedBuilder,
- );
- expect(sharedBuilder).toBeDefined();
- expect(sharedBuilder).toBeInstanceOf(SharedBuilder);
- });
-
- test('Should_CreateOnlyFrontendBuilder_When_OnlyFrontendConfigProvided', () => {
- // Arrange
- const app = new App();
- const config = createValidConfig();
- // biome-ignore lint/suspicious/noExplicitAny: testing undefined config
- config.stacks.shared = undefined as any;
-
- // Act
- const result = StackBuilderFactory.createStackParts(app, config);
-
// Assert
expect(result).toHaveLength(1);
expect(result[0]).toBeInstanceOf(FrontendBuilder);
});
- test('Should_CreateOnlySharedBuilder_When_OnlySharedConfigProvided', () => {
+ test('Should_ReturnEmptyArray_When_NoFrontendConfigProvided', () => {
// Arrange
const app = new App();
const config = createValidConfig();
@@ -100,23 +48,6 @@ describe('StackBuilderFactory', () => {
// Act
const result = StackBuilderFactory.createStackParts(app, config);
- // Assert
- expect(result).toHaveLength(1);
- expect(result[0]).toBeInstanceOf(SharedBuilder);
- });
-
- test('Should_ReturnEmptyArray_When_NoStackConfigsProvided', () => {
- // Arrange
- const app = new App();
- const config = createValidConfig();
- // biome-ignore lint/suspicious/noExplicitAny: testing undefined config
- config.stacks.frontend = undefined as any;
- // biome-ignore lint/suspicious/noExplicitAny: testing undefined config
- config.stacks.shared = undefined as any;
-
- // Act
- const result = StackBuilderFactory.createStackParts(app, config);
-
// Assert
expect(result).toHaveLength(0);
});
diff --git a/src/iac/test/config/domain/builders/frontendBuilder.test.ts b/src/iac/test/config/domain/builders/frontendBuilder.test.ts
index 60eb3743..8d2d37a9 100644
--- a/src/iac/test/config/domain/builders/frontendBuilder.test.ts
+++ b/src/iac/test/config/domain/builders/frontendBuilder.test.ts
@@ -27,7 +27,6 @@ describe('FrontendBuilder', () => {
frontend: {
staticWebsites: [],
},
- shared: {},
},
});
diff --git a/src/iac/test/config/domain/builders/sharedBuilder.test.ts b/src/iac/test/config/domain/builders/sharedBuilder.test.ts
deleted file mode 100644
index 5876a3bb..00000000
--- a/src/iac/test/config/domain/builders/sharedBuilder.test.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { SharedBuilder } from '../../../../src/config/domain/builders/sharedBuilder';
-import type { SharedBuilderProps } from '../../../../src/config/domain/builders/sharedBuilder';
-import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
-import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
-import type { IStackBuildContext } from '../../../../src/config/domain/iStackBuilder';
-import { App } from 'aws-cdk-lib';
-import type { IVpc } from 'aws-cdk-lib/aws-ec2';
-
-jest.mock('../../../../src/aws/developerTools/codepipeline/pipelineStack');
-
-describe('SharedBuilder', () => {
- const mockVpc = {} as IVpc;
- const mockEnv = { account: '123456789012', region: 'us-east-1' };
-
- const createMinimalConfig = (): IDeploymentRequest => ({
- repoName: 'test-repo',
- branch: 'main',
- vpcId: 'vpc-123',
- environment: AppEnvironment.Production,
- domain: {
- name: 'example.com',
- certificateId: 'cert-123',
- hostedZoneId: 'zone-123',
- },
- stacks: {
- shared: {},
- frontend: { staticWebsites: [] },
- },
- });
-
- const createBuilderProps = (
- iacConfig: IDeploymentRequest,
- ): SharedBuilderProps => ({
- scope: new App(),
- iacConfig,
- stackName: 'test-stack',
- });
-
- const createBuildContext = (): IStackBuildContext => ({
- vpc: mockVpc,
- env: mockEnv,
- environment: AppEnvironment.Production,
- });
-
- describe('build', () => {
- it('Should_CreatePipelineStack_When_PipelineConfigProvided', () => {
- const config = createMinimalConfig();
- config.stacks.shared = {
- pipeline: [
- {
- testBuildSpecs: ['test.yml'],
- deployBuildSpecs: ['deploy.yml'],
- manualApproval: false,
- },
- ],
- };
-
- const builder = new SharedBuilder(createBuilderProps(config));
-
- const actual = builder.build(createBuildContext());
-
- expect(actual).toHaveLength(1);
- });
-
- it('Should_ReturnEmptyArray_When_NoSharedStacksConfigured', () => {
- const config = createMinimalConfig();
- const builder = new SharedBuilder(createBuilderProps(config));
-
- const actual = builder.build(createBuildContext());
-
- expect(actual).toEqual([]);
- });
-
- it('Should_ThrowError_When_MissingRequiredConfig', () => {
- const config = createMinimalConfig();
- delete (config.stacks as { shared?: unknown }).shared;
-
- const action = () => new SharedBuilder(createBuilderProps(config));
-
- expect(action).toThrow('Shared stack configuration is required');
- });
- });
-});
diff --git a/src/iac/test/config/domain/iStackBuilder.test.ts b/src/iac/test/config/domain/iStackBuilder.test.ts
index 61ab345c..315658bd 100644
--- a/src/iac/test/config/domain/iStackBuilder.test.ts
+++ b/src/iac/test/config/domain/iStackBuilder.test.ts
@@ -41,7 +41,6 @@ describe('IStackBuilder', () => {
},
stacks: {
frontend: { staticWebsites: [] },
- shared: {},
},
});
diff --git a/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts b/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
index 6ba56840..f1f45364 100644
--- a/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
+++ b/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
@@ -37,7 +37,6 @@ describe('ConsoleDeploymentLogger', () => {
},
],
},
- shared: {},
},
});
diff --git a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
index c2c718d0..f61deb65 100644
--- a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
+++ b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
@@ -120,7 +120,11 @@ function normalizeObjectValues(obj: CloudFormationObject): void {
normalizeFnJoinExpression(obj);
for (const key in obj) {
- if (Object.hasOwn(obj, key) && obj[key] && typeof obj[key] === 'object') {
+ if (
+ Object.prototype.hasOwnProperty.call(obj, key) &&
+ obj[key] &&
+ typeof obj[key] === 'object'
+ ) {
normalizeAllDockerHashesRecursively(
obj[key] as CloudFormationObject | CloudFormationArray,
);
diff --git a/src/iac/test/config/infrastructure/validation/configValidator.test.ts b/src/iac/test/config/infrastructure/validation/configValidator.test.ts
index bee08133..82722006 100644
--- a/src/iac/test/config/infrastructure/validation/configValidator.test.ts
+++ b/src/iac/test/config/infrastructure/validation/configValidator.test.ts
@@ -25,9 +25,6 @@ describe('ConfigValidator', () => {
frontend: {
staticWebsites: [],
},
- shared: {
- pipeline: [],
- },
},
};
}
From 80e18381e0b046dfc4bc4b411a7e0beb01b33f2e Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 15:38:42 +0100
Subject: [PATCH 04/49] style(ui): Update Providers layout and enhance grid
responsiveness
---
.../website/src/components/Providers.astro | 15 ++++-
src/apps/website/src/styles/global.css | 59 ++++++++++---------
2 files changed, 46 insertions(+), 28 deletions(-)
diff --git a/src/apps/website/src/components/Providers.astro b/src/apps/website/src/components/Providers.astro
index 315243d2..b88e9c45 100644
--- a/src/apps/website/src/components/Providers.astro
+++ b/src/apps/website/src/components/Providers.astro
@@ -107,8 +107,9 @@ const t = useTranslations(lang);
display: grid;
grid-template-columns: 1fr;
gap: var(--space-xl);
- max-width: 800px;
+ max-width: 960px;
margin: 0 auto;
+ justify-items: center;
}
.provider-block {
@@ -118,6 +119,18 @@ const t = useTranslations(lang);
display: flex;
flex-direction: column;
gap: var(--space-lg);
+ width: 100%;
+ max-width: 520px;
+ }
+
+ @media (min-width: 768px) {
+ .providers-grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .provider-block {
+ max-width: none;
+ }
}
.provider-header {
diff --git a/src/apps/website/src/styles/global.css b/src/apps/website/src/styles/global.css
index b4ff3bb1..7621a5c5 100644
--- a/src/apps/website/src/styles/global.css
+++ b/src/apps/website/src/styles/global.css
@@ -18,31 +18,36 @@ html {
/* ── CSS Custom Properties ────────────────────────────── */
:root {
- /* Colors — Game Boy LCD neutral palette (retro / dark default) */
- --color-bg: #111311;
- --color-bg-alt: #151815;
- --color-surface: #1c1f1c;
- --color-surface-alt: #242824;
- --color-border: #343834;
- --color-border-light:#454a45;
-
- --color-primary: #8a9a6c;
- --color-primary-dim: #6b7a52;
- --color-secondary: #a0ac8e;
- --color-secondary-dim:#7a8868;
- --color-accent: #c8ceb8;
-
- --color-text: #c5c8c0;
- --color-text-muted: #8a8e86;
- --color-text-dim: #5c605a;
-
- --color-success: #8a9a6c;
- --color-warning: #b8b090;
- --color-error: #a05050;
-
- --color-nav-bg: rgba(17, 19, 17, 0.92);
- --color-nav-mobile: rgba(17, 19, 17, 0.98);
- --color-btn-text: #111311;
+ /*
+ * Game Boy — softened LCD palette
+ * Keeps the unmistakable GB green tint but dialled back
+ * so it's comfortable to read on a modern screen.
+ * Think Game Boy Pocket: same vibe, less eye-burn.
+ */
+ --color-bg: #1a2118; /* very dark green-black */
+ --color-bg-alt: #1f2a1d; /* slightly lighter band */
+ --color-surface: #253024; /* card/panel background */
+ --color-surface-alt: #2a362a; /* surface hover */
+ --color-border: #3a4a38; /* subtle green border */
+ --color-border-light:#4d5f4a; /* lighter border */
+
+ --color-primary: #8bac0f; /* THE Game Boy green — used sparingly */
+ --color-primary-dim: #6d8a0c; /* dimmed primary */
+ --color-secondary: #7a9a3a; /* softer secondary green */
+ --color-secondary-dim:#5a7a2a; /* muted secondary */
+ --color-accent: #9bbc0f; /* full LCD green for highlights */
+
+ --color-text: #c2d1a0; /* soft sage — easy on the eyes */
+ --color-text-muted: #8a9a72; /* muted green-grey */
+ --color-text-dim: #5a6a4a; /* hint text */
+
+ --color-success: #8bac0f; /* GB green */
+ --color-warning: #b8b060; /* warm yellow-green */
+ --color-error: #a06050; /* muted red (small concession) */
+
+ --color-nav-bg: rgba(26, 33, 24, 0.95);
+ --color-nav-mobile: rgba(26, 33, 24, 0.98);
+ --color-btn-text: #1a2118; /* dark bg for button labels */
/* Typography */
--font-pixel: 'Press Start 2P', monospace;
@@ -66,8 +71,8 @@ html {
/* Effects */
--pixel-shadow: 4px 4px 0 var(--color-border);
--pixel-shadow-primary: 4px 4px 0 var(--color-primary-dim);
- --glow-primary: 0 0 20px rgba(138, 154, 108, 0.3);
- --glow-secondary: 0 0 15px rgba(160, 172, 142, 0.2);
+ --glow-primary: 0 0 20px rgba(139, 172, 15, 0.15);
+ --glow-secondary: 0 0 12px rgba(155, 188, 15, 0.10);
/* Transitions */
--transition-fast: 150ms ease;
From 46812da5d4ae5cd3d99faf54efab63bef8ff424d Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 15:44:50 +0100
Subject: [PATCH 05/49] style(ui): Adjust Providers grid for better
responsiveness
---
src/apps/website/src/components/Providers.astro | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/apps/website/src/components/Providers.astro b/src/apps/website/src/components/Providers.astro
index b88e9c45..663cfd77 100644
--- a/src/apps/website/src/components/Providers.astro
+++ b/src/apps/website/src/components/Providers.astro
@@ -121,6 +121,8 @@ const t = useTranslations(lang);
gap: var(--space-lg);
width: 100%;
max-width: 520px;
+ min-width: 0;
+ overflow: hidden;
}
@media (min-width: 768px) {
From e24abf2f0f5dd8dec3034aa497bd4938ac211e9e Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 20:00:12 +0100
Subject: [PATCH 06/49] refactor(iac): Update domain configuration for
consistency
---
src/apps/website/src/components/DemoVideo.astro | 8 --------
src/apps/website/src/styles/global.css | 13 +++++++++++++
src/iac/src/infra/iacConfig.ts | 6 +++---
.../infrastructure/utilities/templateNormalizer.ts | 6 +-----
4 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/src/apps/website/src/components/DemoVideo.astro b/src/apps/website/src/components/DemoVideo.astro
index 35f0eaa0..6531df5d 100644
--- a/src/apps/website/src/components/DemoVideo.astro
+++ b/src/apps/website/src/components/DemoVideo.astro
@@ -26,14 +26,6 @@ const t = useTranslations(lang);
{t.demo.comingSoon}
-
-
-
-
▶
-
{t.demo.ghaWorkflow}
-
{t.demo.comingSoon}
-
-
diff --git a/src/apps/website/src/styles/global.css b/src/apps/website/src/styles/global.css
index 7621a5c5..f8a6b2fa 100644
--- a/src/apps/website/src/styles/global.css
+++ b/src/apps/website/src/styles/global.css
@@ -162,6 +162,19 @@ body {
line-height: 1.7;
font-size: 1rem;
overflow-x: hidden;
+ cursor: default;
+}
+
+h1, h2, h3, h4, h5, h6,
+p, li, span, label,
+.pixel-card, .section-title,
+.step, .feature-card {
+ cursor: default;
+}
+
+code, pre, .codeblock {
+ cursor: text;
+ user-select: text;
}
img, video {
diff --git a/src/iac/src/infra/iacConfig.ts b/src/iac/src/infra/iacConfig.ts
index 681d0d5d..9d872b03 100644
--- a/src/iac/src/infra/iacConfig.ts
+++ b/src/iac/src/infra/iacConfig.ts
@@ -8,9 +8,9 @@ export const iacConfig: IDeploymentConfig = {
vpcId: 'vpc-ee04cd97',
environment: AppEnvironment.Production,
domain: {
- name: 'envilder.io',
- certificateId: 'be63062d-5316-47af-9f94-819c1dc02853',
- hostedZoneId: 'Z0832486XTB67JEGNLMB',
+ name: 'envilder.com',
+ certificateId: 'e04983fe-1561-4ebe-9166-83f77789964a',
+ hostedZoneId: 'Z0718467FEEOZ35UNCTO',
},
stacks: {
frontend: frontendConfig,
diff --git a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
index f61deb65..29573d56 100644
--- a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
+++ b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
@@ -120,11 +120,7 @@ function normalizeObjectValues(obj: CloudFormationObject): void {
normalizeFnJoinExpression(obj);
for (const key in obj) {
- if (
- Object.prototype.hasOwnProperty.call(obj, key) &&
- obj[key] &&
- typeof obj[key] === 'object'
- ) {
+ if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key] && typeof obj[key] === 'object') {
normalizeAllDockerHashesRecursively(
obj[key] as CloudFormationObject | CloudFormationArray,
);
From 7a7c0e4610df3fbc90ede151abf6eecb2c682433 Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 20:04:08 +0100
Subject: [PATCH 07/49] refactor(utilities): Improve readability of
normalizeObjectValues
---
.../config/infrastructure/utilities/templateNormalizer.ts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
index 29573d56..f61deb65 100644
--- a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
+++ b/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
@@ -120,7 +120,11 @@ function normalizeObjectValues(obj: CloudFormationObject): void {
normalizeFnJoinExpression(obj);
for (const key in obj) {
- if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key] && typeof obj[key] === 'object') {
+ if (
+ Object.prototype.hasOwnProperty.call(obj, key) &&
+ obj[key] &&
+ typeof obj[key] === 'object'
+ ) {
normalizeAllDockerHashesRecursively(
obj[key] as CloudFormationObject | CloudFormationArray,
);
From 0af9b981f78a56ef8f68b022a4eba1f98caadba9 Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 22:22:27 +0100
Subject: [PATCH 08/49] test(iac): Add comprehensive tests for deployment
logging, path resolution, and validation
---
.github/agents/i18n-reviewer.agent.md | 136 +
pnpm-lock.yaml | 22 +-
pnpm-workspace.yaml | 2 +
.../website/src/components/DemoVideo.astro | 81 +-
.../website/S3CloudfrontUrlParametersFix.md | 0
.../aws/website/staticWebsiteStack.ts | 0
src/iac/cdk.json | 2 +-
.../deployInfrastructureHandler.ts | 7 -
.../models/deploymentRequest.ts | 3 -
.../builders/factories/stackBuilderFactory.ts | 0
.../config/domain/builders/frontendBuilder.ts | 0
.../{src => }/config/domain/customStack.ts | 0
.../{src => }/config/domain/iStackBuilder.ts | 2 -
.../config/domain/model/appEnvironment.ts | 0
.../config/domain/model/deploymentConfig.ts | 1 -
.../config/domain/model/stackConfig.ts | 0
.../config/domain/ports/iFileOperations.ts | 0
.../{src => }/config/domain/ports/iLogger.ts | 0
.../config/domain/ports/iProjectPath.ts | 0
.../domain/services/stackBuilderService.ts | 3 -
.../domain/validation/configValidator.ts | 4 -
.../fileOperations/fileOperations.ts | 0
.../logging/consoleDeploymentLogger.ts | 0
.../projectPath/fileProjectPath.ts | 0
.../utilities/cloudFormationUtils.ts | 0
.../config/infrastructure/utilities/errors.ts | 0
.../infrastructure/utilities/stringUtils.ts | 0
.../infra/buildspecs/production/website.yml | 0
.../infra/buildspecs/test/website.yml | 0
.../{src => }/infra/config/frontendConfig.ts | 0
src/iac/{src => }/infra/iac.ts | 0
src/iac/{src => }/infra/iacConfig.ts | 1 -
src/iac/package.json | 15 +-
src/iac/pnpm-lock.yaml | 2759 -----------------
src/iac/src/aws/network/vpcLookupStack.ts | 24 -
src/iac/src/aws/network/vpcStack.ts | 112 -
.../src/aws/website/cloudfront-url-rewrite.js | 54 -
.../__snapshots__/vpcStack.test.ts.snap | 612 ----
.../test/aws/network/vpcLookupStack.test.ts | 107 -
src/iac/test/aws/network/vpcStack.test.ts | 61 -
.../test => tests/iac}/aws/website/Dockerfile | 0
.../staticWebsiteStack.test.ts.snap | 0
.../aws/website/cloudfrontUrlRewrite.test.ts | 2 +-
.../aws/website/staticWebsiteStack.test.ts | 6 +-
.../deployInfrastructureHandler.test.ts | 16 +-
.../factories/stackBuilderFactory.test.ts | 9 +-
.../domain/builders/frontendBuilder.test.ts | 18 +-
.../iac}/config/domain/iStackBuilder.test.ts | 9 +-
.../iac}/config/domain/m47Stack.test.ts | 4 +-
.../domain/model/appEnvironment.test.ts | 2 +-
.../services/stackBuilderService.test.ts | 18 +-
.../fileOperations/fileOperations.test.ts | 4 +-
.../logging/consoleDeploymentLogger.test.ts | 9 +-
.../projectPath/fileProjectPath.test.ts | 2 +-
.../utilities/cloudFormationUtils.test.ts | 2 +-
.../infrastructure/utilities/errors.test.ts | 7 +-
.../utilities/templateNormalizer.ts | 0
.../validation/configValidator.test.ts | 32 +-
{src => tests}/iac/jest.config.js | 11 +-
tests/iac/package.json | 20 +
tests/iac/tsconfig.json | 12 +
61 files changed, 267 insertions(+), 3924 deletions(-)
create mode 100644 .github/agents/i18n-reviewer.agent.md
rename src/iac/{src => }/aws/website/S3CloudfrontUrlParametersFix.md (100%)
rename src/iac/{src => }/aws/website/staticWebsiteStack.ts (100%)
rename src/iac/{src => }/config/application/deployInfrastructure/deployInfrastructureHandler.ts (91%)
rename src/iac/{src => }/config/application/deployInfrastructure/models/deploymentRequest.ts (95%)
rename src/iac/{src => }/config/domain/builders/factories/stackBuilderFactory.ts (100%)
rename src/iac/{src => }/config/domain/builders/frontendBuilder.ts (100%)
rename src/iac/{src => }/config/domain/customStack.ts (100%)
rename src/iac/{src => }/config/domain/iStackBuilder.ts (95%)
rename src/iac/{src => }/config/domain/model/appEnvironment.ts (100%)
rename src/iac/{src => }/config/domain/model/deploymentConfig.ts (96%)
rename src/iac/{src => }/config/domain/model/stackConfig.ts (100%)
rename src/iac/{src => }/config/domain/ports/iFileOperations.ts (100%)
rename src/iac/{src => }/config/domain/ports/iLogger.ts (100%)
rename src/iac/{src => }/config/domain/ports/iProjectPath.ts (100%)
rename src/iac/{src => }/config/domain/services/stackBuilderService.ts (95%)
rename src/iac/{src => }/config/domain/validation/configValidator.ts (95%)
rename src/iac/{src => }/config/infrastructure/fileOperations/fileOperations.ts (100%)
rename src/iac/{src => }/config/infrastructure/logging/consoleDeploymentLogger.ts (100%)
rename src/iac/{src => }/config/infrastructure/projectPath/fileProjectPath.ts (100%)
rename src/iac/{src => }/config/infrastructure/utilities/cloudFormationUtils.ts (100%)
rename src/iac/{src => }/config/infrastructure/utilities/errors.ts (100%)
rename src/iac/{src => }/config/infrastructure/utilities/stringUtils.ts (100%)
rename src/iac/{src => }/infra/buildspecs/production/website.yml (100%)
rename src/iac/{src => }/infra/buildspecs/test/website.yml (100%)
rename src/iac/{src => }/infra/config/frontendConfig.ts (100%)
rename src/iac/{src => }/infra/iac.ts (100%)
rename src/iac/{src => }/infra/iacConfig.ts (95%)
delete mode 100644 src/iac/pnpm-lock.yaml
delete mode 100644 src/iac/src/aws/network/vpcLookupStack.ts
delete mode 100644 src/iac/src/aws/network/vpcStack.ts
delete mode 100644 src/iac/src/aws/website/cloudfront-url-rewrite.js
delete mode 100644 src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap
delete mode 100644 src/iac/test/aws/network/vpcLookupStack.test.ts
delete mode 100644 src/iac/test/aws/network/vpcStack.test.ts
rename {src/iac/test => tests/iac}/aws/website/Dockerfile (100%)
rename {src/iac/test => tests/iac}/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap (100%)
rename {src/iac/test => tests/iac}/aws/website/cloudfrontUrlRewrite.test.ts (98%)
rename {src/iac/test => tests/iac}/aws/website/staticWebsiteStack.test.ts (91%)
rename {src/iac/test => tests/iac}/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts (80%)
rename {src/iac/test => tests/iac}/config/domain/builders/factories/stackBuilderFactory.test.ts (74%)
rename {src/iac/test => tests/iac}/config/domain/builders/frontendBuilder.test.ts (72%)
rename {src/iac/test => tests/iac}/config/domain/iStackBuilder.test.ts (86%)
rename {src/iac/test => tests/iac}/config/domain/m47Stack.test.ts (95%)
rename {src/iac/test => tests/iac}/config/domain/model/appEnvironment.test.ts (96%)
rename {src/iac/test => tests/iac}/config/domain/services/stackBuilderService.test.ts (86%)
rename {src/iac/test => tests/iac}/config/infrastructure/fileOperations/fileOperations.test.ts (97%)
rename {src/iac/test => tests/iac}/config/infrastructure/logging/consoleDeploymentLogger.test.ts (85%)
rename {src/iac/test => tests/iac}/config/infrastructure/projectPath/fileProjectPath.test.ts (97%)
rename {src/iac/test => tests/iac}/config/infrastructure/utilities/cloudFormationUtils.test.ts (97%)
rename {src/iac/test => tests/iac}/config/infrastructure/utilities/errors.test.ts (97%)
rename {src/iac/test => tests/iac}/config/infrastructure/utilities/templateNormalizer.ts (100%)
rename {src/iac/test => tests/iac}/config/infrastructure/validation/configValidator.test.ts (87%)
rename {src => tests}/iac/jest.config.js (65%)
create mode 100644 tests/iac/package.json
create mode 100644 tests/iac/tsconfig.json
diff --git a/.github/agents/i18n-reviewer.agent.md b/.github/agents/i18n-reviewer.agent.md
new file mode 100644
index 00000000..42e65755
--- /dev/null
+++ b/.github/agents/i18n-reviewer.agent.md
@@ -0,0 +1,136 @@
+---
+name: i18n Reviewer
+description: >
+ Linguistic review agent for the Envilder website translations. Use when
+ auditing i18n quality, finding untranslated or hardcoded strings, checking
+ grammar/spelling across all locales (EN, CA, ES), or verifying that technical
+ terms are correctly preserved. Browses the live site, cross-references source
+ translation files and Astro components, produces a structured report, then
+ delegates fixes to a subagent.
+tools: [read, search, web, agent, todo, edit, execute]
+argument-hint: "locale to review, page URL, or 'full audit'"
+user-invocable: true
+---
+
+# i18n Reviewer — Multilingual Linguistic Auditor
+
+You are a specialist linguist and i18n auditor for the Envilder website (Astro +
+TypeScript). You are fluent in English, Catalan (CA), and Spanish (ES). You
+understand software localisation conventions — specifically when technical terms
+(CLI flags, product names, cloud service names, code tokens) must NOT be
+translated.
+
+## Context
+
+- The website source lives under `src/apps/website/`
+- Translation strings are in `src/apps/website/src/i18n/{en,ca,es}.ts`
+- Type definitions: `src/apps/website/src/i18n/types.ts`
+- Astro components: `src/apps/website/src/components/*.astro`
+- Layouts: `src/apps/website/src/layouts/*.astro`
+- The site runs at `http://localhost:4322/` with locale prefixes `/ca/` and `/es/`
+- Pages: homepage (`/`), docs (`/docs`), changelog (`/changelog`)
+
+## Terms that MUST NOT be translated
+
+These are product names, CLI flags, code tokens, or industry-standard terms:
+
+- Product/service names: `envilder`, `AWS SSM`, `Azure Key Vault`, `GitHub Action`,
+ `GitHub Actions`, `CloudTrail`, `Azure Monitor`, `Astro`, `npm`, `pnpm`, `npx`,
+ `Lambdas`, `Node.js`
+- CLI flags: `--provider`, `--vault-url`, `--profile`, `--push`, `--exec`,
+ `--check`, `--auto`, `--map`, `--envfile`, `--secret-path`, `--ssm-path`
+- Code tokens: `$config`, `param-map.json`, `.env`, `GetParameter`,
+ `WithDecryption`, `DefaultAzureCredential`, `env-file-path`,
+ `ssm:GetParameter`, `ssm:PutParameter`
+- Acronyms: `IAM`, `RBAC`, `CI/CD`, `MIT`, `CLI`, `GHA`, `API`, `JSON`, `YAML`
+- File paths in code examples or terminal output
+
+## Audit Workflow
+
+### Phase 1 — Discovery (read-only)
+
+Use the todo tool to track progress through each page and locale.
+
+1. **Browse all pages** in each locale using browser tools:
+ - EN: `/`, `/docs`, `/changelog`
+ - CA: `/ca/`, `/ca/docs`, `/ca/changelog`
+ - ES: `/es/`, `/es/docs`, `/es/changelog`
+2. **Read source translation files** (`en.ts`, `ca.ts`, `es.ts`) and compare:
+ - Every i18n key has a translation in all locales
+ - No English text leaks into CA/ES translations
+ - Grammar, spelling, and naturalness are correct
+3. **Scan Astro components and layouts** for hardcoded strings:
+ - Search for English text directly in `.astro` files that should use `t.*`
+ - Check ``, ` `, dates, table cells, badges, labels
+ - Flag any string visible to users that bypasses the i18n system
+4. **Check technical terms** are correctly preserved (not translated)
+5. **Verify date formats** are localised per locale conventions
+
+### Phase 2 — Report
+
+Produce a structured markdown report with these sections:
+
+#### Critical: Hardcoded strings (not in i18n)
+
+Table: `| # | File | Hardcoded text (EN) | CA proposal | ES proposal |`
+
+#### Translation errors
+
+Table: `| # | Locale | i18n key | Current text | Issue | Proposed fix |`
+
+Categories of issues:
+
+- **Spelling/grammar**: Misspellings, wrong accents, incorrect verb forms
+- **Untranslated**: English text present in CA/ES locale
+- **Unnatural phrasing**: Technically correct but reads awkwardly
+- **Anglicism**: English loanword where a native equivalent exists (flag but
+ accept if standard in tech industry)
+- **Inconsistency**: Same concept translated differently across sections
+
+#### Correctly preserved terms
+
+Briefly confirm that technical terms are NOT translated.
+
+#### Summary
+
+- Total critical issues, translation errors, and minor suggestions
+- Overall quality assessment per locale
+
+### Phase 3 — Apply fixes
+
+After presenting the report, ask the user if they want to proceed with fixes.
+When confirmed, delegate the implementation to a subagent:
+
+1. **For hardcoded strings**: The subagent must:
+ - Add new i18n keys to `types.ts`
+ - Add EN values to `en.ts`
+ - Add CA values to `ca.ts`
+ - Add ES values to `es.ts`
+ - Update the `.astro` component to use `t.newKey` instead of the hardcoded string
+2. **For translation errors**: The subagent updates the value in the
+ corresponding locale file (`ca.ts` or `es.ts`)
+3. After all edits, rebuild the site to verify: `cd src/apps/website && pnpm build`
+
+When delegating, provide the subagent with:
+
+- The exact file paths and line numbers
+- The exact current string (oldString) and the replacement (newString)
+- Clear instructions to preserve formatting, indentation, and surrounding code
+
+## Constraints
+
+- DO NOT modify any code outside `src/apps/website/`
+- DO NOT translate CLI flags, product names, or code tokens listed above
+- DO NOT change the i18n architecture or type system structure
+- DO NOT add new i18n keys without also adding values for ALL three locales
+- DO NOT touch terminal mockup content or code block content — these simulate
+ real CLI output and must stay in English
+- ONLY flag issues you are confident about — mark uncertain items as suggestions
+- ALWAYS present the report before making any edits
+- ALWAYS rebuild and verify after applying changes
+
+## Output Format
+
+Start with a brief status of what was audited, then deliver the full report
+using the tables above. End with a clear action prompt asking whether to proceed
+with fixes.
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0d932c4e..6435f6ad 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -108,22 +108,34 @@ importers:
constructs:
specifier: ^10.4.2
version: 10.6.0
+ devDependencies:
+ aws-cdk:
+ specifier: ^2.200.0
+ version: 2.1114.1
+ ts-node:
+ specifier: ^10.9.2
+ version: 10.9.2(@types/node@25.3.3)(typescript@5.9.3)
+ typescript:
+ specifier: ^5.9.3
+ version: 5.9.3
+
+ tests/iac:
devDependencies:
'@types/jest':
specifier: ^29.5.14
version: 29.5.14
- aws-cdk:
+ aws-cdk-lib:
specifier: ^2.200.0
- version: 2.1114.1
+ version: 2.244.0(constructs@10.6.0)
+ constructs:
+ specifier: ^10.4.2
+ version: 10.6.0
jest:
specifier: ^29.7.0
version: 29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3))
ts-jest:
specifier: ^29.3.4
version: 29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.3.3)(ts-node@10.9.2(@types/node@25.3.3)(typescript@5.9.3)))(typescript@5.9.3)
- ts-node:
- specifier: ^10.9.2
- version: 10.9.2(@types/node@25.3.3)(typescript@5.9.3)
typescript:
specifier: ^5.9.3
version: 5.9.3
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index db6dd9d2..ff422ced 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,6 +1,8 @@
packages:
- "."
- "src/apps/website"
+ - "src/iac"
+ - "tests/iac"
onlyBuiltDependencies:
- cpu-features
diff --git a/src/apps/website/src/components/DemoVideo.astro b/src/apps/website/src/components/DemoVideo.astro
index 6531df5d..d3a14aea 100644
--- a/src/apps/website/src/components/DemoVideo.astro
+++ b/src/apps/website/src/components/DemoVideo.astro
@@ -18,84 +18,37 @@ const t = useTranslations(lang);
-
-
-
-
▶
-
{t.demo.cliDemo}
-
{t.demo.comingSoon}
-
+
+
+
diff --git a/src/iac/src/aws/website/S3CloudfrontUrlParametersFix.md b/src/iac/aws/website/S3CloudfrontUrlParametersFix.md
similarity index 100%
rename from src/iac/src/aws/website/S3CloudfrontUrlParametersFix.md
rename to src/iac/aws/website/S3CloudfrontUrlParametersFix.md
diff --git a/src/iac/src/aws/website/staticWebsiteStack.ts b/src/iac/aws/website/staticWebsiteStack.ts
similarity index 100%
rename from src/iac/src/aws/website/staticWebsiteStack.ts
rename to src/iac/aws/website/staticWebsiteStack.ts
diff --git a/src/iac/cdk.json b/src/iac/cdk.json
index e7a1fb08..aa2d51b3 100644
--- a/src/iac/cdk.json
+++ b/src/iac/cdk.json
@@ -1,5 +1,5 @@
{
- "app": "npx ts-node --prefer-ts-exts src/infra/iac.ts",
+ "app": "npx ts-node --prefer-ts-exts infra/iac.ts",
"profile": "mac",
"watch": {
"include": [
diff --git a/src/iac/src/config/application/deployInfrastructure/deployInfrastructureHandler.ts b/src/iac/config/application/deployInfrastructure/deployInfrastructureHandler.ts
similarity index 91%
rename from src/iac/src/config/application/deployInfrastructure/deployInfrastructureHandler.ts
rename to src/iac/config/application/deployInfrastructure/deployInfrastructureHandler.ts
index 94969a73..6992df96 100644
--- a/src/iac/src/config/application/deployInfrastructure/deployInfrastructureHandler.ts
+++ b/src/iac/config/application/deployInfrastructure/deployInfrastructureHandler.ts
@@ -1,5 +1,4 @@
import type { App, Environment, Stack } from 'aws-cdk-lib';
-import { VpcLookupStack } from '../../../aws/network/vpcLookupStack';
import { StackBuilderFactory } from '../../domain/builders/factories/stackBuilderFactory';
import type { ILogger } from '../../domain/ports/iLogger';
import type { IProjectPath } from '../../domain/ports/iProjectPath';
@@ -56,16 +55,10 @@ export class DeployInfrastructureHandler {
}
private buildStacks(): Stack[] {
- const vpcStack = new VpcLookupStack(this.app, {
- env: this.envFromCli,
- vpcId: this.request.vpcId,
- });
-
const stackBuilder = new StackBuilderService(
this.logger,
this.request.repoName,
this.envFromCli,
- vpcStack.vpc,
this.app.node,
this.request.environment,
);
diff --git a/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts b/src/iac/config/application/deployInfrastructure/models/deploymentRequest.ts
similarity index 95%
rename from src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
rename to src/iac/config/application/deployInfrastructure/models/deploymentRequest.ts
index 05bb24e1..934e3cfc 100644
--- a/src/iac/src/config/application/deployInfrastructure/models/deploymentRequest.ts
+++ b/src/iac/config/application/deployInfrastructure/models/deploymentRequest.ts
@@ -27,9 +27,6 @@ export interface IDeploymentRequest {
/** GitHub repository name */
repoName: string;
- /** AWS VPC ID for deployment */
- vpcId: string;
-
/** Git branch for deployment */
branch: string;
diff --git a/src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts b/src/iac/config/domain/builders/factories/stackBuilderFactory.ts
similarity index 100%
rename from src/iac/src/config/domain/builders/factories/stackBuilderFactory.ts
rename to src/iac/config/domain/builders/factories/stackBuilderFactory.ts
diff --git a/src/iac/src/config/domain/builders/frontendBuilder.ts b/src/iac/config/domain/builders/frontendBuilder.ts
similarity index 100%
rename from src/iac/src/config/domain/builders/frontendBuilder.ts
rename to src/iac/config/domain/builders/frontendBuilder.ts
diff --git a/src/iac/src/config/domain/customStack.ts b/src/iac/config/domain/customStack.ts
similarity index 100%
rename from src/iac/src/config/domain/customStack.ts
rename to src/iac/config/domain/customStack.ts
diff --git a/src/iac/src/config/domain/iStackBuilder.ts b/src/iac/config/domain/iStackBuilder.ts
similarity index 95%
rename from src/iac/src/config/domain/iStackBuilder.ts
rename to src/iac/config/domain/iStackBuilder.ts
index 176f7802..f19aa789 100644
--- a/src/iac/src/config/domain/iStackBuilder.ts
+++ b/src/iac/config/domain/iStackBuilder.ts
@@ -1,5 +1,4 @@
import type { Environment, Stack } from 'aws-cdk-lib';
-import type { IVpc } from 'aws-cdk-lib/aws-ec2';
import type { Construct } from 'constructs';
import type { IDeploymentRequest } from '../application/deployInfrastructure/models/deploymentRequest';
import { formatRepoNameForCloudFormation } from '../infrastructure/utilities/cloudFormationUtils';
@@ -13,7 +12,6 @@ export interface IStackBuildProps {
export interface IStackBuildContext {
env: Environment;
- vpc: IVpc;
environment: AppEnvironment;
}
diff --git a/src/iac/src/config/domain/model/appEnvironment.ts b/src/iac/config/domain/model/appEnvironment.ts
similarity index 100%
rename from src/iac/src/config/domain/model/appEnvironment.ts
rename to src/iac/config/domain/model/appEnvironment.ts
diff --git a/src/iac/src/config/domain/model/deploymentConfig.ts b/src/iac/config/domain/model/deploymentConfig.ts
similarity index 96%
rename from src/iac/src/config/domain/model/deploymentConfig.ts
rename to src/iac/config/domain/model/deploymentConfig.ts
index 84bf7c96..8fd8d020 100644
--- a/src/iac/src/config/domain/model/deploymentConfig.ts
+++ b/src/iac/config/domain/model/deploymentConfig.ts
@@ -7,7 +7,6 @@ import type { FrontendStackConfig } from './stackConfig';
export interface IDeploymentConfig {
repoName: string;
branch: string;
- vpcId: string;
environment: AppEnvironment;
domain: {
name: string;
diff --git a/src/iac/src/config/domain/model/stackConfig.ts b/src/iac/config/domain/model/stackConfig.ts
similarity index 100%
rename from src/iac/src/config/domain/model/stackConfig.ts
rename to src/iac/config/domain/model/stackConfig.ts
diff --git a/src/iac/src/config/domain/ports/iFileOperations.ts b/src/iac/config/domain/ports/iFileOperations.ts
similarity index 100%
rename from src/iac/src/config/domain/ports/iFileOperations.ts
rename to src/iac/config/domain/ports/iFileOperations.ts
diff --git a/src/iac/src/config/domain/ports/iLogger.ts b/src/iac/config/domain/ports/iLogger.ts
similarity index 100%
rename from src/iac/src/config/domain/ports/iLogger.ts
rename to src/iac/config/domain/ports/iLogger.ts
diff --git a/src/iac/src/config/domain/ports/iProjectPath.ts b/src/iac/config/domain/ports/iProjectPath.ts
similarity index 100%
rename from src/iac/src/config/domain/ports/iProjectPath.ts
rename to src/iac/config/domain/ports/iProjectPath.ts
diff --git a/src/iac/src/config/domain/services/stackBuilderService.ts b/src/iac/config/domain/services/stackBuilderService.ts
similarity index 95%
rename from src/iac/src/config/domain/services/stackBuilderService.ts
rename to src/iac/config/domain/services/stackBuilderService.ts
index aac16281..0aab9553 100644
--- a/src/iac/src/config/domain/services/stackBuilderService.ts
+++ b/src/iac/config/domain/services/stackBuilderService.ts
@@ -1,5 +1,4 @@
import type { Environment, Stack } from 'aws-cdk-lib';
-import type { IVpc } from 'aws-cdk-lib/aws-ec2';
import type { Node } from 'constructs';
import type { AppEnvironment } from '../../domain/model/appEnvironment';
import type { ILogger } from '../../domain/ports/iLogger';
@@ -14,7 +13,6 @@ export class StackBuilderService {
private readonly logger: ILogger,
private readonly githubRepo: string,
private readonly env: Environment,
- private readonly vpc: IVpc,
private readonly node: Node,
private readonly environment: AppEnvironment,
) {}
@@ -38,7 +36,6 @@ export class StackBuilderService {
const context = {
env: this.env,
- vpc: this.vpc,
environment: this.environment,
};
diff --git a/src/iac/src/config/domain/validation/configValidator.ts b/src/iac/config/domain/validation/configValidator.ts
similarity index 95%
rename from src/iac/src/config/domain/validation/configValidator.ts
rename to src/iac/config/domain/validation/configValidator.ts
index 333968a6..f4994ecd 100644
--- a/src/iac/src/config/domain/validation/configValidator.ts
+++ b/src/iac/config/domain/validation/configValidator.ts
@@ -18,10 +18,6 @@ export class ConfigValidator {
errors.push('repoName is required and cannot be empty');
}
- if (!config.vpcId || config.vpcId.trim() === '') {
- errors.push('vpcId is required and cannot be empty');
- }
-
if (!config.branch || config.branch.trim() === '') {
errors.push('branch is required and cannot be empty');
}
diff --git a/src/iac/src/config/infrastructure/fileOperations/fileOperations.ts b/src/iac/config/infrastructure/fileOperations/fileOperations.ts
similarity index 100%
rename from src/iac/src/config/infrastructure/fileOperations/fileOperations.ts
rename to src/iac/config/infrastructure/fileOperations/fileOperations.ts
diff --git a/src/iac/src/config/infrastructure/logging/consoleDeploymentLogger.ts b/src/iac/config/infrastructure/logging/consoleDeploymentLogger.ts
similarity index 100%
rename from src/iac/src/config/infrastructure/logging/consoleDeploymentLogger.ts
rename to src/iac/config/infrastructure/logging/consoleDeploymentLogger.ts
diff --git a/src/iac/src/config/infrastructure/projectPath/fileProjectPath.ts b/src/iac/config/infrastructure/projectPath/fileProjectPath.ts
similarity index 100%
rename from src/iac/src/config/infrastructure/projectPath/fileProjectPath.ts
rename to src/iac/config/infrastructure/projectPath/fileProjectPath.ts
diff --git a/src/iac/src/config/infrastructure/utilities/cloudFormationUtils.ts b/src/iac/config/infrastructure/utilities/cloudFormationUtils.ts
similarity index 100%
rename from src/iac/src/config/infrastructure/utilities/cloudFormationUtils.ts
rename to src/iac/config/infrastructure/utilities/cloudFormationUtils.ts
diff --git a/src/iac/src/config/infrastructure/utilities/errors.ts b/src/iac/config/infrastructure/utilities/errors.ts
similarity index 100%
rename from src/iac/src/config/infrastructure/utilities/errors.ts
rename to src/iac/config/infrastructure/utilities/errors.ts
diff --git a/src/iac/src/config/infrastructure/utilities/stringUtils.ts b/src/iac/config/infrastructure/utilities/stringUtils.ts
similarity index 100%
rename from src/iac/src/config/infrastructure/utilities/stringUtils.ts
rename to src/iac/config/infrastructure/utilities/stringUtils.ts
diff --git a/src/iac/src/infra/buildspecs/production/website.yml b/src/iac/infra/buildspecs/production/website.yml
similarity index 100%
rename from src/iac/src/infra/buildspecs/production/website.yml
rename to src/iac/infra/buildspecs/production/website.yml
diff --git a/src/iac/src/infra/buildspecs/test/website.yml b/src/iac/infra/buildspecs/test/website.yml
similarity index 100%
rename from src/iac/src/infra/buildspecs/test/website.yml
rename to src/iac/infra/buildspecs/test/website.yml
diff --git a/src/iac/src/infra/config/frontendConfig.ts b/src/iac/infra/config/frontendConfig.ts
similarity index 100%
rename from src/iac/src/infra/config/frontendConfig.ts
rename to src/iac/infra/config/frontendConfig.ts
diff --git a/src/iac/src/infra/iac.ts b/src/iac/infra/iac.ts
similarity index 100%
rename from src/iac/src/infra/iac.ts
rename to src/iac/infra/iac.ts
diff --git a/src/iac/src/infra/iacConfig.ts b/src/iac/infra/iacConfig.ts
similarity index 95%
rename from src/iac/src/infra/iacConfig.ts
rename to src/iac/infra/iacConfig.ts
index 9d872b03..955868f2 100644
--- a/src/iac/src/infra/iacConfig.ts
+++ b/src/iac/infra/iacConfig.ts
@@ -5,7 +5,6 @@ import { frontendConfig } from './config/frontendConfig';
export const iacConfig: IDeploymentConfig = {
repoName: 'envilder',
branch: 'main',
- vpcId: 'vpc-ee04cd97',
environment: AppEnvironment.Production,
domain: {
name: 'envilder.com',
diff --git a/src/iac/package.json b/src/iac/package.json
index b1369b94..3d65c2b7 100644
--- a/src/iac/package.json
+++ b/src/iac/package.json
@@ -5,25 +5,18 @@
"scripts": {
"build": "tsc --build",
"watch": "tsc -w",
- "test": "jest --colors --seed=1",
- "test:update": "jest --colors --seed=1 --updateSnapshot --verbose",
- "test:ci": "jest --colors --seed=1 --ci --verbose",
- "test:ci:update": "jest --colors --seed=1 --ci --updateSnapshot --verbose",
"cdk": "cdk",
- "lint": "biome lint ./src ./test",
- "lint:fix": "biome lint --fix ./src ./test",
- "format": "biome format ./src ./test",
- "format:write": "biome format --write ./src ./test"
+ "lint": "biome lint ./aws ./config ./infra",
+ "lint:fix": "biome lint --fix ./aws ./config ./infra",
+ "format": "biome format ./aws ./config ./infra",
+ "format:write": "biome format --write ./aws ./config ./infra"
},
"dependencies": {
"aws-cdk-lib": "^2.200.0",
"constructs": "^10.4.2"
},
"devDependencies": {
- "@types/jest": "^29.5.14",
"aws-cdk": "^2.200.0",
- "jest": "^29.7.0",
- "ts-jest": "^29.3.4",
"ts-node": "^10.9.2",
"typescript": "^5.9.3"
}
diff --git a/src/iac/pnpm-lock.yaml b/src/iac/pnpm-lock.yaml
deleted file mode 100644
index a6cfacd6..00000000
--- a/src/iac/pnpm-lock.yaml
+++ /dev/null
@@ -1,2759 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- aws-cdk-lib:
- specifier: ^2.200.0
- version: 2.244.0(constructs@10.6.0)
- constructs:
- specifier: ^10.4.2
- version: 10.6.0
- devDependencies:
- '@types/jest':
- specifier: ^29.5.14
- version: 29.5.14
- aws-cdk:
- specifier: ^2.200.0
- version: 2.1114.1
- jest:
- specifier: ^29.7.0
- version: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- ts-jest:
- specifier: ^29.3.4
- version: 29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3)
- ts-node:
- specifier: ^10.9.2
- version: 10.9.2(@types/node@25.5.0)(typescript@5.9.3)
- typescript:
- specifier: ^5.9.3
- version: 5.9.3
-
-packages:
-
- '@aws-cdk/asset-awscli-v1@2.2.263':
- resolution: {integrity: sha512-X9JvcJhYcb7PHs8R7m4zMablO5C9PGb/hYfLnxds9h/rKJu6l7MiXE/SabCibuehxPnuO/vk+sVVJiUWrccarQ==}
-
- '@aws-cdk/asset-node-proxy-agent-v6@2.1.1':
- resolution: {integrity: sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==}
-
- '@aws-cdk/cloud-assembly-schema@52.2.0':
- resolution: {integrity: sha512-ourZjixQ/UfsZc7gdk3vt1eHBODMUjQTYYYCY3ZX8fiXyHtWNDAYZPrXUK96jpCC2fLP+tfHTJrBjZ563pmcEw==}
- engines: {node: '>= 18.0.0'}
- bundledDependencies:
- - jsonschema
- - semver
-
- '@babel/code-frame@7.29.0':
- resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/compat-data@7.29.0':
- resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/core@7.29.0':
- resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/generator@7.29.1':
- resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-compilation-targets@7.28.6':
- resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-globals@7.28.0':
- resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-imports@7.28.6':
- resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.28.6':
- resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- '@babel/helper-plugin-utils@7.28.6':
- resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-string-parser@7.27.1':
- resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-identifier@7.28.5':
- resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-option@7.27.1':
- resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helpers@7.29.2':
- resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/parser@7.29.2':
- resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- '@babel/plugin-syntax-async-generators@7.8.4':
- resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-bigint@7.8.3':
- resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-properties@7.12.13':
- resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-static-block@7.14.5':
- resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-import-attributes@7.28.6':
- resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-import-meta@7.10.4':
- resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-json-strings@7.8.3':
- resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-jsx@7.28.6':
- resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
- resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
- resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-numeric-separator@7.10.4':
- resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3':
- resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3':
- resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-chaining@7.8.3':
- resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5':
- resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-top-level-await@7.14.5':
- resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-typescript@7.28.6':
- resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/template@7.28.6':
- resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/traverse@7.29.0':
- resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/types@7.29.0':
- resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
- engines: {node: '>=6.9.0'}
-
- '@bcoe/v8-coverage@0.2.3':
- resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
-
- '@cspotcode/source-map-support@0.8.1':
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
-
- '@istanbuljs/load-nyc-config@1.1.0':
- resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
- engines: {node: '>=8'}
-
- '@istanbuljs/schema@0.1.3':
- resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
- engines: {node: '>=8'}
-
- '@jest/console@29.7.0':
- resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/core@29.7.0':
- resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- '@jest/environment@29.7.0':
- resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect-utils@29.7.0':
- resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/expect@29.7.0':
- resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/fake-timers@29.7.0':
- resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/globals@29.7.0':
- resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/reporters@29.7.0':
- resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- '@jest/schemas@29.6.3':
- resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/source-map@29.6.3':
- resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-result@29.7.0':
- resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-sequencer@29.7.0':
- resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/transform@29.7.0':
- resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/types@29.6.3':
- resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jridgewell/gen-mapping@0.3.13':
- resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
-
- '@jridgewell/remapping@2.3.5':
- resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
-
- '@jridgewell/resolve-uri@3.1.2':
- resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/sourcemap-codec@1.5.5':
- resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
-
- '@jridgewell/trace-mapping@0.3.31':
- resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
-
- '@jridgewell/trace-mapping@0.3.9':
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
-
- '@sinclair/typebox@0.27.10':
- resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==}
-
- '@sinonjs/commons@3.0.1':
- resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
-
- '@sinonjs/fake-timers@10.3.0':
- resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
-
- '@tsconfig/node10@1.0.12':
- resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==}
-
- '@tsconfig/node12@1.0.11':
- resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
-
- '@tsconfig/node14@1.0.3':
- resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
-
- '@tsconfig/node16@1.0.4':
- resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
-
- '@types/babel__core@7.20.5':
- resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
-
- '@types/babel__generator@7.27.0':
- resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
-
- '@types/babel__template@7.4.4':
- resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
-
- '@types/babel__traverse@7.28.0':
- resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
-
- '@types/graceful-fs@4.1.9':
- resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
-
- '@types/istanbul-lib-coverage@2.0.6':
- resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
-
- '@types/istanbul-lib-report@3.0.3':
- resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
-
- '@types/istanbul-reports@3.0.4':
- resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
-
- '@types/jest@29.5.14':
- resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
-
- '@types/node@25.5.0':
- resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==}
-
- '@types/stack-utils@2.0.3':
- resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
-
- '@types/yargs-parser@21.0.3':
- resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
-
- '@types/yargs@17.0.35':
- resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==}
-
- acorn-walk@8.3.5:
- resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==}
- engines: {node: '>=0.4.0'}
-
- acorn@8.16.0:
- resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
- engines: {node: '>=0.4.0'}
- hasBin: true
-
- ansi-escapes@4.3.2:
- resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
- engines: {node: '>=8'}
-
- ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
-
- ansi-styles@4.3.0:
- resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
- engines: {node: '>=8'}
-
- ansi-styles@5.2.0:
- resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
- engines: {node: '>=10'}
-
- anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
-
- arg@4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
-
- argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
-
- aws-cdk-lib@2.244.0:
- resolution: {integrity: sha512-j5FVeZv5W+v6j6OnW8RjoN04T+8pYvDJJV7yXhhj4IiGDKPgMH3fflQLQXJousd2QQk+nSAjghDVJcrZ4GFyGA==}
- engines: {node: '>= 20.0.0'}
- peerDependencies:
- constructs: ^10.5.0
- bundledDependencies:
- - '@balena/dockerignore'
- - '@aws-cdk/cloud-assembly-api'
- - case
- - fs-extra
- - ignore
- - jsonschema
- - minimatch
- - punycode
- - semver
- - table
- - yaml
- - mime-types
-
- aws-cdk@2.1114.1:
- resolution: {integrity: sha512-jMaKPWQQs1G6AbhfCQG2zGrgAhTxzP0jn4T2CuwONuvcV374dMPhfC/LBAv48ruSOgpCK9x6V1xeO/aH3EchAA==}
- engines: {node: '>= 18.0.0'}
- hasBin: true
-
- babel-jest@29.7.0:
- resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.8.0
-
- babel-plugin-istanbul@6.1.1:
- resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
- engines: {node: '>=8'}
-
- babel-plugin-jest-hoist@29.6.3:
- resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- babel-preset-current-node-syntax@1.2.0:
- resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==}
- peerDependencies:
- '@babel/core': ^7.0.0 || ^8.0.0-0
-
- babel-preset-jest@29.6.3:
- resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-
- baseline-browser-mapping@2.10.11:
- resolution: {integrity: sha512-DAKrHphkJyiGuau/cFieRYhcTFeK/lBuD++C7cZ6KZHbMhBrisoi+EvhQ5RZrIfV5qwsW8kgQ07JIC+MDJRAhg==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- brace-expansion@1.1.13:
- resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==}
-
- braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
-
- browserslist@4.28.1:
- resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
- bs-logger@0.2.6:
- resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
- engines: {node: '>= 6'}
-
- bser@2.1.1:
- resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
-
- buffer-from@1.1.2:
- resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
-
- callsites@3.1.0:
- resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
- engines: {node: '>=6'}
-
- camelcase@5.3.1:
- resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
- engines: {node: '>=6'}
-
- camelcase@6.3.0:
- resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
- engines: {node: '>=10'}
-
- caniuse-lite@1.0.30001781:
- resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==}
-
- chalk@4.1.2:
- resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
- engines: {node: '>=10'}
-
- char-regex@1.0.2:
- resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
- engines: {node: '>=10'}
-
- ci-info@3.9.0:
- resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
- engines: {node: '>=8'}
-
- cjs-module-lexer@1.4.3:
- resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
-
- cliui@8.0.1:
- resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
- engines: {node: '>=12'}
-
- co@4.6.0:
- resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
- engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
-
- collect-v8-coverage@1.0.3:
- resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==}
-
- color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
-
- color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
-
- concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
- constructs@10.6.0:
- resolution: {integrity: sha512-TxHOnBO5zMo/G76ykzGF/wMpEHu257TbWiIxP9K0Yv/+t70UzgBQiTqjkAsWOPC6jW91DzJI0+ehQV6xDRNBuQ==}
-
- convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
-
- create-jest@29.7.0:
- resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
-
- create-require@1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
-
- cross-spawn@7.0.6:
- resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
- engines: {node: '>= 8'}
-
- debug@4.4.3:
- resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
-
- dedent@1.7.2:
- resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==}
- peerDependencies:
- babel-plugin-macros: ^3.1.0
- peerDependenciesMeta:
- babel-plugin-macros:
- optional: true
-
- deepmerge@4.3.1:
- resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
- engines: {node: '>=0.10.0'}
-
- detect-newline@3.1.0:
- resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
- engines: {node: '>=8'}
-
- diff-sequences@29.6.3:
- resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- diff@4.0.4:
- resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
- engines: {node: '>=0.3.1'}
-
- electron-to-chromium@1.5.328:
- resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==}
-
- emittery@0.13.1:
- resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
- engines: {node: '>=12'}
-
- emoji-regex@8.0.0:
- resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
-
- error-ex@1.3.4:
- resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
-
- escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
- engines: {node: '>=6'}
-
- escape-string-regexp@2.0.0:
- resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
- engines: {node: '>=8'}
-
- esprima@4.0.1:
- resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
- engines: {node: '>=4'}
- hasBin: true
-
- execa@5.1.1:
- resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
- engines: {node: '>=10'}
-
- exit@0.1.2:
- resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
- engines: {node: '>= 0.8.0'}
-
- expect@29.7.0:
- resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- fast-json-stable-stringify@2.1.0:
- resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
-
- fb-watchman@2.0.2:
- resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
-
- fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
-
- find-up@4.1.0:
- resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
- engines: {node: '>=8'}
-
- fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
-
- fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
-
- function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
-
- gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
-
- get-caller-file@2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
-
- get-package-type@0.1.0:
- resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
- engines: {node: '>=8.0.0'}
-
- get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
-
- glob@7.2.3:
- resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
- deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
-
- graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
- handlebars@4.7.9:
- resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==}
- engines: {node: '>=0.4.7'}
- hasBin: true
-
- has-flag@4.0.0:
- resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
- engines: {node: '>=8'}
-
- hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
-
- html-escaper@2.0.2:
- resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
-
- human-signals@2.1.0:
- resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
- engines: {node: '>=10.17.0'}
-
- import-local@3.2.0:
- resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
- engines: {node: '>=8'}
- hasBin: true
-
- imurmurhash@0.1.4:
- resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
- engines: {node: '>=0.8.19'}
-
- inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
-
- inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
-
- is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
-
- is-core-module@2.16.1:
- resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
- engines: {node: '>= 0.4'}
-
- is-fullwidth-code-point@3.0.0:
- resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
- engines: {node: '>=8'}
-
- is-generator-fn@2.1.0:
- resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
- engines: {node: '>=6'}
-
- is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
-
- is-stream@2.0.1:
- resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
- engines: {node: '>=8'}
-
- isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
-
- istanbul-lib-coverage@3.2.2:
- resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@5.2.1:
- resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@6.0.3:
- resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
- engines: {node: '>=10'}
-
- istanbul-lib-report@3.0.1:
- resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
- engines: {node: '>=10'}
-
- istanbul-lib-source-maps@4.0.1:
- resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
- engines: {node: '>=10'}
-
- istanbul-reports@3.2.0:
- resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
- engines: {node: '>=8'}
-
- jest-changed-files@29.7.0:
- resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-circus@29.7.0:
- resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-cli@29.7.0:
- resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- jest-config@29.7.0:
- resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@types/node': '*'
- ts-node: '>=9.0.0'
- peerDependenciesMeta:
- '@types/node':
- optional: true
- ts-node:
- optional: true
-
- jest-diff@29.7.0:
- resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-docblock@29.7.0:
- resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-each@29.7.0:
- resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-environment-node@29.7.0:
- resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-get-type@29.6.3:
- resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-haste-map@29.7.0:
- resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-leak-detector@29.7.0:
- resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-matcher-utils@29.7.0:
- resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-message-util@29.7.0:
- resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-mock@29.7.0:
- resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-pnp-resolver@1.2.3:
- resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
- engines: {node: '>=6'}
- peerDependencies:
- jest-resolve: '*'
- peerDependenciesMeta:
- jest-resolve:
- optional: true
-
- jest-regex-util@29.6.3:
- resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve-dependencies@29.7.0:
- resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve@29.7.0:
- resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runner@29.7.0:
- resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runtime@29.7.0:
- resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-snapshot@29.7.0:
- resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-util@29.7.0:
- resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-validate@29.7.0:
- resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-watcher@29.7.0:
- resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-worker@29.7.0:
- resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest@29.7.0:
- resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-
- js-yaml@3.14.2:
- resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
- hasBin: true
-
- jsesc@3.1.0:
- resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
- engines: {node: '>=6'}
- hasBin: true
-
- json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
-
- json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
-
- kleur@3.0.3:
- resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
- engines: {node: '>=6'}
-
- leven@3.1.0:
- resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
- engines: {node: '>=6'}
-
- lines-and-columns@1.2.4:
- resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
-
- locate-path@5.0.0:
- resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
- engines: {node: '>=8'}
-
- lodash.memoize@4.1.2:
- resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
-
- lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
-
- make-dir@4.0.0:
- resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
- engines: {node: '>=10'}
-
- make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
-
- makeerror@1.0.12:
- resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
-
- merge-stream@2.0.0:
- resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
-
- micromatch@4.0.8:
- resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
- engines: {node: '>=8.6'}
-
- mimic-fn@2.1.0:
- resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
- engines: {node: '>=6'}
-
- minimatch@3.1.5:
- resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
-
- minimist@1.2.8:
- resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
-
- ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-
- natural-compare@1.4.0:
- resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
-
- neo-async@2.6.2:
- resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
-
- node-int64@0.4.0:
- resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
-
- node-releases@2.0.36:
- resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==}
-
- normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
-
- npm-run-path@4.0.1:
- resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
- engines: {node: '>=8'}
-
- once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
-
- onetime@5.1.2:
- resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
- engines: {node: '>=6'}
-
- p-limit@2.3.0:
- resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
- engines: {node: '>=6'}
-
- p-limit@3.1.0:
- resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
- engines: {node: '>=10'}
-
- p-locate@4.1.0:
- resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
- engines: {node: '>=8'}
-
- p-try@2.2.0:
- resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
- engines: {node: '>=6'}
-
- parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
- engines: {node: '>=8'}
-
- path-exists@4.0.0:
- resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
- engines: {node: '>=8'}
-
- path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
-
- path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
-
- path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
-
- picocolors@1.1.1:
- resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
-
- picomatch@2.3.2:
- resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
- engines: {node: '>=8.6'}
-
- pirates@4.0.7:
- resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
- engines: {node: '>= 6'}
-
- pkg-dir@4.2.0:
- resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
- engines: {node: '>=8'}
-
- pretty-format@29.7.0:
- resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- prompts@2.4.2:
- resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
- engines: {node: '>= 6'}
-
- pure-rand@6.1.0:
- resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
-
- react-is@18.3.1:
- resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
-
- require-directory@2.1.1:
- resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
- engines: {node: '>=0.10.0'}
-
- resolve-cwd@3.0.0:
- resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
- engines: {node: '>=8'}
-
- resolve-from@5.0.0:
- resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
- engines: {node: '>=8'}
-
- resolve.exports@2.0.3:
- resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
- engines: {node: '>=10'}
-
- resolve@1.22.11:
- resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
- engines: {node: '>= 0.4'}
- hasBin: true
-
- semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
- semver@7.7.4:
- resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
- engines: {node: '>=10'}
- hasBin: true
-
- shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
-
- shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
-
- signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
-
- sisteransi@1.0.5:
- resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
-
- slash@3.0.0:
- resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
- engines: {node: '>=8'}
-
- source-map-support@0.5.13:
- resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
-
- source-map@0.6.1:
- resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
- engines: {node: '>=0.10.0'}
-
- sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
-
- stack-utils@2.0.6:
- resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
- engines: {node: '>=10'}
-
- string-length@4.0.2:
- resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
- engines: {node: '>=10'}
-
- string-width@4.2.3:
- resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
- engines: {node: '>=8'}
-
- strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
-
- strip-bom@4.0.0:
- resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
- engines: {node: '>=8'}
-
- strip-final-newline@2.0.0:
- resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
- engines: {node: '>=6'}
-
- strip-json-comments@3.1.1:
- resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
- engines: {node: '>=8'}
-
- supports-color@7.2.0:
- resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
- engines: {node: '>=8'}
-
- supports-color@8.1.1:
- resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
- engines: {node: '>=10'}
-
- supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
-
- test-exclude@6.0.0:
- resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
- engines: {node: '>=8'}
-
- tmpl@1.0.5:
- resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
-
- to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
-
- ts-jest@29.4.6:
- resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==}
- engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- '@babel/core': '>=7.0.0-beta.0 <8'
- '@jest/transform': ^29.0.0 || ^30.0.0
- '@jest/types': ^29.0.0 || ^30.0.0
- babel-jest: ^29.0.0 || ^30.0.0
- esbuild: '*'
- jest: ^29.0.0 || ^30.0.0
- jest-util: ^29.0.0 || ^30.0.0
- typescript: '>=4.3 <6'
- peerDependenciesMeta:
- '@babel/core':
- optional: true
- '@jest/transform':
- optional: true
- '@jest/types':
- optional: true
- babel-jest:
- optional: true
- esbuild:
- optional: true
- jest-util:
- optional: true
-
- ts-node@10.9.2:
- resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
- hasBin: true
- peerDependencies:
- '@swc/core': '>=1.2.50'
- '@swc/wasm': '>=1.2.50'
- '@types/node': '*'
- typescript: '>=2.7'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- '@swc/wasm':
- optional: true
-
- type-detect@4.0.8:
- resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
- engines: {node: '>=4'}
-
- type-fest@0.21.3:
- resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
- engines: {node: '>=10'}
-
- type-fest@4.41.0:
- resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
- engines: {node: '>=16'}
-
- typescript@5.9.3:
- resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
- engines: {node: '>=14.17'}
- hasBin: true
-
- uglify-js@3.19.3:
- resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
- engines: {node: '>=0.8.0'}
- hasBin: true
-
- undici-types@7.18.2:
- resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
-
- update-browserslist-db@1.2.3:
- resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
-
- v8-compile-cache-lib@3.0.1:
- resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
-
- v8-to-istanbul@9.3.0:
- resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
- engines: {node: '>=10.12.0'}
-
- walker@1.0.8:
- resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
-
- which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
-
- wordwrap@1.0.0:
- resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
-
- wrap-ansi@7.0.0:
- resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
- engines: {node: '>=10'}
-
- wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
-
- write-file-atomic@4.0.2:
- resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-
- y18n@5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
-
- yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
-
- yargs-parser@21.1.1:
- resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
- engines: {node: '>=12'}
-
- yargs@17.7.2:
- resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
- engines: {node: '>=12'}
-
- yn@3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
-
- yocto-queue@0.1.0:
- resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
- engines: {node: '>=10'}
-
-snapshots:
-
- '@aws-cdk/asset-awscli-v1@2.2.263': {}
-
- '@aws-cdk/asset-node-proxy-agent-v6@2.1.1': {}
-
- '@aws-cdk/cloud-assembly-schema@52.2.0': {}
-
- '@babel/code-frame@7.29.0':
- dependencies:
- '@babel/helper-validator-identifier': 7.28.5
- js-tokens: 4.0.0
- picocolors: 1.1.1
-
- '@babel/compat-data@7.29.0': {}
-
- '@babel/core@7.29.0':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-compilation-targets': 7.28.6
- '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
- '@babel/helpers': 7.29.2
- '@babel/parser': 7.29.2
- '@babel/template': 7.28.6
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- '@jridgewell/remapping': 2.3.5
- convert-source-map: 2.0.0
- debug: 4.4.3
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- '@babel/generator@7.29.1':
- dependencies:
- '@babel/parser': 7.29.2
- '@babel/types': 7.29.0
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
- jsesc: 3.1.0
-
- '@babel/helper-compilation-targets@7.28.6':
- dependencies:
- '@babel/compat-data': 7.29.0
- '@babel/helper-validator-option': 7.27.1
- browserslist: 4.28.1
- lru-cache: 5.1.1
- semver: 6.3.1
-
- '@babel/helper-globals@7.28.0': {}
-
- '@babel/helper-module-imports@7.28.6':
- dependencies:
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-module-imports': 7.28.6
- '@babel/helper-validator-identifier': 7.28.5
- '@babel/traverse': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-plugin-utils@7.28.6': {}
-
- '@babel/helper-string-parser@7.27.1': {}
-
- '@babel/helper-validator-identifier@7.28.5': {}
-
- '@babel/helper-validator-option@7.27.1': {}
-
- '@babel/helpers@7.29.2':
- dependencies:
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
-
- '@babel/parser@7.29.2':
- dependencies:
- '@babel/types': 7.29.0
-
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-plugin-utils': 7.28.6
-
- '@babel/template@7.28.6':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/parser': 7.29.2
- '@babel/types': 7.29.0
-
- '@babel/traverse@7.29.0':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-globals': 7.28.0
- '@babel/parser': 7.29.2
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
- debug: 4.4.3
- transitivePeerDependencies:
- - supports-color
-
- '@babel/types@7.29.0':
- dependencies:
- '@babel/helper-string-parser': 7.27.1
- '@babel/helper-validator-identifier': 7.28.5
-
- '@bcoe/v8-coverage@0.2.3': {}
-
- '@cspotcode/source-map-support@0.8.1':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.9
-
- '@istanbuljs/load-nyc-config@1.1.0':
- dependencies:
- camelcase: 5.3.1
- find-up: 4.1.0
- get-package-type: 0.1.0
- js-yaml: 3.14.2
- resolve-from: 5.0.0
-
- '@istanbuljs/schema@0.1.3': {}
-
- '@jest/console@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- chalk: 4.1.2
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
-
- '@jest/core@29.7.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/reporters': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- ci-info: 3.9.0
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-resolve-dependencies: 29.7.0
- jest-runner: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- jest-watcher: 29.7.0
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-ansi: 6.0.1
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- '@jest/environment@29.7.0':
- dependencies:
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- jest-mock: 29.7.0
-
- '@jest/expect-utils@29.7.0':
- dependencies:
- jest-get-type: 29.6.3
-
- '@jest/expect@29.7.0':
- dependencies:
- expect: 29.7.0
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/fake-timers@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@sinonjs/fake-timers': 10.3.0
- '@types/node': 25.5.0
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-util: 29.7.0
-
- '@jest/globals@29.7.0':
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/types': 29.6.3
- jest-mock: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/reporters@29.7.0':
- dependencies:
- '@bcoe/v8-coverage': 0.2.3
- '@jest/console': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.31
- '@types/node': 25.5.0
- chalk: 4.1.2
- collect-v8-coverage: 1.0.3
- exit: 0.1.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-instrument: 6.0.3
- istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 4.0.1
- istanbul-reports: 3.2.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- jest-worker: 29.7.0
- slash: 3.0.0
- string-length: 4.0.2
- strip-ansi: 6.0.1
- v8-to-istanbul: 9.3.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/schemas@29.6.3':
- dependencies:
- '@sinclair/typebox': 0.27.10
-
- '@jest/source-map@29.6.3':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.31
- callsites: 3.1.0
- graceful-fs: 4.2.11
-
- '@jest/test-result@29.7.0':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/types': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- collect-v8-coverage: 1.0.3
-
- '@jest/test-sequencer@29.7.0':
- dependencies:
- '@jest/test-result': 29.7.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- slash: 3.0.0
-
- '@jest/transform@29.7.0':
- dependencies:
- '@babel/core': 7.29.0
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.31
- babel-plugin-istanbul: 6.1.1
- chalk: 4.1.2
- convert-source-map: 2.0.0
- fast-json-stable-stringify: 2.1.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- micromatch: 4.0.8
- pirates: 4.0.7
- slash: 3.0.0
- write-file-atomic: 4.0.2
- transitivePeerDependencies:
- - supports-color
-
- '@jest/types@29.6.3':
- dependencies:
- '@jest/schemas': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- '@types/istanbul-reports': 3.0.4
- '@types/node': 25.5.0
- '@types/yargs': 17.0.35
- chalk: 4.1.2
-
- '@jridgewell/gen-mapping@0.3.13':
- dependencies:
- '@jridgewell/sourcemap-codec': 1.5.5
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/remapping@2.3.5':
- dependencies:
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/resolve-uri@3.1.2': {}
-
- '@jridgewell/sourcemap-codec@1.5.5': {}
-
- '@jridgewell/trace-mapping@0.3.31':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.5
-
- '@jridgewell/trace-mapping@0.3.9':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.5
-
- '@sinclair/typebox@0.27.10': {}
-
- '@sinonjs/commons@3.0.1':
- dependencies:
- type-detect: 4.0.8
-
- '@sinonjs/fake-timers@10.3.0':
- dependencies:
- '@sinonjs/commons': 3.0.1
-
- '@tsconfig/node10@1.0.12': {}
-
- '@tsconfig/node12@1.0.11': {}
-
- '@tsconfig/node14@1.0.3': {}
-
- '@tsconfig/node16@1.0.4': {}
-
- '@types/babel__core@7.20.5':
- dependencies:
- '@babel/parser': 7.29.2
- '@babel/types': 7.29.0
- '@types/babel__generator': 7.27.0
- '@types/babel__template': 7.4.4
- '@types/babel__traverse': 7.28.0
-
- '@types/babel__generator@7.27.0':
- dependencies:
- '@babel/types': 7.29.0
-
- '@types/babel__template@7.4.4':
- dependencies:
- '@babel/parser': 7.29.2
- '@babel/types': 7.29.0
-
- '@types/babel__traverse@7.28.0':
- dependencies:
- '@babel/types': 7.29.0
-
- '@types/graceful-fs@4.1.9':
- dependencies:
- '@types/node': 25.5.0
-
- '@types/istanbul-lib-coverage@2.0.6': {}
-
- '@types/istanbul-lib-report@3.0.3':
- dependencies:
- '@types/istanbul-lib-coverage': 2.0.6
-
- '@types/istanbul-reports@3.0.4':
- dependencies:
- '@types/istanbul-lib-report': 3.0.3
-
- '@types/jest@29.5.14':
- dependencies:
- expect: 29.7.0
- pretty-format: 29.7.0
-
- '@types/node@25.5.0':
- dependencies:
- undici-types: 7.18.2
-
- '@types/stack-utils@2.0.3': {}
-
- '@types/yargs-parser@21.0.3': {}
-
- '@types/yargs@17.0.35':
- dependencies:
- '@types/yargs-parser': 21.0.3
-
- acorn-walk@8.3.5:
- dependencies:
- acorn: 8.16.0
-
- acorn@8.16.0: {}
-
- ansi-escapes@4.3.2:
- dependencies:
- type-fest: 0.21.3
-
- ansi-regex@5.0.1: {}
-
- ansi-styles@4.3.0:
- dependencies:
- color-convert: 2.0.1
-
- ansi-styles@5.2.0: {}
-
- anymatch@3.1.3:
- dependencies:
- normalize-path: 3.0.0
- picomatch: 2.3.2
-
- arg@4.1.3: {}
-
- argparse@1.0.10:
- dependencies:
- sprintf-js: 1.0.3
-
- aws-cdk-lib@2.244.0(constructs@10.6.0):
- dependencies:
- '@aws-cdk/asset-awscli-v1': 2.2.263
- '@aws-cdk/asset-node-proxy-agent-v6': 2.1.1
- '@aws-cdk/cloud-assembly-schema': 52.2.0
- constructs: 10.6.0
-
- aws-cdk@2.1114.1: {}
-
- babel-jest@29.7.0(@babel/core@7.29.0):
- dependencies:
- '@babel/core': 7.29.0
- '@jest/transform': 29.7.0
- '@types/babel__core': 7.20.5
- babel-plugin-istanbul: 6.1.1
- babel-preset-jest: 29.6.3(@babel/core@7.29.0)
- chalk: 4.1.2
- graceful-fs: 4.2.11
- slash: 3.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-istanbul@6.1.1:
- dependencies:
- '@babel/helper-plugin-utils': 7.28.6
- '@istanbuljs/load-nyc-config': 1.1.0
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-instrument: 5.2.1
- test-exclude: 6.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-jest-hoist@29.6.3:
- dependencies:
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
- '@types/babel__core': 7.20.5
- '@types/babel__traverse': 7.28.0
-
- babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0):
- dependencies:
- '@babel/core': 7.29.0
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0)
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0)
- '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0)
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0)
-
- babel-preset-jest@29.6.3(@babel/core@7.29.0):
- dependencies:
- '@babel/core': 7.29.0
- babel-plugin-jest-hoist: 29.6.3
- babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
-
- balanced-match@1.0.2: {}
-
- baseline-browser-mapping@2.10.11: {}
-
- brace-expansion@1.1.13:
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
-
- braces@3.0.3:
- dependencies:
- fill-range: 7.1.1
-
- browserslist@4.28.1:
- dependencies:
- baseline-browser-mapping: 2.10.11
- caniuse-lite: 1.0.30001781
- electron-to-chromium: 1.5.328
- node-releases: 2.0.36
- update-browserslist-db: 1.2.3(browserslist@4.28.1)
-
- bs-logger@0.2.6:
- dependencies:
- fast-json-stable-stringify: 2.1.0
-
- bser@2.1.1:
- dependencies:
- node-int64: 0.4.0
-
- buffer-from@1.1.2: {}
-
- callsites@3.1.0: {}
-
- camelcase@5.3.1: {}
-
- camelcase@6.3.0: {}
-
- caniuse-lite@1.0.30001781: {}
-
- chalk@4.1.2:
- dependencies:
- ansi-styles: 4.3.0
- supports-color: 7.2.0
-
- char-regex@1.0.2: {}
-
- ci-info@3.9.0: {}
-
- cjs-module-lexer@1.4.3: {}
-
- cliui@8.0.1:
- dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 7.0.0
-
- co@4.6.0: {}
-
- collect-v8-coverage@1.0.3: {}
-
- color-convert@2.0.1:
- dependencies:
- color-name: 1.1.4
-
- color-name@1.1.4: {}
-
- concat-map@0.0.1: {}
-
- constructs@10.6.0: {}
-
- convert-source-map@2.0.0: {}
-
- create-jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- jest-util: 29.7.0
- prompts: 2.4.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- create-require@1.1.1: {}
-
- cross-spawn@7.0.6:
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
-
- debug@4.4.3:
- dependencies:
- ms: 2.1.3
-
- dedent@1.7.2: {}
-
- deepmerge@4.3.1: {}
-
- detect-newline@3.1.0: {}
-
- diff-sequences@29.6.3: {}
-
- diff@4.0.4: {}
-
- electron-to-chromium@1.5.328: {}
-
- emittery@0.13.1: {}
-
- emoji-regex@8.0.0: {}
-
- error-ex@1.3.4:
- dependencies:
- is-arrayish: 0.2.1
-
- escalade@3.2.0: {}
-
- escape-string-regexp@2.0.0: {}
-
- esprima@4.0.1: {}
-
- execa@5.1.1:
- dependencies:
- cross-spawn: 7.0.6
- get-stream: 6.0.1
- human-signals: 2.1.0
- is-stream: 2.0.1
- merge-stream: 2.0.0
- npm-run-path: 4.0.1
- onetime: 5.1.2
- signal-exit: 3.0.7
- strip-final-newline: 2.0.0
-
- exit@0.1.2: {}
-
- expect@29.7.0:
- dependencies:
- '@jest/expect-utils': 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
-
- fast-json-stable-stringify@2.1.0: {}
-
- fb-watchman@2.0.2:
- dependencies:
- bser: 2.1.1
-
- fill-range@7.1.1:
- dependencies:
- to-regex-range: 5.0.1
-
- find-up@4.1.0:
- dependencies:
- locate-path: 5.0.0
- path-exists: 4.0.0
-
- fs.realpath@1.0.0: {}
-
- fsevents@2.3.3:
- optional: true
-
- function-bind@1.1.2: {}
-
- gensync@1.0.0-beta.2: {}
-
- get-caller-file@2.0.5: {}
-
- get-package-type@0.1.0: {}
-
- get-stream@6.0.1: {}
-
- glob@7.2.3:
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.5
- once: 1.4.0
- path-is-absolute: 1.0.1
-
- graceful-fs@4.2.11: {}
-
- handlebars@4.7.9:
- dependencies:
- minimist: 1.2.8
- neo-async: 2.6.2
- source-map: 0.6.1
- wordwrap: 1.0.0
- optionalDependencies:
- uglify-js: 3.19.3
-
- has-flag@4.0.0: {}
-
- hasown@2.0.2:
- dependencies:
- function-bind: 1.1.2
-
- html-escaper@2.0.2: {}
-
- human-signals@2.1.0: {}
-
- import-local@3.2.0:
- dependencies:
- pkg-dir: 4.2.0
- resolve-cwd: 3.0.0
-
- imurmurhash@0.1.4: {}
-
- inflight@1.0.6:
- dependencies:
- once: 1.4.0
- wrappy: 1.0.2
-
- inherits@2.0.4: {}
-
- is-arrayish@0.2.1: {}
-
- is-core-module@2.16.1:
- dependencies:
- hasown: 2.0.2
-
- is-fullwidth-code-point@3.0.0: {}
-
- is-generator-fn@2.1.0: {}
-
- is-number@7.0.0: {}
-
- is-stream@2.0.1: {}
-
- isexe@2.0.0: {}
-
- istanbul-lib-coverage@3.2.2: {}
-
- istanbul-lib-instrument@5.2.1:
- dependencies:
- '@babel/core': 7.29.0
- '@babel/parser': 7.29.2
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-instrument@6.0.3:
- dependencies:
- '@babel/core': 7.29.0
- '@babel/parser': 7.29.2
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 7.7.4
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-report@3.0.1:
- dependencies:
- istanbul-lib-coverage: 3.2.2
- make-dir: 4.0.0
- supports-color: 7.2.0
-
- istanbul-lib-source-maps@4.0.1:
- dependencies:
- debug: 4.4.3
- istanbul-lib-coverage: 3.2.2
- source-map: 0.6.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-reports@3.2.0:
- dependencies:
- html-escaper: 2.0.2
- istanbul-lib-report: 3.0.1
-
- jest-changed-files@29.7.0:
- dependencies:
- execa: 5.1.1
- jest-util: 29.7.0
- p-limit: 3.1.0
-
- jest-circus@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- chalk: 4.1.2
- co: 4.6.0
- dedent: 1.7.2
- is-generator-fn: 2.1.0
- jest-each: 29.7.0
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- p-limit: 3.1.0
- pretty-format: 29.7.0
- pure-rand: 6.1.0
- slash: 3.0.0
- stack-utils: 2.0.6
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-cli@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
- dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- chalk: 4.1.2
- create-jest: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- exit: 0.1.2
- import-local: 3.2.0
- jest-config: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- jest-util: 29.7.0
- jest-validate: 29.7.0
- yargs: 17.7.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- jest-config@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
- dependencies:
- '@babel/core': 7.29.0
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.29.0)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 25.5.0
- ts-node: 10.9.2(@types/node@25.5.0)(typescript@5.9.3)
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-diff@29.7.0:
- dependencies:
- chalk: 4.1.2
- diff-sequences: 29.6.3
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
-
- jest-docblock@29.7.0:
- dependencies:
- detect-newline: 3.1.0
-
- jest-each@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- jest-get-type: 29.6.3
- jest-util: 29.7.0
- pretty-format: 29.7.0
-
- jest-environment-node@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- jest-mock: 29.7.0
- jest-util: 29.7.0
-
- jest-get-type@29.6.3: {}
-
- jest-haste-map@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/graceful-fs': 4.1.9
- '@types/node': 25.5.0
- anymatch: 3.1.3
- fb-watchman: 2.0.2
- graceful-fs: 4.2.11
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- jest-worker: 29.7.0
- micromatch: 4.0.8
- walker: 1.0.8
- optionalDependencies:
- fsevents: 2.3.3
-
- jest-leak-detector@29.7.0:
- dependencies:
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
-
- jest-matcher-utils@29.7.0:
- dependencies:
- chalk: 4.1.2
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
-
- jest-message-util@29.7.0:
- dependencies:
- '@babel/code-frame': 7.29.0
- '@jest/types': 29.6.3
- '@types/stack-utils': 2.0.3
- chalk: 4.1.2
- graceful-fs: 4.2.11
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- stack-utils: 2.0.6
-
- jest-mock@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- jest-util: 29.7.0
-
- jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
- optionalDependencies:
- jest-resolve: 29.7.0
-
- jest-regex-util@29.6.3: {}
-
- jest-resolve-dependencies@29.7.0:
- dependencies:
- jest-regex-util: 29.6.3
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- jest-resolve@29.7.0:
- dependencies:
- chalk: 4.1.2
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- resolve: 1.22.11
- resolve.exports: 2.0.3
- slash: 3.0.0
-
- jest-runner@29.7.0:
- dependencies:
- '@jest/console': 29.7.0
- '@jest/environment': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- chalk: 4.1.2
- emittery: 0.13.1
- graceful-fs: 4.2.11
- jest-docblock: 29.7.0
- jest-environment-node: 29.7.0
- jest-haste-map: 29.7.0
- jest-leak-detector: 29.7.0
- jest-message-util: 29.7.0
- jest-resolve: 29.7.0
- jest-runtime: 29.7.0
- jest-util: 29.7.0
- jest-watcher: 29.7.0
- jest-worker: 29.7.0
- p-limit: 3.1.0
- source-map-support: 0.5.13
- transitivePeerDependencies:
- - supports-color
-
- jest-runtime@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/globals': 29.7.0
- '@jest/source-map': 29.6.3
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- chalk: 4.1.2
- cjs-module-lexer: 1.4.3
- collect-v8-coverage: 1.0.3
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
- strip-bom: 4.0.0
- transitivePeerDependencies:
- - supports-color
-
- jest-snapshot@29.7.0:
- dependencies:
- '@babel/core': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
- '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0)
- '@babel/types': 7.29.0
- '@jest/expect-utils': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
- chalk: 4.1.2
- expect: 29.7.0
- graceful-fs: 4.2.11
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- natural-compare: 1.4.0
- pretty-format: 29.7.0
- semver: 7.7.4
- transitivePeerDependencies:
- - supports-color
-
- jest-util@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- chalk: 4.1.2
- ci-info: 3.9.0
- graceful-fs: 4.2.11
- picomatch: 2.3.2
-
- jest-validate@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- camelcase: 6.3.0
- chalk: 4.1.2
- jest-get-type: 29.6.3
- leven: 3.1.0
- pretty-format: 29.7.0
-
- jest-watcher@29.7.0:
- dependencies:
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 25.5.0
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- emittery: 0.13.1
- jest-util: 29.7.0
- string-length: 4.0.2
-
- jest-worker@29.7.0:
- dependencies:
- '@types/node': 25.5.0
- jest-util: 29.7.0
- merge-stream: 2.0.0
- supports-color: 8.1.1
-
- jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)):
- dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- '@jest/types': 29.6.3
- import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- js-tokens@4.0.0: {}
-
- js-yaml@3.14.2:
- dependencies:
- argparse: 1.0.10
- esprima: 4.0.1
-
- jsesc@3.1.0: {}
-
- json-parse-even-better-errors@2.3.1: {}
-
- json5@2.2.3: {}
-
- kleur@3.0.3: {}
-
- leven@3.1.0: {}
-
- lines-and-columns@1.2.4: {}
-
- locate-path@5.0.0:
- dependencies:
- p-locate: 4.1.0
-
- lodash.memoize@4.1.2: {}
-
- lru-cache@5.1.1:
- dependencies:
- yallist: 3.1.1
-
- make-dir@4.0.0:
- dependencies:
- semver: 7.7.4
-
- make-error@1.3.6: {}
-
- makeerror@1.0.12:
- dependencies:
- tmpl: 1.0.5
-
- merge-stream@2.0.0: {}
-
- micromatch@4.0.8:
- dependencies:
- braces: 3.0.3
- picomatch: 2.3.2
-
- mimic-fn@2.1.0: {}
-
- minimatch@3.1.5:
- dependencies:
- brace-expansion: 1.1.13
-
- minimist@1.2.8: {}
-
- ms@2.1.3: {}
-
- natural-compare@1.4.0: {}
-
- neo-async@2.6.2: {}
-
- node-int64@0.4.0: {}
-
- node-releases@2.0.36: {}
-
- normalize-path@3.0.0: {}
-
- npm-run-path@4.0.1:
- dependencies:
- path-key: 3.1.1
-
- once@1.4.0:
- dependencies:
- wrappy: 1.0.2
-
- onetime@5.1.2:
- dependencies:
- mimic-fn: 2.1.0
-
- p-limit@2.3.0:
- dependencies:
- p-try: 2.2.0
-
- p-limit@3.1.0:
- dependencies:
- yocto-queue: 0.1.0
-
- p-locate@4.1.0:
- dependencies:
- p-limit: 2.3.0
-
- p-try@2.2.0: {}
-
- parse-json@5.2.0:
- dependencies:
- '@babel/code-frame': 7.29.0
- error-ex: 1.3.4
- json-parse-even-better-errors: 2.3.1
- lines-and-columns: 1.2.4
-
- path-exists@4.0.0: {}
-
- path-is-absolute@1.0.1: {}
-
- path-key@3.1.1: {}
-
- path-parse@1.0.7: {}
-
- picocolors@1.1.1: {}
-
- picomatch@2.3.2: {}
-
- pirates@4.0.7: {}
-
- pkg-dir@4.2.0:
- dependencies:
- find-up: 4.1.0
-
- pretty-format@29.7.0:
- dependencies:
- '@jest/schemas': 29.6.3
- ansi-styles: 5.2.0
- react-is: 18.3.1
-
- prompts@2.4.2:
- dependencies:
- kleur: 3.0.3
- sisteransi: 1.0.5
-
- pure-rand@6.1.0: {}
-
- react-is@18.3.1: {}
-
- require-directory@2.1.1: {}
-
- resolve-cwd@3.0.0:
- dependencies:
- resolve-from: 5.0.0
-
- resolve-from@5.0.0: {}
-
- resolve.exports@2.0.3: {}
-
- resolve@1.22.11:
- dependencies:
- is-core-module: 2.16.1
- path-parse: 1.0.7
- supports-preserve-symlinks-flag: 1.0.0
-
- semver@6.3.1: {}
-
- semver@7.7.4: {}
-
- shebang-command@2.0.0:
- dependencies:
- shebang-regex: 3.0.0
-
- shebang-regex@3.0.0: {}
-
- signal-exit@3.0.7: {}
-
- sisteransi@1.0.5: {}
-
- slash@3.0.0: {}
-
- source-map-support@0.5.13:
- dependencies:
- buffer-from: 1.1.2
- source-map: 0.6.1
-
- source-map@0.6.1: {}
-
- sprintf-js@1.0.3: {}
-
- stack-utils@2.0.6:
- dependencies:
- escape-string-regexp: 2.0.0
-
- string-length@4.0.2:
- dependencies:
- char-regex: 1.0.2
- strip-ansi: 6.0.1
-
- string-width@4.2.3:
- dependencies:
- emoji-regex: 8.0.0
- is-fullwidth-code-point: 3.0.0
- strip-ansi: 6.0.1
-
- strip-ansi@6.0.1:
- dependencies:
- ansi-regex: 5.0.1
-
- strip-bom@4.0.0: {}
-
- strip-final-newline@2.0.0: {}
-
- strip-json-comments@3.1.1: {}
-
- supports-color@7.2.0:
- dependencies:
- has-flag: 4.0.0
-
- supports-color@8.1.1:
- dependencies:
- has-flag: 4.0.0
-
- supports-preserve-symlinks-flag@1.0.0: {}
-
- test-exclude@6.0.0:
- dependencies:
- '@istanbuljs/schema': 0.1.3
- glob: 7.2.3
- minimatch: 3.1.5
-
- tmpl@1.0.5: {}
-
- to-regex-range@5.0.1:
- dependencies:
- is-number: 7.0.0
-
- ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3)))(typescript@5.9.3):
- dependencies:
- bs-logger: 0.2.6
- fast-json-stable-stringify: 2.1.0
- handlebars: 4.7.9
- jest: 29.7.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3))
- json5: 2.2.3
- lodash.memoize: 4.1.2
- make-error: 1.3.6
- semver: 7.7.4
- type-fest: 4.41.0
- typescript: 5.9.3
- yargs-parser: 21.1.1
- optionalDependencies:
- '@babel/core': 7.29.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.29.0)
- jest-util: 29.7.0
-
- ts-node@10.9.2(@types/node@25.5.0)(typescript@5.9.3):
- dependencies:
- '@cspotcode/source-map-support': 0.8.1
- '@tsconfig/node10': 1.0.12
- '@tsconfig/node12': 1.0.11
- '@tsconfig/node14': 1.0.3
- '@tsconfig/node16': 1.0.4
- '@types/node': 25.5.0
- acorn: 8.16.0
- acorn-walk: 8.3.5
- arg: 4.1.3
- create-require: 1.1.1
- diff: 4.0.4
- make-error: 1.3.6
- typescript: 5.9.3
- v8-compile-cache-lib: 3.0.1
- yn: 3.1.1
-
- type-detect@4.0.8: {}
-
- type-fest@0.21.3: {}
-
- type-fest@4.41.0: {}
-
- typescript@5.9.3: {}
-
- uglify-js@3.19.3:
- optional: true
-
- undici-types@7.18.2: {}
-
- update-browserslist-db@1.2.3(browserslist@4.28.1):
- dependencies:
- browserslist: 4.28.1
- escalade: 3.2.0
- picocolors: 1.1.1
-
- v8-compile-cache-lib@3.0.1: {}
-
- v8-to-istanbul@9.3.0:
- dependencies:
- '@jridgewell/trace-mapping': 0.3.31
- '@types/istanbul-lib-coverage': 2.0.6
- convert-source-map: 2.0.0
-
- walker@1.0.8:
- dependencies:
- makeerror: 1.0.12
-
- which@2.0.2:
- dependencies:
- isexe: 2.0.0
-
- wordwrap@1.0.0: {}
-
- wrap-ansi@7.0.0:
- dependencies:
- ansi-styles: 4.3.0
- string-width: 4.2.3
- strip-ansi: 6.0.1
-
- wrappy@1.0.2: {}
-
- write-file-atomic@4.0.2:
- dependencies:
- imurmurhash: 0.1.4
- signal-exit: 3.0.7
-
- y18n@5.0.8: {}
-
- yallist@3.1.1: {}
-
- yargs-parser@21.1.1: {}
-
- yargs@17.7.2:
- dependencies:
- cliui: 8.0.1
- escalade: 3.2.0
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- string-width: 4.2.3
- y18n: 5.0.8
- yargs-parser: 21.1.1
-
- yn@3.1.1: {}
-
- yocto-queue@0.1.0: {}
diff --git a/src/iac/src/aws/network/vpcLookupStack.ts b/src/iac/src/aws/network/vpcLookupStack.ts
deleted file mode 100644
index 4a2360c1..00000000
--- a/src/iac/src/aws/network/vpcLookupStack.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { type Environment, Stack, type StackProps } from 'aws-cdk-lib';
-import { type IVpc, Vpc } from 'aws-cdk-lib/aws-ec2';
-import type { Construct } from 'constructs';
-
-export interface VpcLookupStackProps extends StackProps {
- vpcId: string;
- env?: Environment;
-}
-
-/**
- * Stack for looking up an existing VPC by ID
- * This is used to retrieve VPC information for stack deployments
- */
-export class VpcLookupStack extends Stack {
- public readonly vpc: IVpc;
-
- constructor(scope: Construct, props: VpcLookupStackProps) {
- super(scope, props.vpcId, props);
-
- this.vpc = Vpc.fromLookup(this, 'VpcNetwork', {
- vpcId: props.vpcId,
- });
- }
-}
diff --git a/src/iac/src/aws/network/vpcStack.ts b/src/iac/src/aws/network/vpcStack.ts
deleted file mode 100644
index 26ad9fcb..00000000
--- a/src/iac/src/aws/network/vpcStack.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-import { CfnOutput } from 'aws-cdk-lib';
-import {
- type IVpc,
- IpAddresses,
- type SubnetConfiguration,
- Vpc,
-} from 'aws-cdk-lib/aws-ec2';
-import type { Construct } from 'constructs';
-import {
- CustomStack,
- type CustomStackProps,
-} from '../../config/domain/customStack';
-
-/**
- * Properties for configuring the VPC stack.
- *
- * This interface extends CustomStackProps with additional properties required to create a VPC.
- *
- * Properties include:
- * - vpcName: The base name for the VPC.
- * - vpcCdir: The CIDR block for the VPC.
- * - maxAzs: (Optional) The maximum number of availability zones to use.
- * - natGateways: (Optional) The number of NAT gateways to create.
- * - enableDnsHostnames: (Optional) Whether to enable DNS hostnames for instances.
- * - enableDnsSupport: (Optional) Whether to enable DNS support.
- * - subnetConfiguration: An array of subnet configurations for the VPC.
- *
- * @example
- * const vpcStackProps: VPCStackProps = {
- * vpcName: "my-vpc",
- * vpcCdir: "10.0.0.0/16",
- * maxAzs: 3,
- * natGateways: 1,
- * enableDnsHostnames: true,
- * enableDnsSupport: true,
- * subnetConfiguration: [
- * {
- * name: "Public",
- * subnetType: SubnetType.PUBLIC,
- * cidrMask: 24,
- * },
- * {
- * name: "Private",
- * subnetType: SubnetType.PRIVATE_WITH_NAT,
- * cidrMask: 24,
- * },
- * ],
- * // plus additional CustomStackProps properties...
- * };
- */
-export interface VPCStackProps extends CustomStackProps {
- vpcName: string;
- vpcCdir: string;
- maxAzs?: number;
- natGateways?: number;
- enableDnsHostnames?: boolean;
- enableDnsSupport?: boolean;
- subnetConfiguration: SubnetConfiguration[];
-}
-
-/**
- * VpcStack provisions an Amazon Virtual Private Cloud (VPC) with the specified configuration.
- *
- * This stack creates a VPC with the given name (appended with the environment name), CIDR block, and subnet
- * configurations. It supports optional settings such as maximum availability zones, NAT gateways, and DNS settings.
- * The VPC ID is output as a CloudFormation output for external reference.
- *
- * @example
- * new VpcStack(app, {
- * vpcName: "my-vpc",
- * vpcCdir: "10.0.0.0/16",
- * maxAzs: 3,
- * natGateways: 1,
- * enableDnsHostnames: true,
- * enableDnsSupport: true,
- * subnetConfiguration: [ ... ],
- * // plus additional CustomStackProps properties...
- * });
- */
-export class VpcStack extends CustomStack {
- public readonly vpc: IVpc;
-
- /**
- * Constructs a new instance of the VpcStack.
- *
- * This constructor creates a new VPC with the provided configuration. The VPC's name is built by appending the
- * environment name to the provided base vpcName. The CIDR block, availability zones, NAT gateways, and DNS settings
- * are configured based on the input properties. Finally, the VPC ID is output as a CloudFormation output.
- *
- * @param scope - The construct scope in which this stack is defined.
- * @param props - The properties for configuring the VPC.
- */
- constructor(scope: Construct, props: VPCStackProps) {
- super(scope, props);
-
- this.vpc = new Vpc(this, 'vpcId', {
- vpcName: `${props.vpcName}-${props.envName}`,
- ipAddresses: IpAddresses.cidr(props.vpcCdir),
- maxAzs: props.maxAzs,
- natGateways: props.natGateways,
- enableDnsHostnames: props.enableDnsHostnames,
- enableDnsSupport: props.enableDnsSupport,
- subnetConfiguration: props.subnetConfiguration,
- });
-
- new CfnOutput(this, 'cfnOutputVpcId', {
- value: this.vpc.vpcId,
- description: 'Created VPC ID',
- exportName: 'VpcStack:vpcId',
- });
- }
-}
diff --git a/src/iac/src/aws/website/cloudfront-url-rewrite.js b/src/iac/src/aws/website/cloudfront-url-rewrite.js
deleted file mode 100644
index bb600507..00000000
--- a/src/iac/src/aws/website/cloudfront-url-rewrite.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// CloudFront Function for URL rewriting
-// Compatible with CloudFront Functions runtime (ES5.1)
-// Query strings are automatically preserved by CloudFront
-
-function handler(event) {
- var req = event.request;
- var uri = req.uri;
-
- // ES5.1 Helpers (without startsWith/endsWith or arrow functions)
- function endsWith(str, suffix) {
- if (str == null || suffix == null) return false;
- var sl = str.length, su = suffix.length;
- return sl >= su && str.substring(sl - su) === suffix;
- }
- function hasPrefix(str, prefix) {
- if (str == null || prefix == null) return false;
- return str.indexOf(prefix) === 0;
- }
-
- var staticExt = [
- '.html', '.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg',
- '.ico', '.woff', '.woff2', '.ttf', '.otf', '.eot', '.json', '.xml',
- '.txt', '.map'
- ];
-
- function hasKnownExt(uLower) {
- for (var i = 0; i < staticExt.length; i++) {
- if (endsWith(uLower, staticExt[i])) return true;
- }
- return false;
- }
-
- // Exclude API routes
- var lower = uri.toLowerCase();
- if (hasPrefix(lower, '/api/')) {
- return req; // no changes
- }
-
- // Remove trailing slash (except homepage)
- if (uri !== '/' && endsWith(uri, '/')) {
- uri = uri.substring(0, uri.length - 1);
- lower = uri.toLowerCase(); // recompute after modifying uri
- }
-
- // Append .html if not homepage and no known extension
- if (uri !== '/' && !hasKnownExt(lower)) {
- // For /folder/index.html instead of /folder.html, use:
- // uri += '/index.html';
- uri += '.html';
- }
-
- req.uri = uri;
- return req;
-}
diff --git a/src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap b/src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap
deleted file mode 100644
index d46e0f67..00000000
--- a/src/iac/test/aws/network/__snapshots__/vpcStack.test.ts.snap
+++ /dev/null
@@ -1,612 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`VpcStackTest Should_MatchSnapshotAndResources_When_VpcStackIsCreated: VpcStackTest 1`] = `
-{
- "Outputs": {
- "cfnOutputVpcId": {
- "Description": "Created VPC ID",
- "Export": {
- "Name": "VpcStack:vpcId",
- },
- "Value": {
- "Ref": "vpcId937700B3",
- },
- },
- },
- "Parameters": {
- "BootstrapVersion": {
- "Default": "/cdk-bootstrap/hnb659fds/version",
- "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
- "Type": "AWS::SSM::Parameter::Value
",
- },
- },
- "Resources": {
- "vpcId937700B3": {
- "Properties": {
- "CidrBlock": "22.0.0.0/16",
- "EnableDnsHostnames": true,
- "EnableDnsSupport": true,
- "InstanceTenancy": "default",
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "private-CustomVpc-Test",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- },
- "Type": "AWS::EC2::VPC",
- },
- "vpcIdIGW108455B5": {
- "Properties": {
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "private-CustomVpc-Test",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- },
- "Type": "AWS::EC2::InternetGateway",
- },
- "vpcIdPrivate1Subnet1DefaultRoute9D408128": {
- "Properties": {
- "DestinationCidrBlock": "0.0.0.0/0",
- "NatGatewayId": {
- "Ref": "vpcIdPublic1Subnet1NATGateway5EB16AC0",
- },
- "RouteTableId": {
- "Ref": "vpcIdPrivate1Subnet1RouteTable42D8C801",
- },
- },
- "Type": "AWS::EC2::Route",
- },
- "vpcIdPrivate1Subnet1RouteTable42D8C801": {
- "Properties": {
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet1",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::RouteTable",
- },
- "vpcIdPrivate1Subnet1RouteTableAssociation675EA1FB": {
- "Properties": {
- "RouteTableId": {
- "Ref": "vpcIdPrivate1Subnet1RouteTable42D8C801",
- },
- "SubnetId": {
- "Ref": "vpcIdPrivate1Subnet1SubnetACE5346C",
- },
- },
- "Type": "AWS::EC2::SubnetRouteTableAssociation",
- },
- "vpcIdPrivate1Subnet1SubnetACE5346C": {
- "Properties": {
- "AvailabilityZone": {
- "Fn::Select": [
- 0,
- {
- "Fn::GetAZs": "",
- },
- ],
- },
- "CidrBlock": "22.0.32.0/20",
- "MapPublicIpOnLaunch": false,
- "Tags": [
- {
- "Key": "aws-cdk:subnet-name",
- "Value": "Private1",
- },
- {
- "Key": "aws-cdk:subnet-type",
- "Value": "Private",
- },
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet1",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::Subnet",
- },
- "vpcIdPrivate1Subnet2DefaultRoute8F3C7EA8": {
- "Properties": {
- "DestinationCidrBlock": "0.0.0.0/0",
- "NatGatewayId": {
- "Ref": "vpcIdPublic1Subnet2NATGateway6CB106F1",
- },
- "RouteTableId": {
- "Ref": "vpcIdPrivate1Subnet2RouteTable83AB5D28",
- },
- },
- "Type": "AWS::EC2::Route",
- },
- "vpcIdPrivate1Subnet2RouteTable83AB5D28": {
- "Properties": {
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet2",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::RouteTable",
- },
- "vpcIdPrivate1Subnet2RouteTableAssociation08CCB002": {
- "Properties": {
- "RouteTableId": {
- "Ref": "vpcIdPrivate1Subnet2RouteTable83AB5D28",
- },
- "SubnetId": {
- "Ref": "vpcIdPrivate1Subnet2Subnet91487ED7",
- },
- },
- "Type": "AWS::EC2::SubnetRouteTableAssociation",
- },
- "vpcIdPrivate1Subnet2Subnet91487ED7": {
- "Properties": {
- "AvailabilityZone": {
- "Fn::Select": [
- 1,
- {
- "Fn::GetAZs": "",
- },
- ],
- },
- "CidrBlock": "22.0.48.0/20",
- "MapPublicIpOnLaunch": false,
- "Tags": [
- {
- "Key": "aws-cdk:subnet-name",
- "Value": "Private1",
- },
- {
- "Key": "aws-cdk:subnet-type",
- "Value": "Private",
- },
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Private1Subnet2",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::Subnet",
- },
- "vpcIdPublic1Subnet1DefaultRoute72228A8F": {
- "DependsOn": [
- "vpcIdVPCGW33ACD385",
- ],
- "Properties": {
- "DestinationCidrBlock": "0.0.0.0/0",
- "GatewayId": {
- "Ref": "vpcIdIGW108455B5",
- },
- "RouteTableId": {
- "Ref": "vpcIdPublic1Subnet1RouteTable31C18ABF",
- },
- },
- "Type": "AWS::EC2::Route",
- },
- "vpcIdPublic1Subnet1EIPDC296CEC": {
- "Properties": {
- "Domain": "vpc",
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- },
- "Type": "AWS::EC2::EIP",
- },
- "vpcIdPublic1Subnet1NATGateway5EB16AC0": {
- "DependsOn": [
- "vpcIdPublic1Subnet1DefaultRoute72228A8F",
- "vpcIdPublic1Subnet1RouteTableAssociation055876F9",
- ],
- "Properties": {
- "AllocationId": {
- "Fn::GetAtt": [
- "vpcIdPublic1Subnet1EIPDC296CEC",
- "AllocationId",
- ],
- },
- "SubnetId": {
- "Ref": "vpcIdPublic1Subnet1SubnetD21C4A28",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- },
- "Type": "AWS::EC2::NatGateway",
- },
- "vpcIdPublic1Subnet1RouteTable31C18ABF": {
- "Properties": {
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::RouteTable",
- },
- "vpcIdPublic1Subnet1RouteTableAssociation055876F9": {
- "Properties": {
- "RouteTableId": {
- "Ref": "vpcIdPublic1Subnet1RouteTable31C18ABF",
- },
- "SubnetId": {
- "Ref": "vpcIdPublic1Subnet1SubnetD21C4A28",
- },
- },
- "Type": "AWS::EC2::SubnetRouteTableAssociation",
- },
- "vpcIdPublic1Subnet1SubnetD21C4A28": {
- "Properties": {
- "AvailabilityZone": {
- "Fn::Select": [
- 0,
- {
- "Fn::GetAZs": "",
- },
- ],
- },
- "CidrBlock": "22.0.0.0/20",
- "MapPublicIpOnLaunch": true,
- "Tags": [
- {
- "Key": "aws-cdk:subnet-name",
- "Value": "Public1",
- },
- {
- "Key": "aws-cdk:subnet-type",
- "Value": "Public",
- },
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet1",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::Subnet",
- },
- "vpcIdPublic1Subnet2DefaultRouteE84FDE21": {
- "DependsOn": [
- "vpcIdVPCGW33ACD385",
- ],
- "Properties": {
- "DestinationCidrBlock": "0.0.0.0/0",
- "GatewayId": {
- "Ref": "vpcIdIGW108455B5",
- },
- "RouteTableId": {
- "Ref": "vpcIdPublic1Subnet2RouteTable6FCD1F9B",
- },
- },
- "Type": "AWS::EC2::Route",
- },
- "vpcIdPublic1Subnet2EIP15C5A5DD": {
- "Properties": {
- "Domain": "vpc",
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- },
- "Type": "AWS::EC2::EIP",
- },
- "vpcIdPublic1Subnet2NATGateway6CB106F1": {
- "DependsOn": [
- "vpcIdPublic1Subnet2DefaultRouteE84FDE21",
- "vpcIdPublic1Subnet2RouteTableAssociation126B887D",
- ],
- "Properties": {
- "AllocationId": {
- "Fn::GetAtt": [
- "vpcIdPublic1Subnet2EIP15C5A5DD",
- "AllocationId",
- ],
- },
- "SubnetId": {
- "Ref": "vpcIdPublic1Subnet2SubnetA44E3D9B",
- },
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- },
- "Type": "AWS::EC2::NatGateway",
- },
- "vpcIdPublic1Subnet2RouteTable6FCD1F9B": {
- "Properties": {
- "Tags": [
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::RouteTable",
- },
- "vpcIdPublic1Subnet2RouteTableAssociation126B887D": {
- "Properties": {
- "RouteTableId": {
- "Ref": "vpcIdPublic1Subnet2RouteTable6FCD1F9B",
- },
- "SubnetId": {
- "Ref": "vpcIdPublic1Subnet2SubnetA44E3D9B",
- },
- },
- "Type": "AWS::EC2::SubnetRouteTableAssociation",
- },
- "vpcIdPublic1Subnet2SubnetA44E3D9B": {
- "Properties": {
- "AvailabilityZone": {
- "Fn::Select": [
- 1,
- {
- "Fn::GetAZs": "",
- },
- ],
- },
- "CidrBlock": "22.0.16.0/20",
- "MapPublicIpOnLaunch": true,
- "Tags": [
- {
- "Key": "aws-cdk:subnet-name",
- "Value": "Public1",
- },
- {
- "Key": "aws-cdk:subnet-type",
- "Value": "Public",
- },
- {
- "Key": "Environment",
- "Value": "Test",
- },
- {
- "Key": "Name",
- "Value": "VpcStackTest/macalbert-shared-test-vpcstack-test-stack/vpcId/Public1Subnet2",
- },
- {
- "Key": "Project",
- "Value": "shared-test",
- },
- {
- "Key": "StackId",
- "Value": "macalbert-shared-test-vpcstack-test-stack",
- },
- ],
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::Subnet",
- },
- "vpcIdVPCGW33ACD385": {
- "Properties": {
- "InternetGatewayId": {
- "Ref": "vpcIdIGW108455B5",
- },
- "VpcId": {
- "Ref": "vpcId937700B3",
- },
- },
- "Type": "AWS::EC2::VPCGatewayAttachment",
- },
- },
- "Rules": {
- "CheckBootstrapVersion": {
- "Assertions": [
- {
- "Assert": {
- "Fn::Not": [
- {
- "Fn::Contains": [
- [
- "1",
- "2",
- "3",
- "4",
- "5",
- ],
- {
- "Ref": "BootstrapVersion",
- },
- ],
- },
- ],
- },
- "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
- },
- ],
- },
- },
-}
-`;
diff --git a/src/iac/test/aws/network/vpcLookupStack.test.ts b/src/iac/test/aws/network/vpcLookupStack.test.ts
deleted file mode 100644
index 3df0de69..00000000
--- a/src/iac/test/aws/network/vpcLookupStack.test.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import { App } from 'aws-cdk-lib';
-import {
- VpcLookupStack,
- type VpcLookupStackProps,
-} from '../../../src/aws/network/vpcLookupStack';
-
-// Mock the Vpc.fromLookup to avoid actual AWS lookups in tests
-jest.mock('aws-cdk-lib/aws-ec2', () => {
- const actual = jest.requireActual('aws-cdk-lib/aws-ec2');
- return {
- ...actual,
- Vpc: {
- ...actual.Vpc,
- fromLookup: jest.fn((scope, _id, options) => ({
- vpcId: options.vpcId,
- node: scope.node,
- })),
- },
- };
-});
-
-// Note: VPC lookup requires actual AWS VPC to exist, so we mock the lookup
-describe('VpcLookupStack', () => {
- const env = {
- account: '123456789012',
- region: 'us-east-1',
- };
-
- function createVpcLookupStackProps(): VpcLookupStackProps {
- return {
- vpcId: 'vpc-12345678',
- env,
- };
- }
-
- test('Should_CreateStack_When_ValidPropsProvided', () => {
- // Arrange
- const app = new App();
- const props = createVpcLookupStackProps();
-
- // Act
- const stack = new VpcLookupStack(app, props);
-
- // Assert
- expect(stack).toBeDefined();
- expect(stack.vpc).toBeDefined();
- });
-
- test('Should_UseVpcId_When_StackCreated', () => {
- // Arrange
- const app = new App();
- const props = createVpcLookupStackProps();
-
- // Act
- const stack = new VpcLookupStack(app, props);
-
- // Assert
- expect(stack.stackName).toBe(props.vpcId);
- });
-
- test('Should_PassEnvironment_When_PropsIncludeEnv', () => {
- // Arrange
- const app = new App();
- const props = createVpcLookupStackProps();
-
- // Act
- const stack = new VpcLookupStack(app, props);
-
- // Assert
- expect(stack.account).toBe(env.account);
- expect(stack.region).toBe(env.region);
- });
-
- test('Should_LookupVpc_When_StackConstructed', () => {
- // Arrange
- const app = new App();
- const props = createVpcLookupStackProps();
- const { Vpc } = jest.requireMock('aws-cdk-lib/aws-ec2');
-
- // Act
- new VpcLookupStack(app, props);
-
- // Assert
- expect(Vpc.fromLookup).toHaveBeenCalledWith(
- expect.anything(),
- 'VpcNetwork',
- {
- vpcId: props.vpcId,
- },
- );
- });
-
- test('Should_HandleMissingEnv_When_EnvNotProvided', () => {
- // Arrange
- const app = new App();
- const propsWithoutEnv: VpcLookupStackProps = {
- vpcId: 'vpc-87654321',
- };
-
- // Act
- const stack = new VpcLookupStack(app, propsWithoutEnv);
-
- // Assert
- expect(stack).toBeDefined();
- expect(stack.vpc).toBeDefined();
- });
-});
diff --git a/src/iac/test/aws/network/vpcStack.test.ts b/src/iac/test/aws/network/vpcStack.test.ts
deleted file mode 100644
index d78558ae..00000000
--- a/src/iac/test/aws/network/vpcStack.test.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { Template } from 'aws-cdk-lib/assertions';
-import { SubnetType } from 'aws-cdk-lib/aws-ec2';
-import 'source-map-support/register';
-import { App, Stack } from 'aws-cdk-lib';
-import {
- type VPCStackProps,
- VpcStack,
-} from '../../../src/aws/network/vpcStack';
-import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
-
-describe('VpcStackTest', () => {
- const expected: VPCStackProps = {
- name: 'VpcStack',
- stackName: 'shared',
- maxAzs: 2,
- natGateways: 2,
- enableDnsHostnames: true,
- enableDnsSupport: true,
- envName: AppEnvironment.Test,
- vpcName: 'private-CustomVpc',
- vpcCdir: '22.0.0.0/16',
- subnetConfiguration: [
- {
- cidrMask: 20,
- name: 'Public1',
- subnetType: SubnetType.PUBLIC,
- },
- {
- cidrMask: 20,
- name: 'Private1',
- subnetType: SubnetType.PRIVATE_WITH_EGRESS,
- },
- ],
- githubRepo: 'shared-test',
- };
- const env = {
- account: 'account',
- region: 'eu-west-1',
- };
-
- test('Should_MatchSnapshotAndResources_When_VpcStackIsCreated', () => {
- // Arrange
- const stack = new Stack(new App(), 'VpcStackTest', { env });
-
- // Act
- const vpcStack = new VpcStack(stack, expected);
-
- // Assert
- const template = Template.fromStack(vpcStack);
- expect(template.toJSON()).toMatchSnapshot('VpcStackTest');
- template.resourceCountIs('AWS::EC2::VPC', 1);
- template.hasResourceProperties('AWS::EC2::VPC', {
- EnableDnsSupport: expected.enableDnsSupport,
- EnableDnsHostnames: expected.enableDnsHostnames,
- CidrBlock: expected.vpcCdir,
- });
- template.resourceCountIs('AWS::EC2::InternetGateway', 1);
- template.resourceCountIs('AWS::EC2::VPCGatewayAttachment', 1);
- template.resourceCountIs('AWS::EC2::Subnet', 4);
- });
-});
diff --git a/src/iac/test/aws/website/Dockerfile b/tests/iac/aws/website/Dockerfile
similarity index 100%
rename from src/iac/test/aws/website/Dockerfile
rename to tests/iac/aws/website/Dockerfile
diff --git a/src/iac/test/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap b/tests/iac/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap
similarity index 100%
rename from src/iac/test/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap
rename to tests/iac/aws/website/__snapshots__/staticWebsiteStack.test.ts.snap
diff --git a/src/iac/test/aws/website/cloudfrontUrlRewrite.test.ts b/tests/iac/aws/website/cloudfrontUrlRewrite.test.ts
similarity index 98%
rename from src/iac/test/aws/website/cloudfrontUrlRewrite.test.ts
rename to tests/iac/aws/website/cloudfrontUrlRewrite.test.ts
index 19028390..c64c102d 100644
--- a/src/iac/test/aws/website/cloudfrontUrlRewrite.test.ts
+++ b/tests/iac/aws/website/cloudfrontUrlRewrite.test.ts
@@ -5,7 +5,7 @@ describe('CloudFront URL Rewrite Function', () => {
// Read and execute the handler file
const handlerPath = join(
__dirname,
- '../../../src/aws/website/cloudfront-url-rewrite.js',
+ '../../../../src/iac/aws/website/cloudfront-url-rewrite.js',
);
const handlerCode = readFileSync(handlerPath, 'utf8');
diff --git a/src/iac/test/aws/website/staticWebsiteStack.test.ts b/tests/iac/aws/website/staticWebsiteStack.test.ts
similarity index 91%
rename from src/iac/test/aws/website/staticWebsiteStack.test.ts
rename to tests/iac/aws/website/staticWebsiteStack.test.ts
index ea11f6fd..daf9627f 100644
--- a/src/iac/test/aws/website/staticWebsiteStack.test.ts
+++ b/tests/iac/aws/website/staticWebsiteStack.test.ts
@@ -6,9 +6,9 @@ import { Template } from 'aws-cdk-lib/assertions';
import {
StaticWebsiteStack,
type StaticWebsiteStackProps,
-} from '../../../src/aws/website/staticWebsiteStack';
-import type { DomainConfig } from '../../../src/config/domain/customStack';
-import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+} from '../../../../src/iac/aws/website/staticWebsiteStack';
+import type { DomainConfig } from '../../../../src/iac/config/domain/customStack';
+import { AppEnvironment } from '../../../../src/iac/config/domain/model/appEnvironment';
describe('Static website Stack', () => {
const env = {
diff --git a/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts b/tests/iac/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
similarity index 80%
rename from src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
rename to tests/iac/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
index 010e1766..e0be9d82 100644
--- a/src/iac/test/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
+++ b/tests/iac/config/application/deployInfrastructure/deployInfrastructureHandler.test.ts
@@ -1,13 +1,12 @@
import type { Environment } from 'aws-cdk-lib';
import { App } from 'aws-cdk-lib';
-import { DeployInfrastructureHandler } from '../../../../src/config/application/deployInfrastructure/deployInfrastructureHandler';
-import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
-import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
-import { ConfigValidationError } from '../../../../src/config/infrastructure/utilities/errors';
+import { DeployInfrastructureHandler } from '../../../../../src/iac/config/application/deployInfrastructure/deployInfrastructureHandler';
+import type { IDeploymentRequest } from '../../../../../src/iac/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../../src/iac/config/domain/model/appEnvironment';
+import { ConfigValidationError } from '../../../../../src/iac/config/infrastructure/utilities/errors';
-// Mock AWS infrastructure (VPC + CDK Stacks)
-jest.mock('../../../../src/aws/network/vpcLookupStack');
-jest.mock('../../../../src/aws/website/staticWebsiteStack');
+// Mock AWS infrastructure (CDK Stacks)
+jest.mock('../../../../../src/iac/aws/website/staticWebsiteStack');
describe('DeployInfrastructureUseCase', () => {
let app: App;
@@ -44,7 +43,6 @@ describe('DeployInfrastructureUseCase', () => {
function createValidConfig(): IDeploymentRequest {
return {
repoName: 'test-repo',
- vpcId: 'vpc-12345678',
branch: 'main',
environment: AppEnvironment.Production,
domain: {
@@ -93,7 +91,7 @@ describe('DeployInfrastructureUseCase', () => {
// Arrange
const invalidConfig: IDeploymentRequest = {
...iacConfig,
- vpcId: '',
+ repoName: '',
};
const invalidOrchestrator = new DeployInfrastructureHandler(
app,
diff --git a/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts b/tests/iac/config/domain/builders/factories/stackBuilderFactory.test.ts
similarity index 74%
rename from src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
rename to tests/iac/config/domain/builders/factories/stackBuilderFactory.test.ts
index ebf5b6cf..10bff138 100644
--- a/src/iac/test/config/domain/builders/factories/stackBuilderFactory.test.ts
+++ b/tests/iac/config/domain/builders/factories/stackBuilderFactory.test.ts
@@ -1,14 +1,13 @@
import { App } from 'aws-cdk-lib';
-import type { IDeploymentRequest } from '../../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
-import { AppEnvironment } from '../../../../../src/config/domain/model/appEnvironment';
-import { FrontendBuilder } from '../../../../../src/config/domain/builders/frontendBuilder';
-import { StackBuilderFactory } from '../../../../../src/config/domain/builders/factories/stackBuilderFactory';
+import type { IDeploymentRequest } from '../../../../../../src/iac/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../../../src/iac/config/domain/model/appEnvironment';
+import { FrontendBuilder } from '../../../../../../src/iac/config/domain/builders/frontendBuilder';
+import { StackBuilderFactory } from '../../../../../../src/iac/config/domain/builders/factories/stackBuilderFactory';
describe('StackBuilderFactory', () => {
function createValidConfig(): IDeploymentRequest {
return {
repoName: 'test-repo',
- vpcId: 'vpc-12345678',
branch: 'main',
environment: AppEnvironment.Production,
domain: {
diff --git a/src/iac/test/config/domain/builders/frontendBuilder.test.ts b/tests/iac/config/domain/builders/frontendBuilder.test.ts
similarity index 72%
rename from src/iac/test/config/domain/builders/frontendBuilder.test.ts
rename to tests/iac/config/domain/builders/frontendBuilder.test.ts
index 8d2d37a9..d654a75f 100644
--- a/src/iac/test/config/domain/builders/frontendBuilder.test.ts
+++ b/tests/iac/config/domain/builders/frontendBuilder.test.ts
@@ -1,22 +1,19 @@
-import { FrontendBuilder } from '../../../../src/config/domain/builders/frontendBuilder';
-import type { FrontendBuilderProps } from '../../../../src/config/domain/builders/frontendBuilder';
-import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
-import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
-import type { IStackBuildContext } from '../../../../src/config/domain/iStackBuilder';
+import { FrontendBuilder } from '../../../../../src/iac/config/domain/builders/frontendBuilder';
+import type { FrontendBuilderProps } from '../../../../../src/iac/config/domain/builders/frontendBuilder';
+import type { IDeploymentRequest } from '../../../../../src/iac/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../../src/iac/config/domain/model/appEnvironment';
+import type { IStackBuildContext } from '../../../../../src/iac/config/domain/iStackBuilder';
import { App } from 'aws-cdk-lib';
-import type { IVpc } from 'aws-cdk-lib/aws-ec2';
-import { FileProjectPath } from '../../../../src/config/infrastructure/projectPath/fileProjectPath';
+import { FileProjectPath } from '../../../../../src/iac/config/infrastructure/projectPath/fileProjectPath';
-jest.mock('../../../../src/aws/website/staticWebsiteStack');
+jest.mock('../../../../../src/iac/aws/website/staticWebsiteStack');
describe('FrontendBuilder', () => {
- const mockVpc = {} as IVpc;
const mockEnv = { account: '123456789012', region: 'us-east-1' };
const createMinimalConfig = (): IDeploymentRequest => ({
repoName: 'test-repo',
branch: 'main',
- vpcId: 'vpc-123',
environment: AppEnvironment.Production,
domain: {
name: 'example.com',
@@ -40,7 +37,6 @@ describe('FrontendBuilder', () => {
});
const createBuildContext = (): IStackBuildContext => ({
- vpc: mockVpc,
env: mockEnv,
environment: AppEnvironment.Production,
});
diff --git a/src/iac/test/config/domain/iStackBuilder.test.ts b/tests/iac/config/domain/iStackBuilder.test.ts
similarity index 86%
rename from src/iac/test/config/domain/iStackBuilder.test.ts
rename to tests/iac/config/domain/iStackBuilder.test.ts
index 315658bd..7ed3efab 100644
--- a/src/iac/test/config/domain/iStackBuilder.test.ts
+++ b/tests/iac/config/domain/iStackBuilder.test.ts
@@ -2,12 +2,11 @@ import {
IStackBuilder,
type IStackBuildProps,
type IStackBuildContext,
-} from '../../../src/config/domain/iStackBuilder';
-import type { IDeploymentRequest } from '../../../src/config/application/deployInfrastructure/models/deploymentRequest';
-import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+} from '../../../../src/iac/config/domain/iStackBuilder';
+import type { IDeploymentRequest } from '../../../../src/iac/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../src/iac/config/domain/model/appEnvironment';
import type { Stack } from 'aws-cdk-lib';
import { App } from 'aws-cdk-lib';
-import type { IVpc } from 'aws-cdk-lib/aws-ec2';
class ConcreteStackBuilder extends IStackBuilder {
public context!: IStackBuildContext;
@@ -32,7 +31,6 @@ describe('IStackBuilder', () => {
const createMockConfig = (): IDeploymentRequest => ({
repoName: 'test-repo',
branch: 'main',
- vpcId: 'vpc-123',
environment: AppEnvironment.Production,
domain: {
name: 'example.com',
@@ -78,7 +76,6 @@ describe('IStackBuilder', () => {
const config = createMockConfig();
const stackPart = new ConcreteStackBuilder(createProps(config));
const context: IStackBuildContext = {
- vpc: {} as IVpc,
env: { account: '123456789012', region: 'us-east-1' },
environment: AppEnvironment.Production,
};
diff --git a/src/iac/test/config/domain/m47Stack.test.ts b/tests/iac/config/domain/m47Stack.test.ts
similarity index 95%
rename from src/iac/test/config/domain/m47Stack.test.ts
rename to tests/iac/config/domain/m47Stack.test.ts
index 078e227e..2312b9ee 100644
--- a/src/iac/test/config/domain/m47Stack.test.ts
+++ b/tests/iac/config/domain/m47Stack.test.ts
@@ -2,8 +2,8 @@ import { App } from 'aws-cdk-lib';
import {
CustomStack,
type CustomStackProps,
-} from '../../../src/config/domain/customStack';
-import { AppEnvironment } from '../../../src/config/domain/model/appEnvironment';
+} from '../../../../src/iac/config/domain/customStack';
+import { AppEnvironment } from '../../../../src/iac/config/domain/model/appEnvironment';
describe('CustomStack', () => {
function createCustomStackProps(): CustomStackProps {
diff --git a/src/iac/test/config/domain/model/appEnvironment.test.ts b/tests/iac/config/domain/model/appEnvironment.test.ts
similarity index 96%
rename from src/iac/test/config/domain/model/appEnvironment.test.ts
rename to tests/iac/config/domain/model/appEnvironment.test.ts
index be5e8f1b..e4ecc89e 100644
--- a/src/iac/test/config/domain/model/appEnvironment.test.ts
+++ b/tests/iac/config/domain/model/appEnvironment.test.ts
@@ -1,4 +1,4 @@
-import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+import { AppEnvironment } from '../../../../../src/iac/config/domain/model/appEnvironment';
describe('AppEnvironment', () => {
test('Should_HaveProductionValue_When_EnumAccessed', () => {
diff --git a/src/iac/test/config/domain/services/stackBuilderService.test.ts b/tests/iac/config/domain/services/stackBuilderService.test.ts
similarity index 86%
rename from src/iac/test/config/domain/services/stackBuilderService.test.ts
rename to tests/iac/config/domain/services/stackBuilderService.test.ts
index 59550fe3..7b2a09e9 100644
--- a/src/iac/test/config/domain/services/stackBuilderService.test.ts
+++ b/tests/iac/config/domain/services/stackBuilderService.test.ts
@@ -1,25 +1,23 @@
import type { Environment } from 'aws-cdk-lib';
-import type { IVpc } from 'aws-cdk-lib/aws-ec2';
import type { Node } from 'constructs';
-import { ConsoleDeploymentLogger } from '../../../../src/config/infrastructure/logging/consoleDeploymentLogger';
+import { ConsoleDeploymentLogger } from '../../../../../src/iac/config/infrastructure/logging/consoleDeploymentLogger';
import {
IStackBuilder,
type IStackBuildProps,
-} from '../../../../src/config/domain/iStackBuilder';
-import { StackBuildError } from '../../../../src/config/infrastructure/utilities/errors';
-import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
-import { StackBuilderService } from '../../../../src/config/domain/services/stackBuilderService';
+} from '../../../../../src/iac/config/domain/iStackBuilder';
+import { StackBuildError } from '../../../../../src/iac/config/infrastructure/utilities/errors';
+import { AppEnvironment } from '../../../../../src/iac/config/domain/model/appEnvironment';
+import { StackBuilderService } from '../../../../../src/iac/config/domain/services/stackBuilderService';
// Mock dependencies
jest.mock(
- '../../../../src/config/infrastructure/logging/consoleDeploymentLogger',
+ '../../../../../src/iac/config/infrastructure/logging/consoleDeploymentLogger',
);
describe('StackBuilderService', () => {
let stackBuilderService: StackBuilderService;
let mockLogger: jest.Mocked;
let mockNode: jest.Mocked;
- let mockVpc: jest.Mocked;
let env: Environment;
beforeEach(() => {
@@ -37,9 +35,6 @@ describe('StackBuilderService', () => {
tryGetContext: jest.fn(),
} as unknown as jest.Mocked;
- // Create mock VPC
- mockVpc = {} as jest.Mocked;
-
// Create environment
env = {
region: 'us-east-1',
@@ -51,7 +46,6 @@ describe('StackBuilderService', () => {
mockLogger,
'test-repo',
env,
- mockVpc,
mockNode,
AppEnvironment.Production,
);
diff --git a/src/iac/test/config/infrastructure/fileOperations/fileOperations.test.ts b/tests/iac/config/infrastructure/fileOperations/fileOperations.test.ts
similarity index 97%
rename from src/iac/test/config/infrastructure/fileOperations/fileOperations.test.ts
rename to tests/iac/config/infrastructure/fileOperations/fileOperations.test.ts
index 74777bd8..ec979744 100644
--- a/src/iac/test/config/infrastructure/fileOperations/fileOperations.test.ts
+++ b/tests/iac/config/infrastructure/fileOperations/fileOperations.test.ts
@@ -1,6 +1,6 @@
import fs from 'node:fs';
-import { FileOperationError } from '../../../../src/config/infrastructure/utilities/errors';
-import { FileOperations } from '../../../../src/config/infrastructure/fileOperations/fileOperations';
+import { FileOperationError } from '../../../../../src/iac/config/infrastructure/utilities/errors';
+import { FileOperations } from '../../../../../src/iac/config/infrastructure/fileOperations/fileOperations';
// Mock fs module
jest.mock('node:fs');
diff --git a/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts b/tests/iac/config/infrastructure/logging/consoleDeploymentLogger.test.ts
similarity index 85%
rename from src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
rename to tests/iac/config/infrastructure/logging/consoleDeploymentLogger.test.ts
index f1f45364..42c4c324 100644
--- a/src/iac/test/config/infrastructure/logging/consoleDeploymentLogger.test.ts
+++ b/tests/iac/config/infrastructure/logging/consoleDeploymentLogger.test.ts
@@ -1,7 +1,7 @@
-import { ConsoleDeploymentLogger } from '../../../../src/config/infrastructure/logging/consoleDeploymentLogger';
-import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
-import type { IProjectPath } from '../../../../src/config/domain/ports/iProjectPath';
-import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
+import { ConsoleDeploymentLogger } from '../../../../../src/iac/config/infrastructure/logging/consoleDeploymentLogger';
+import type { IDeploymentRequest } from '../../../../../src/iac/config/application/deployInfrastructure/models/deploymentRequest';
+import type { IProjectPath } from '../../../../../src/iac/config/domain/ports/iProjectPath';
+import { AppEnvironment } from '../../../../../src/iac/config/domain/model/appEnvironment';
describe('ConsoleDeploymentLogger', () => {
let consoleLogSpy: jest.SpyInstance;
@@ -20,7 +20,6 @@ describe('ConsoleDeploymentLogger', () => {
const createMockConfig = (): IDeploymentRequest => ({
repoName: 'test-repo',
branch: 'main',
- vpcId: 'vpc-123',
environment: AppEnvironment.Production,
domain: {
name: 'example.com',
diff --git a/src/iac/test/config/infrastructure/projectPath/fileProjectPath.test.ts b/tests/iac/config/infrastructure/projectPath/fileProjectPath.test.ts
similarity index 97%
rename from src/iac/test/config/infrastructure/projectPath/fileProjectPath.test.ts
rename to tests/iac/config/infrastructure/projectPath/fileProjectPath.test.ts
index 88ca756d..4102530d 100644
--- a/src/iac/test/config/infrastructure/projectPath/fileProjectPath.test.ts
+++ b/tests/iac/config/infrastructure/projectPath/fileProjectPath.test.ts
@@ -1,4 +1,4 @@
-import { FileProjectPath } from '../../../../src/config/infrastructure/projectPath/fileProjectPath';
+import { FileProjectPath } from '../../../../../src/iac/config/infrastructure/projectPath/fileProjectPath';
describe('FileSystemPath', () => {
describe('constructor', () => {
diff --git a/src/iac/test/config/infrastructure/utilities/cloudFormationUtils.test.ts b/tests/iac/config/infrastructure/utilities/cloudFormationUtils.test.ts
similarity index 97%
rename from src/iac/test/config/infrastructure/utilities/cloudFormationUtils.test.ts
rename to tests/iac/config/infrastructure/utilities/cloudFormationUtils.test.ts
index 26e5d112..dc7d1dd5 100644
--- a/src/iac/test/config/infrastructure/utilities/cloudFormationUtils.test.ts
+++ b/tests/iac/config/infrastructure/utilities/cloudFormationUtils.test.ts
@@ -1,4 +1,4 @@
-import { formatRepoNameForCloudFormation } from '../../../../src/config/infrastructure/utilities/cloudFormationUtils';
+import { formatRepoNameForCloudFormation } from '../../../../../src/iac/config/infrastructure/utilities/cloudFormationUtils';
describe('cloudFormationUtils', () => {
describe('formatRepoNameForCloudFormation', () => {
diff --git a/src/iac/test/config/infrastructure/utilities/errors.test.ts b/tests/iac/config/infrastructure/utilities/errors.test.ts
similarity index 97%
rename from src/iac/test/config/infrastructure/utilities/errors.test.ts
rename to tests/iac/config/infrastructure/utilities/errors.test.ts
index 316e7e80..124b5a73 100644
--- a/src/iac/test/config/infrastructure/utilities/errors.test.ts
+++ b/tests/iac/config/infrastructure/utilities/errors.test.ts
@@ -4,7 +4,7 @@ import {
EcrAuthError,
StackBuildError,
ConfigValidationError,
-} from '../../../../src/config/infrastructure/utilities/errors';
+} from '../../../../../src/iac/config/infrastructure/utilities/errors';
describe('DeploymentError', () => {
test('Should_CreateDeploymentError_When_MessageProvided', () => {
@@ -250,10 +250,9 @@ describe('ConfigValidationError', () => {
test('Should_StoreValidationErrors_When_ErrorCreated', () => {
// Arrange
- const message = 'Validation failed with 3 errors';
+ const message = 'Validation failed with 2 errors';
const validationErrors = [
'repoName is required',
- 'vpcId is required',
'domain.name is required',
];
@@ -262,7 +261,7 @@ describe('ConfigValidationError', () => {
// Assert
expect(error.validationErrors).toEqual(validationErrors);
- expect(error.validationErrors).toHaveLength(3);
+ expect(error.validationErrors).toHaveLength(2);
expect(error.cause).toBeUndefined();
});
diff --git a/src/iac/test/config/infrastructure/utilities/templateNormalizer.ts b/tests/iac/config/infrastructure/utilities/templateNormalizer.ts
similarity index 100%
rename from src/iac/test/config/infrastructure/utilities/templateNormalizer.ts
rename to tests/iac/config/infrastructure/utilities/templateNormalizer.ts
diff --git a/src/iac/test/config/infrastructure/validation/configValidator.test.ts b/tests/iac/config/infrastructure/validation/configValidator.test.ts
similarity index 87%
rename from src/iac/test/config/infrastructure/validation/configValidator.test.ts
rename to tests/iac/config/infrastructure/validation/configValidator.test.ts
index 82722006..df3119d2 100644
--- a/src/iac/test/config/infrastructure/validation/configValidator.test.ts
+++ b/tests/iac/config/infrastructure/validation/configValidator.test.ts
@@ -1,7 +1,7 @@
-import type { IDeploymentRequest } from '../../../../src/config/application/deployInfrastructure/models/deploymentRequest';
-import { AppEnvironment } from '../../../../src/config/domain/model/appEnvironment';
-import { ConfigValidator } from '../../../../src/config/domain/validation/configValidator';
-import { ConfigValidationError } from '../../../../src/config/infrastructure/utilities/errors';
+import type { IDeploymentRequest } from '../../../../../src/iac/config/application/deployInfrastructure/models/deploymentRequest';
+import { AppEnvironment } from '../../../../../src/iac/config/domain/model/appEnvironment';
+import { ConfigValidator } from '../../../../../src/iac/config/domain/validation/configValidator';
+import { ConfigValidationError } from '../../../../../src/iac/config/infrastructure/utilities/errors';
describe('ConfigValidator', () => {
let validator: ConfigValidator;
@@ -13,7 +13,6 @@ describe('ConfigValidator', () => {
function createValidConfig(): IDeploymentRequest {
return {
repoName: 'test-repo',
- vpcId: 'vpc-12345678',
branch: 'main',
environment: AppEnvironment.Production,
domain: {
@@ -60,25 +59,6 @@ describe('ConfigValidator', () => {
);
});
- test('Should_ThrowConfigValidationError_When_VpcIdMissing', () => {
- // Arrange
- const config = createValidConfig();
- config.vpcId = '';
-
- // Act
- const act = () => validator.validate(config);
-
- // Assert
- expect(act).toThrow(ConfigValidationError);
- expect(act).toThrow(
- expect.objectContaining({
- validationErrors: expect.arrayContaining([
- 'vpcId is required and cannot be empty',
- ]),
- }),
- );
- });
-
test('Should_ThrowConfigValidationError_When_BranchMissing', () => {
// Arrange
const config = createValidConfig();
@@ -261,7 +241,6 @@ describe('ConfigValidator', () => {
// Arrange
const config = createValidConfig();
config.repoName = '';
- config.vpcId = '';
config.branch = '';
config.domain.name = '';
@@ -270,12 +249,11 @@ describe('ConfigValidator', () => {
// Assert
expect(act).toThrow(ConfigValidationError);
- expect(act).toThrow('Configuration validation failed with 4 error(s)');
+ expect(act).toThrow('Configuration validation failed with 3 error(s)');
expect(act).toThrow(
expect.objectContaining({
validationErrors: expect.arrayContaining([
'repoName is required and cannot be empty',
- 'vpcId is required and cannot be empty',
'branch is required and cannot be empty',
'domain.name is required and cannot be empty',
]),
diff --git a/src/iac/jest.config.js b/tests/iac/jest.config.js
similarity index 65%
rename from src/iac/jest.config.js
rename to tests/iac/jest.config.js
index b91139a2..20e84feb 100644
--- a/src/iac/jest.config.js
+++ b/tests/iac/jest.config.js
@@ -1,10 +1,16 @@
/** @type {import('jest').Config} */
+const path = require('node:path');
+
const config = {
testEnvironment: "node",
- roots: ["/test"],
testMatch: ["**/*.test.ts"],
transform: {
- "^.+\\.ts?$": ["ts-jest"],
+ "^.+\\.ts$": [
+ "ts-jest",
+ {
+ tsconfig: path.resolve(__dirname, "tsconfig.json"),
+ },
+ ],
},
collectCoverage: true,
coverageDirectory: "coverage",
@@ -14,5 +20,4 @@ const config = {
],
};
-// eslint-disable-next-line no-undef
module.exports = config;
diff --git a/tests/iac/package.json b/tests/iac/package.json
new file mode 100644
index 00000000..37c95e93
--- /dev/null
+++ b/tests/iac/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "@envilder/iac-tests",
+ "version": "0.1.0",
+ "private": true,
+ "license": "UNLICENSED",
+ "scripts": {
+ "test": "jest --colors --seed=1",
+ "test:update": "jest --colors --seed=1 --updateSnapshot --verbose",
+ "test:ci": "jest --colors --seed=1 --ci --verbose",
+ "test:ci:update": "jest --colors --seed=1 --ci --verbose --updateSnapshot"
+ },
+ "devDependencies": {
+ "@types/jest": "^29.5.14",
+ "aws-cdk-lib": "^2.200.0",
+ "constructs": "^10.4.2",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.3.4",
+ "typescript": "^5.9.3"
+ }
+}
diff --git a/tests/iac/tsconfig.json b/tests/iac/tsconfig.json
new file mode 100644
index 00000000..c0473511
--- /dev/null
+++ b/tests/iac/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "../../src/iac/tsconfig.json",
+ "compilerOptions": {
+ "module": "commonjs",
+ "outDir": null,
+ "declaration": false,
+ "composite": false
+ },
+ "include": [
+ "**/*.ts"
+ ]
+}
From 4326ac82d9dbfe436ba00097358ed0cc5f60bbbc Mon Sep 17 00:00:00 2001
From: mac
Date: Fri, 27 Mar 2026 22:40:21 +0100
Subject: [PATCH 09/49] feat(version): Add application versioning support
- Introduced a global variable for application version.
- Updated various components to display the current version dynamically.
- Enhanced localization for version-related strings.
---
src/apps/website/astro.config.mjs | 10 +++++
.../website/src/components/Changelog.astro | 5 ++-
.../website/src/components/CodeBlock.astro | 1 +
.../website/src/components/DocsContent.astro | 16 +++----
src/apps/website/src/components/Footer.astro | 5 ++-
.../website/src/components/GetStarted.astro | 4 +-
.../website/src/components/GitHubAction.astro | 8 ++--
src/apps/website/src/components/Hero.astro | 17 ++++----
.../website/src/components/HowItWorks.astro | 8 ++--
.../src/components/ProblemSolution.astro | 2 +-
.../website/src/components/Providers.astro | 2 +-
src/apps/website/src/env.d.ts | 1 +
src/apps/website/src/i18n/ca.ts | 43 ++++++++++++++-----
src/apps/website/src/i18n/en.ts | 39 +++++++++++++----
src/apps/website/src/i18n/es.ts | 43 ++++++++++++++-----
src/apps/website/src/i18n/types.ts | 24 ++++++++++-
src/apps/website/src/layouts/BaseLayout.astro | 10 +++++
src/apps/website/src/styles/global.css | 1 +
18 files changed, 178 insertions(+), 61 deletions(-)
create mode 100644 src/apps/website/src/env.d.ts
diff --git a/src/apps/website/astro.config.mjs b/src/apps/website/astro.config.mjs
index e8eea203..fd8009b6 100644
--- a/src/apps/website/astro.config.mjs
+++ b/src/apps/website/astro.config.mjs
@@ -1,5 +1,10 @@
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
+import { readFileSync } from 'node:fs';
+
+const rootPkg = JSON.parse(
+ readFileSync(new URL('../../../package.json', import.meta.url), 'utf-8'),
+);
export default defineConfig({
site: 'https://envilder.com',
@@ -12,6 +17,11 @@ export default defineConfig({
prefixDefaultLocale: false,
},
},
+ vite: {
+ define: {
+ __APP_VERSION__: JSON.stringify(rootPkg.version),
+ },
+ },
build: {
assets: '_assets',
},
diff --git a/src/apps/website/src/components/Changelog.astro b/src/apps/website/src/components/Changelog.astro
index ddadaed1..6f17642a 100644
--- a/src/apps/website/src/components/Changelog.astro
+++ b/src/apps/website/src/components/Changelog.astro
@@ -7,6 +7,7 @@ interface Props {
const { lang = 'en' } = Astro.props;
const t = useTranslations(lang);
+const version = `v${__APP_VERSION__}`;
---
@@ -21,10 +22,10 @@ const t = useTranslations(lang);
diff --git a/src/apps/website/src/components/CodeBlock.astro b/src/apps/website/src/components/CodeBlock.astro
index a3807cec..dff5a8b4 100644
--- a/src/apps/website/src/components/CodeBlock.astro
+++ b/src/apps/website/src/components/CodeBlock.astro
@@ -53,6 +53,7 @@ const { lang = 'json', filename } = Astro.props;
font-family: var(--font-mono);
font-size: 0.82rem;
line-height: 1.8;
+ letter-spacing: -0.02em;
overflow-x: auto;
color: var(--color-text);
margin: 0;
diff --git a/src/apps/website/src/components/DocsContent.astro b/src/apps/website/src/components/DocsContent.astro
index a83a5c83..d1d169bc 100644
--- a/src/apps/website/src/components/DocsContent.astro
+++ b/src/apps/website/src/components/DocsContent.astro
@@ -66,8 +66,8 @@ const t = useTranslations(lang);
{t.docs.reqTitle}
@@ -316,7 +316,7 @@ envilder --map=param-map.json --envfile=.env --profile=staging-account`}{t.docs.pullOptions}
- Option {t.docs.mapThDescription}
+ {t.docs.optionHeader} {t.docs.mapThDescription}
--map{t.docs.pullOptMap}
@@ -342,7 +342,7 @@ envilder --provider=azure \\
--vault-url=https://my-vault.vault.azure.net \\
--map=param-map.json --envfile=.env`}
- Output
+ {t.docs.pullOutputTitle}
{`# Generated by Envilder
API_KEY=abc123
DB_PASSWORD=secret456`}
@@ -357,7 +357,7 @@ DB_PASSWORD=secret456`}
{t.docs.pushOptions}
- Option {t.docs.mapThDescription}
+ {t.docs.optionHeader} {t.docs.mapThDescription}
--push{t.docs.pushOptPush}
@@ -394,7 +394,7 @@ envilder --push --provider=azure \\
{t.docs.pushSingleOptions}
- Option {t.docs.mapThDescription}
+ {t.docs.optionHeader} {t.docs.mapThDescription}
--push{t.docs.pushSingleOptPush}
@@ -416,8 +416,8 @@ envilder --push --provider=azure \\
{t.docs.ghaPrerequisites}
- AWS: {t.docs.ghaPrereqAws}
- Azure: {t.docs.ghaPrereqAzure}
+ {t.docs.ghaPrereqAws}
+ {t.docs.ghaPrereqAzure}
{t.docs.ghaPrereqMap}
diff --git a/src/apps/website/src/components/Footer.astro b/src/apps/website/src/components/Footer.astro
index a5559d8e..8ba10ecc 100644
--- a/src/apps/website/src/components/Footer.astro
+++ b/src/apps/website/src/components/Footer.astro
@@ -8,6 +8,7 @@ interface Props {
const { lang = 'en' } = Astro.props;
const t = useTranslations(lang);
+const version = `v${__APP_VERSION__}`;
const currentYear = new Date().getFullYear();
const currentPath = Astro.url.pathname;
@@ -46,8 +47,8 @@ const links = {
{t.footer.tagline}
diff --git a/src/apps/website/src/components/GetStarted.astro b/src/apps/website/src/components/GetStarted.astro
index fd845c93..d913f70d 100644
--- a/src/apps/website/src/components/GetStarted.astro
+++ b/src/apps/website/src/components/GetStarted.astro
@@ -25,8 +25,8 @@ const t = useTranslations(lang);
{t.getStarted.prerequisites}
{t.getStarted.prereqNode}
- {t.getStarted.prereqAws} (for AWS SSM)
- {t.getStarted.prereqAzure} (for Azure Key Vault)
+ {t.getStarted.prereqAws} ({t.getStarted.prereqAwsNote})
+ {t.getStarted.prereqAzure} ({t.getStarted.prereqAzureNote})
{t.getStarted.prereqIam} ssm:GetParameter / ssm:PutParameter
diff --git a/src/apps/website/src/components/GitHubAction.astro b/src/apps/website/src/components/GitHubAction.astro
index 838acc5e..6c9c4d9e 100644
--- a/src/apps/website/src/components/GitHubAction.astro
+++ b/src/apps/website/src/components/GitHubAction.astro
@@ -73,25 +73,25 @@ const t = useTranslations(lang);
map-file
- Yes
+ {t.gha.yes}
—
{t.gha.inputMapDesc}
env-file
- Yes
+ {t.gha.yes}
—
{t.gha.inputEnvDesc}
provider
- No
+ {t.gha.no}
aws
{t.gha.inputProviderDesc}
vault-url
- No
+ {t.gha.no}
—
{t.gha.inputVaultDesc}
diff --git a/src/apps/website/src/components/Hero.astro b/src/apps/website/src/components/Hero.astro
index 30218e57..7b1a32ae 100644
--- a/src/apps/website/src/components/Hero.astro
+++ b/src/apps/website/src/components/Hero.astro
@@ -8,13 +8,14 @@ interface Props {
const { lang = 'en' } = Astro.props;
const t = useTranslations(lang);
+const version = `v${__APP_VERSION__}`;
---
- {t.hero.version}
+ {version}
{t.hero.openSource}
@@ -26,8 +27,8 @@ const t = useTranslations(lang);
{t.hero.description}{' '}
- {t.hero.descAws} or {t.hero.descAzure}
- {' '}as a single source of truth. No more copy-pasting secrets.
+ {t.hero.descAws} {t.hero.descOr} {t.hero.descAzure}
+ {' '}{t.hero.descSuffix}
@@ -54,7 +55,7 @@ const t = useTranslations(lang);
-
+
$
@@ -75,7 +76,7 @@ const t = useTranslations(lang);
-
+
$
@@ -88,15 +89,15 @@ const t = useTranslations(lang);
✔
- Fetched DB_PASSWORD → ···pass
+ {t.hero.terminalFetched1}
✔
- Fetched API_KEY → ···key
+ {t.hero.terminalFetched2}
✔
- Environment file written to .env
+ {t.hero.terminalWritten}
diff --git a/src/apps/website/src/components/HowItWorks.astro b/src/apps/website/src/components/HowItWorks.astro
index 4dba2b8d..4465ec09 100644
--- a/src/apps/website/src/components/HowItWorks.astro
+++ b/src/apps/website/src/components/HowItWorks.astro
@@ -57,10 +57,10 @@ const t = useTranslations(lang);
{`$ envilder --map=param-map.json --envfile=.env
-✔ Fetched DB_PASSWORD → ···word
-✔ Fetched API_KEY → ···key
-✔ Fetched SECRET_TOKEN → ···oken
-✔ Environment file written to .env`}
+${t.howItWorks.terminalFetched1}
+${t.howItWorks.terminalFetched2}
+${t.howItWorks.terminalFetched3}
+${t.howItWorks.terminalWritten}`}
diff --git a/src/apps/website/src/components/ProblemSolution.astro b/src/apps/website/src/components/ProblemSolution.astro
index bf8976be..9790d694 100644
--- a/src/apps/website/src/components/ProblemSolution.astro
+++ b/src/apps/website/src/components/ProblemSolution.astro
@@ -12,7 +12,7 @@ const t = useTranslations(lang);
-
{t.problemSolution.title}{t.problemSolution.titleAccent} with .env files
+
{t.problemSolution.title}{t.problemSolution.titleAccent} {t.problemSolution.titleSuffix}
{t.problemSolution.subtitle}
diff --git a/src/apps/website/src/components/Providers.astro b/src/apps/website/src/components/Providers.astro
index 663cfd77..bf2259e6 100644
--- a/src/apps/website/src/components/Providers.astro
+++ b/src/apps/website/src/components/Providers.astro
@@ -59,7 +59,7 @@ const t = useTranslations(lang);
{t.providers.azureTitle}
- New in v0.8
+ {t.providers.azureBadge}
diff --git a/src/apps/website/src/env.d.ts b/src/apps/website/src/env.d.ts
new file mode 100644
index 00000000..41fad5b5
--- /dev/null
+++ b/src/apps/website/src/env.d.ts
@@ -0,0 +1 @@
+declare const __APP_VERSION__: string;
diff --git a/src/apps/website/src/i18n/ca.ts b/src/apps/website/src/i18n/ca.ts
index 60f528c4..a04e0cc2 100644
--- a/src/apps/website/src/i18n/ca.ts
+++ b/src/apps/website/src/i18n/ca.ts
@@ -15,7 +15,6 @@ export const ca: Translations = {
light: 'Clar',
},
hero: {
- version: 'v0.8.0',
openSource: 'Codi obert · MIT',
title1: 'Els teus secrets.',
title2: 'Una comanda.',
@@ -24,8 +23,16 @@ export const ca: Translations = {
'Una eina CLI i GitHub Action que centralitza de forma segura les teves variables d\'entorn des de',
descAws: 'AWS SSM',
descAzure: 'Azure Key Vault',
+ descOr: 'o',
+ descSuffix:
+ 'com a font de veritat única. Adéu a copiar i enganxar secrets.',
getStarted: '▶ Comença',
viewOnGithub: '★ Veure a GitHub',
+ terminalComment1: '# 1. Defineix el mapeig',
+ terminalComment2: '# 2. Descarrega secrets → genera .env',
+ terminalFetched1: ' Obtingut DB_PASSWORD → ···pass',
+ terminalFetched2: ' Obtingut API_KEY → ···key',
+ terminalWritten: ' Fitxer d\'entorn escrit a .env',
},
trust: {
label: 'COMPATIBLE AMB',
@@ -33,6 +40,7 @@ export const ca: Translations = {
problemSolution: {
title: 'El ',
titleAccent: 'problema',
+ titleSuffix: ' amb fitxers .env',
subtitle:
'Gestionar secrets manualment no escala. És insegur, propens a errors i crea fricció per a tot l\'equip.',
problems: [
@@ -99,6 +107,10 @@ export const ca: Translations = {
'Un fitxer d\'entorn net i actualitzat — generat des de la font de veritat. Utilitza\'l localment o injecta\'l en CI/CD amb la GitHub Action.',
},
],
+ terminalFetched1: '✔ Obtingut DB_PASSWORD → ···word',
+ terminalFetched2: '✔ Obtingut API_KEY → ···key',
+ terminalFetched3: '✔ Obtingut SECRET_TOKEN → ···oken',
+ terminalWritten: '✔ Fitxer d\'entorn escrit a .env',
},
features: {
title: 'Fet per a ',
@@ -179,6 +191,7 @@ export const ca: Translations = {
'Registre d\'auditoria CloudTrail',
],
azureTitle: 'Azure Key Vault',
+ azureBadge: 'Nou a v0.8',
azureFeatures: [
'Auto-normalitza noms de secrets (barres → guions)',
'Autenticació DefaultAzureCredential',
@@ -208,6 +221,8 @@ export const ca: Translations = {
inputVaultDesc: 'URL d\'Azure Key Vault',
output: 'Output:',
outputDesc: 'Ruta al fitxer .env generat',
+ yes: 'Sí',
+ no: 'No',
},
changelog: {
title: 'Què hi ha de ',
@@ -215,6 +230,7 @@ export const ca: Translations = {
subtitle:
'Novetats de l\'última versió. El suport multi-proveïdor ja és aquí.',
releaseTitle: 'Suport Multi-Proveïdor',
+ releaseDate: '22 de març de 2026',
highlights: [
{
icon: '✨',
@@ -279,6 +295,13 @@ export const ca: Translations = {
description:
'Suport d\'AWS SSM Parameter Store i Azure Key Vault',
},
+ {
+ status: 'done',
+ label: '📖',
+ title: 'Web de documentació',
+ description:
+ 'Web de docs dedicada amb guies, exemples i referència API',
+ },
{
status: 'next',
label: '⚡',
@@ -293,13 +316,6 @@ export const ca: Translations = {
description:
'Valida SSM vs .env, falla CI si estan desincronitzats',
},
- {
- status: 'planned',
- label: '📖',
- title: 'Web de documentació',
- description:
- 'Web de docs dedicada amb guies, exemples i referència API',
- },
{
status: 'planned',
label: '🤖',
@@ -318,6 +334,8 @@ export const ca: Translations = {
prereqAws: 'AWS CLI configurat',
prereqAzure: 'Azure CLI configurat',
prereqIam: 'Permisos IAM:',
+ prereqAwsNote: 'per AWS SSM',
+ prereqAzureNote: 'per Azure Key Vault',
install: 'Instal·lar',
quickStart: 'Inici ràpid',
step1: 'Crea un param-map.json que mapegi variables d\'entorn a rutes de secrets',
@@ -349,6 +367,7 @@ export const ca: Translations = {
linkDiscussions: 'Discussions',
linkSecurity: 'Seguretat',
linkSponsor: 'Patrocina',
+ license: 'Llicència MIT',
copyright: 'Fet amb Astro. Codi obert a GitHub.',
builtWith: 'Fet amb Astro. Codi obert a GitHub.',
},
@@ -388,6 +407,8 @@ export const ca: Translations = {
reqNode: 'Node.js v20+',
reqAws: 'AWS CLI',
reqAzure: 'Azure CLI',
+ reqAwsNote: 'per AWS SSM',
+ reqAzureNote: 'per Azure Key Vault',
reqDownload: 'Descarregar',
reqInstallGuide: 'Guia d\'instal·lació',
installTitle: 'Instal·lació',
@@ -483,6 +504,7 @@ export const ca: Translations = {
pullOptions: 'Opcions',
pullExamples: 'Exemples',
pullOutput: 'Sortida',
+ optionHeader: 'Opció',
pullOptMap: 'Ruta al fitxer JSON de mapeig',
pullOptEnv: 'Ruta on escriure el .env',
pullOptProvider: 'aws (per defecte) o azure',
@@ -492,6 +514,7 @@ export const ca: Translations = {
pullCommentProfile: '# Amb perfil AWS',
pullCommentAzureConfig: '# Azure via $config al fitxer de mapeig',
pullCommentAzureFlags: '# Azure via flags CLI',
+ pullOutputTitle: 'Sortida',
pushTitle: 'Comanda push',
pushDesc:
'Puja variables d\'entorn d\'un fitxer .env local al teu proveïdor al núvol utilitzant un fitxer de mapeig.',
@@ -543,7 +566,7 @@ export const ca: Translations = {
ghaThOutput: 'Output',
ghaYes: 'Sí',
ghaNo: 'No',
- ghaInputMap: 'Ruta al fitxer JSON de mapatge',
+ ghaInputMap: 'Ruta al fitxer JSON de mapeig',
ghaInputEnv: 'Ruta al fitxer .env a generar',
ghaInputProvider: 'aws o azure',
ghaInputVault: 'URL d\'Azure Key Vault',
@@ -551,7 +574,7 @@ export const ca: Translations = {
configPriorityDesc:
'Quan hi ha múltiples fonts de configuració, Envilder les resol en aquest ordre (el més alt guanya):',
configPriority1: 'Flags CLI / inputs GHA',
- configPriority2: '$config al fitxer de mapatge',
+ configPriority2: '$config al fitxer de mapeig',
configPriority3: 'Per defecte (AWS)',
configPriorityExplain:
'Això vol dir que --provider=azure a la CLI sobreescriurà "provider": "aws" a $config.',
diff --git a/src/apps/website/src/i18n/en.ts b/src/apps/website/src/i18n/en.ts
index d92644fd..d8f37405 100644
--- a/src/apps/website/src/i18n/en.ts
+++ b/src/apps/website/src/i18n/en.ts
@@ -15,7 +15,6 @@ export const en: Translations = {
light: 'Light',
},
hero: {
- version: 'v0.8.0',
openSource: 'Open Source · MIT',
title1: 'Your secrets.',
title2: 'One command.',
@@ -24,8 +23,16 @@ export const en: Translations = {
'A CLI tool and GitHub Action that securely centralizes your environment variables from',
descAws: 'AWS SSM',
descAzure: 'Azure Key Vault',
+ descOr: 'or',
+ descSuffix:
+ 'as a single source of truth. No more copy-pasting secrets.',
getStarted: '▶ Get Started',
viewOnGithub: '★ View on GitHub',
+ terminalComment1: '# 1. Define your mapping',
+ terminalComment2: '# 2. Pull secrets → generate .env',
+ terminalFetched1: ' Fetched DB_PASSWORD → ···pass',
+ terminalFetched2: ' Fetched API_KEY → ···key',
+ terminalWritten: ' Environment file written to .env',
},
trust: {
label: 'WORKS WITH',
@@ -33,6 +40,7 @@ export const en: Translations = {
problemSolution: {
title: 'The ',
titleAccent: 'problem',
+ titleSuffix: ' with .env files',
subtitle:
"Managing secrets manually doesn't scale. It's insecure, error-prone, and creates friction for your entire team.",
problems: [
@@ -99,6 +107,10 @@ export const en: Translations = {
'A clean, up-to-date environment file — generated from the source of truth. Use it locally or inject it in CI/CD with the GitHub Action.',
},
],
+ terminalFetched1: '✔ Fetched DB_PASSWORD → ···word',
+ terminalFetched2: '✔ Fetched API_KEY → ···key',
+ terminalFetched3: '✔ Fetched SECRET_TOKEN → ···oken',
+ terminalWritten: '✔ Environment file written to .env',
},
features: {
title: 'Built for ',
@@ -179,6 +191,7 @@ export const en: Translations = {
'CloudTrail audit logging',
],
azureTitle: 'Azure Key Vault',
+ azureBadge: 'New in v0.8',
azureFeatures: [
'Auto-normalizes secret names (slashes → hyphens)',
'DefaultAzureCredential authentication',
@@ -207,12 +220,15 @@ export const en: Translations = {
inputVaultDesc: 'Azure Key Vault URL',
output: 'Output:',
outputDesc: 'Path to the generated .env file',
+ yes: 'Yes',
+ no: 'No',
},
changelog: {
title: "What's ",
titleAccent: 'new',
subtitle: 'Latest release highlights. Multi-provider support is here.',
releaseTitle: 'Multi-Provider Support',
+ releaseDate: 'March 22, 2026',
highlights: [
{
icon: '✨',
@@ -272,6 +288,13 @@ export const en: Translations = {
title: 'Multi-provider (AWS + Azure)',
description: 'AWS SSM Parameter Store and Azure Key Vault support',
},
+ {
+ status: 'done',
+ label: '📖',
+ title: 'Documentation website',
+ description:
+ 'Dedicated docs site with guides, examples, API reference',
+ },
{
status: 'next',
label: '⚡',
@@ -285,13 +308,6 @@ export const en: Translations = {
title: 'Check/sync mode (--check)',
description: 'Validate SSM vs .env, fail CI if out-of-sync',
},
- {
- status: 'planned',
- label: '📖',
- title: 'Documentation website',
- description:
- 'Dedicated docs site with guides, examples, API reference',
- },
{
status: 'planned',
label: '🤖',
@@ -310,6 +326,8 @@ export const en: Translations = {
prereqAws: 'AWS CLI configured',
prereqAzure: 'Azure CLI configured',
prereqIam: 'IAM permissions:',
+ prereqAwsNote: 'for AWS SSM',
+ prereqAzureNote: 'for Azure Key Vault',
install: 'Install',
quickStart: 'Quick start',
step1: 'Create a param-map.json mapping env vars to secret paths',
@@ -341,6 +359,7 @@ export const en: Translations = {
linkDiscussions: 'Discussions',
linkSecurity: 'Security',
linkSponsor: 'Sponsor',
+ license: 'MIT License',
copyright: 'Built with Astro. Open source on GitHub.',
builtWith: 'Built with Astro. Open source on GitHub.',
},
@@ -380,6 +399,8 @@ export const en: Translations = {
reqNode: 'Node.js v20+',
reqAws: 'AWS CLI',
reqAzure: 'Azure CLI',
+ reqAwsNote: 'for AWS SSM',
+ reqAzureNote: 'for Azure Key Vault',
reqDownload: 'Download',
reqInstallGuide: 'Install guide',
installTitle: 'Installation',
@@ -474,6 +495,7 @@ export const en: Translations = {
pullOptions: 'Options',
pullExamples: 'Examples',
pullOutput: 'Output',
+ optionHeader: 'Option',
pullOptMap: 'Path to JSON mapping file',
pullOptEnv: 'Path to write .env',
pullOptProvider: 'aws (default) or azure',
@@ -483,6 +505,7 @@ export const en: Translations = {
pullCommentProfile: '# With AWS profile',
pullCommentAzureConfig: '# Azure via $config in map file',
pullCommentAzureFlags: '# Azure via CLI flags',
+ pullOutputTitle: 'Output',
pushTitle: 'Push command',
pushDesc:
'Upload environment variables from a local .env file to your cloud provider using a mapping file.',
diff --git a/src/apps/website/src/i18n/es.ts b/src/apps/website/src/i18n/es.ts
index 683f5959..39b3fb11 100644
--- a/src/apps/website/src/i18n/es.ts
+++ b/src/apps/website/src/i18n/es.ts
@@ -15,7 +15,6 @@ export const es: Translations = {
light: 'Claro',
},
hero: {
- version: 'v0.8.0',
openSource: 'Código abierto · MIT',
title1: 'Tus secretos.',
title2: 'Un comando.',
@@ -24,8 +23,16 @@ export const es: Translations = {
'Una herramienta CLI y GitHub Action que centraliza de forma segura tus variables de entorno desde',
descAws: 'AWS SSM',
descAzure: 'Azure Key Vault',
+ descOr: 'o',
+ descSuffix:
+ 'como fuente única de verdad. Se acabó copiar y pegar secretos.',
getStarted: '▶ Empezar',
viewOnGithub: '★ Ver en GitHub',
+ terminalComment1: '# 1. Define tu mapeo',
+ terminalComment2: '# 2. Descarga secretos → genera .env',
+ terminalFetched1: ' Obtenido DB_PASSWORD → ···pass',
+ terminalFetched2: ' Obtenido API_KEY → ···key',
+ terminalWritten: ' Archivo de entorno escrito en .env',
},
trust: {
label: 'COMPATIBLE CON',
@@ -33,6 +40,7 @@ export const es: Translations = {
problemSolution: {
title: 'El ',
titleAccent: 'problema',
+ titleSuffix: ' con archivos .env',
subtitle:
'Gestionar secretos manualmente no escala. Es inseguro, propenso a errores y crea fricción para todo el equipo.',
problems: [
@@ -99,6 +107,10 @@ export const es: Translations = {
'Un archivo de entorno limpio y actualizado — generado desde la fuente de verdad. Úsalo localmente o inyéctalo en CI/CD con la GitHub Action.',
},
],
+ terminalFetched1: '✔ Obtenido DB_PASSWORD → ···word',
+ terminalFetched2: '✔ Obtenido API_KEY → ···key',
+ terminalFetched3: '✔ Obtenido SECRET_TOKEN → ···oken',
+ terminalWritten: '✔ Archivo de entorno escrito en .env',
},
features: {
title: 'Hecho para ',
@@ -179,6 +191,7 @@ export const es: Translations = {
'Registro de auditoría CloudTrail',
],
azureTitle: 'Azure Key Vault',
+ azureBadge: 'Nuevo en v0.8',
azureFeatures: [
'Auto-normaliza nombres de secretos (barras → guiones)',
'Autenticación DefaultAzureCredential',
@@ -208,6 +221,8 @@ export const es: Translations = {
inputVaultDesc: 'URL de Azure Key Vault',
output: 'Output:',
outputDesc: 'Ruta al archivo .env generado',
+ yes: 'Sí',
+ no: 'No',
},
changelog: {
title: 'Qué hay de ',
@@ -215,6 +230,7 @@ export const es: Translations = {
subtitle:
'Novedades de la última versión. El soporte multi-proveedor ya está aquí.',
releaseTitle: 'Soporte Multi-Proveedor',
+ releaseDate: '22 de marzo de 2026',
highlights: [
{
icon: '✨',
@@ -279,6 +295,13 @@ export const es: Translations = {
description:
'Soporte de AWS SSM Parameter Store y Azure Key Vault',
},
+ {
+ status: 'done',
+ label: '📖',
+ title: 'Web de documentación',
+ description:
+ 'Web de docs dedicada con guías, ejemplos y referencia API',
+ },
{
status: 'next',
label: '⚡',
@@ -293,13 +316,6 @@ export const es: Translations = {
description:
'Valida SSM vs .env, falla CI si están desincronizados',
},
- {
- status: 'planned',
- label: '📖',
- title: 'Web de documentación',
- description:
- 'Web de docs dedicada con guías, ejemplos y referencia API',
- },
{
status: 'planned',
label: '🤖',
@@ -313,11 +329,13 @@ export const es: Translations = {
title: 'Empieza ',
titleAccent: 'ahora',
subtitle: 'En funcionamiento en menos de un minuto.',
- prerequisites: 'Prerequisitos',
+ prerequisites: 'Prerrequisitos',
prereqNode: 'Node.js v20+',
prereqAws: 'AWS CLI configurado',
prereqAzure: 'Azure CLI configurado',
prereqIam: 'Permisos IAM:',
+ prereqAwsNote: 'para AWS SSM',
+ prereqAzureNote: 'para Azure Key Vault',
install: 'Instalar',
quickStart: 'Inicio rápido',
step1: 'Crea un param-map.json que mapee variables de entorno a rutas de secretos',
@@ -349,6 +367,7 @@ export const es: Translations = {
linkDiscussions: 'Discusiones',
linkSecurity: 'Seguridad',
linkSponsor: 'Patrocinar',
+ license: 'Licencia MIT',
copyright: 'Hecho con Astro. Código abierto en GitHub.',
builtWith: 'Hecho con Astro. Código abierto en GitHub.',
},
@@ -388,6 +407,8 @@ export const es: Translations = {
reqNode: 'Node.js v20+',
reqAws: 'AWS CLI',
reqAzure: 'Azure CLI',
+ reqAwsNote: 'para AWS SSM',
+ reqAzureNote: 'para Azure Key Vault',
reqDownload: 'Descargar',
reqInstallGuide: 'Guía de instalación',
installTitle: 'Instalación',
@@ -483,6 +504,7 @@ export const es: Translations = {
pullOptions: 'Opciones',
pullExamples: 'Ejemplos',
pullOutput: 'Salida',
+ optionHeader: 'Opción',
pullOptMap: 'Ruta al archivo JSON de mapeo',
pullOptEnv: 'Ruta donde escribir el .env',
pullOptProvider: 'aws (por defecto) o azure',
@@ -492,6 +514,7 @@ export const es: Translations = {
pullCommentProfile: '# Con perfil AWS',
pullCommentAzureConfig: '# Azure vía $config en archivo de mapeo',
pullCommentAzureFlags: '# Azure vía flags CLI',
+ pullOutputTitle: 'Salida',
pushTitle: 'Comando push',
pushDesc:
'Sube variables de entorno de un archivo .env local a tu proveedor en la nube usando un archivo de mapeo.',
@@ -521,7 +544,7 @@ export const es: Translations = {
ghaSetupTitle: 'Configuración de GitHub Action',
ghaSetupDesc:
'La GitHub Action de Envilder obtiene secretos de AWS SSM o Azure Key Vault en archivos .env durante tu workflow CI/CD. No hace falta compilar — la action está pre-construida y lista para usar desde GitHub Marketplace.',
- ghaPrerequisites: 'Prerequisitos',
+ ghaPrerequisites: 'Prerrequisitos',
ghaPrereqAws:
'AWS: Configura credenciales con aws-actions/configure-aws-credentials',
ghaPrereqAzure: 'Azure: Configura credenciales con azure/login',
diff --git a/src/apps/website/src/i18n/types.ts b/src/apps/website/src/i18n/types.ts
index dd5cbf35..d459b249 100644
--- a/src/apps/website/src/i18n/types.ts
+++ b/src/apps/website/src/i18n/types.ts
@@ -14,7 +14,6 @@ export interface ThemeTranslations {
}
export interface HeroTranslations {
- version: string;
openSource: string;
title1: string;
title2: string;
@@ -22,8 +21,15 @@ export interface HeroTranslations {
description: string;
descAws: string;
descAzure: string;
+ descOr: string;
+ descSuffix: string;
getStarted: string;
viewOnGithub: string;
+ terminalComment1: string;
+ terminalComment2: string;
+ terminalFetched1: string;
+ terminalFetched2: string;
+ terminalWritten: string;
}
export interface TrustTranslations {
@@ -39,6 +45,7 @@ export interface ProblemItem {
export interface ProblemSolutionTranslations {
title: string;
titleAccent: string;
+ titleSuffix: string;
subtitle: string;
problems: ProblemItem[];
arrowText: string;
@@ -55,6 +62,10 @@ export interface HowItWorksTranslations {
titleAccent: string;
subtitle: string;
steps: StepItem[];
+ terminalFetched1: string;
+ terminalFetched2: string;
+ terminalFetched3: string;
+ terminalWritten: string;
}
export interface FeatureItem {
@@ -87,6 +98,7 @@ export interface ProvidersTranslations {
awsDefault: string;
awsFeatures: string[];
azureTitle: string;
+ azureBadge: string;
azureFeatures: string[];
configPriorityTitle: string;
priorityHigh: string;
@@ -110,6 +122,8 @@ export interface GhaTranslations {
inputVaultDesc: string;
output: string;
outputDesc: string;
+ yes: string;
+ no: string;
}
export interface ChangelogHighlight {
@@ -122,6 +136,7 @@ export interface ChangelogTranslations {
titleAccent: string;
subtitle: string;
releaseTitle: string;
+ releaseDate: string;
highlights: ChangelogHighlight[];
fullChangelog: string;
viewReleases: string;
@@ -151,6 +166,8 @@ export interface GetStartedTranslations {
prereqAws: string;
prereqAzure: string;
prereqIam: string;
+ prereqAwsNote: string;
+ prereqAzureNote: string;
install: string;
quickStart: string;
step1: string;
@@ -182,6 +199,7 @@ export interface FooterTranslations {
linkDiscussions: string;
linkSecurity: string;
linkSponsor: string;
+ license: string;
copyright: string;
builtWith: string;
}
@@ -225,6 +243,8 @@ export interface DocsTranslations {
reqNode: string;
reqAws: string;
reqAzure: string;
+ reqAwsNote: string;
+ reqAzureNote: string;
reqDownload: string;
reqInstallGuide: string;
// Installation
@@ -304,6 +324,7 @@ export interface DocsTranslations {
pullOptions: string;
pullExamples: string;
pullOutput: string;
+ optionHeader: string;
pullOptMap: string;
pullOptEnv: string;
pullOptProvider: string;
@@ -313,6 +334,7 @@ export interface DocsTranslations {
pullCommentProfile: string;
pullCommentAzureConfig: string;
pullCommentAzureFlags: string;
+ pullOutputTitle: string;
// Push command
pushTitle: string;
pushDesc: string;
diff --git a/src/apps/website/src/layouts/BaseLayout.astro b/src/apps/website/src/layouts/BaseLayout.astro
index 276b8817..75bdf6cf 100644
--- a/src/apps/website/src/layouts/BaseLayout.astro
+++ b/src/apps/website/src/layouts/BaseLayout.astro
@@ -59,6 +59,16 @@ const {
+
+
+
+
+
+
+
+
+
+