Repository: nuxt/image
Pull request #1112 (2023-11-16 13:25:25)

feat: support aws amplify provider
Note: This is an experimental provider and will be available soon!

nuxt-studio[bot]: 
### <span aria-hidden="true">✅</span> Live Preview ready!

| Name | Edit | Preview | Latest Commit |
| :--- | :----- | :------ | :------ |
| **Image** | [Edit on Studio ↗︎](https://nuxt.studio/@nuxt/image/studio/content?refId=%231112) | [View Live Preview](https://image.nuxt.com?preview=4bf92ebaac60a9366a28bfbea9399d6b) | 69cae3cd76d217ed79aaa08d96548b99160ba46f |

<!-- This comment is generated by [Nuxt Studio](https://nuxt.studio) -->
<!-- Do not remove or edit this comment. -->

cloudflare-pages[bot]: ## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>68eab59</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>🚫&nbsp; Build failed.</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/nuxt-image/a175d332-dcea-4281-8125-ef728463b9e3)


Patch:
diff --git a/docs/content/3.providers/aws-amplify.md b/docs/content/3.providers/aws-amplify.md
new file mode 100644
index 0000000..b18686a
--- /dev/null
+++ b/docs/content/3.providers/aws-amplify.md
@@ -0,0 +1,52 @@
+---
+title: AWS Amplify
+description: Nuxt Image has first class integration with AWS Amplify Hosting
+links:
+  - label: Source
+    icon: i-simple-icons-github
+    to: https://github.com/nuxt/image/blob/main/src/runtime/providers/awsAmplify.ts
+    size: xs
+---
+
+Integration between [AWS Amplify Hosting](https://aws.amazon.com/amplify/) and the image module.
+
+This provider will be enabled by default in AWS Amplify deployments.
+
+::alert{type="warning"}
+This is an experimental preset and will be available soon! 🚀
+::
+
+## Domains
+
+To use external URLs (images not in `public/` directory), hostnames should be whitelisted.
+
+**Example:**
+
+```ts [nuxt.config]
+export default {
+  image: {
+    domains: [
+      'avatars0.githubusercontent.com'
+    ]
+  }
+}
+```
+
+## Sizes
+
+Specify any custom `width` property you use in `<NuxtImg>`, `<NuxtPicture>` and `$img`.
+
+If a width is not defined, image will fallback to closest possible width.
+
+**Example:**
+
+```ts [nuxt.config]
+export default {
+  image: {
+    screens: {
+      icon: 40,
+      avatar: 24
+    }
+  }
+}
+```
diff --git a/docs/public/providers/aws-amplify.svg b/docs/public/providers/aws-amplify.svg
new file mode 100644
index 0000000..fc29a2a
--- /dev/null
+++ b/docs/public/providers/aws-amplify.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 64 (93537) - https://sketch.com -->
+    <!-- Source: https://aws-icons.com/icons/amplify -->
+    <title>Icon-Architecture/64/Arch_AWS-Amplify-Console_64</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+        <linearGradient x1="0%" y1="100%" x2="100%" y2="0%" id="linearGradient-1">
+            <stop stop-color="#BD0816" offset="0%"></stop>
+            <stop stop-color="#FF5252" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="Icon-Architecture/64/Arch_AWS-Amplify-Console_64" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Icon-Architecture-BG/64/Mobile" fill="url(#linearGradient-1)">
+            <rect id="Rectangle" x="0" y="0" width="80" height="80"></rect>
+        </g>
+        <path d="M59.6107389,59.179 L39.5067389,20 L45.2577389,20 L65.3627389,59.179 L59.6107389,59.179 Z M67.8887389,59.722 L46.7587389,18.544 C46.5887389,18.21 46.2447389,18 45.8697389,18 L37.8697389,18 C37.5207389,18 37.1977389,18.181 37.0157389,18.479 C36.8347389,18.776 36.8207389,19.147 36.9797389,19.457 L58.1097389,60.636 C58.2807389,60.969 58.6247389,61.179 58.9997389,61.179 L66.9997389,61.179 C67.3477389,61.179 67.6717389,60.998 67.8527389,60.7 C68.0347389,60.403 68.0487389,60.033 67.8887389,59.722 L67.8887389,59.722 Z M47.5987389,59.179 L32.2147389,30.332 L35.3657389,25.121 L53.3407389,59.179 L47.5987389,59.179 Z M36.3097389,22.624 C36.1407389,22.305 35.8147389,22.101 35.4547389,22.091 C35.1087389,22.07 34.7567389,22.265 34.5697389,22.573 L30.2097389,29.784 C30.0267389,30.086 30.0167389,30.461 30.1817389,30.772 L46.1167389,60.65 C46.2907389,60.975 46.6307389,61.179 46.9997389,61.179 L54.9997389,61.179 C55.3497389,61.179 55.6747389,60.995 55.8557389,60.695 C56.0367389,60.395 56.0477389,60.022 55.8837389,59.712 L36.3097389,22.624 Z M14.7727389,59.179 L28.8847389,35.84 L31.7597389,41.229 L25.1337389,52.678 C24.9547389,52.988 24.9547389,53.369 25.1327389,53.679 C25.3117389,53.988 25.6417389,54.179 25.9997389,54.179 L38.6667389,54.179 L41.3327389,59.179 L14.7727389,59.179 Z M40.1487389,52.708 C39.9747389,52.383 39.6347389,52.179 39.2657389,52.179 L27.7337389,52.179 L33.7687389,41.75 C33.9427389,41.451 33.9487389,41.084 33.7867389,40.779 L29.8227389,33.346 C29.6527389,33.029 29.3267389,32.827 28.9667389,32.817 C28.5827389,32.8 28.2697389,32.992 28.0847389,33.299 L12.1437389,59.661 C11.9577389,59.971 11.9517389,60.356 12.1287389,60.67 C12.3057389,60.985 12.6377389,61.179 12.9997389,61.179 L42.9997389,61.179 C43.3507389,61.179 43.6757389,60.995 43.8567389,60.694 C44.0377389,60.392 44.0477389,60.018 43.8817389,59.708 L40.1487389,52.708 Z" id="AWS-Amplify-Console_Icon_64_Squid" fill="#FFFFFF"></path>
+    </g>
+</svg>
diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts
index 32b62b6..b3d85f1 100644
--- a/playground/nuxt.config.ts
+++ b/playground/nuxt.config.ts
@@ -28,6 +28,9 @@ export default defineNuxtConfig({
     aliyun: {
       baseURL: 'https://assets.yanbot.tech'
     },
+    awsAmplify: {
+      baseURL: 'https://example.amplifyapp.com/_amplify/image'
+    },
     twicpics: {
       baseURL: 'https://demo.twic.pics/'
     },
diff --git a/playground/providers.ts b/playground/providers.ts
index 683a523..460a2d5 100644
--- a/playground/providers.ts
+++ b/playground/providers.ts
@@ -109,6 +109,16 @@ export const providers: Provider[] = [
       }
     ]
   },
+  // AWS Amplify
+  {
+    name: 'awsAmplify',
+    samples: [
+      {
+        src: '/test.jpg',
+        width: 300
+      }
+    ]
+  },
   // Cloudflare
   {
     name: 'cloudflare',
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 16d92d7..9968fea 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -88,7 +88,7 @@ importers:
         version: 3.8.1(@types/node@20.9.0)(eslint@8.53.0)(rollup@3.29.4)(typescript@5.2.2)(vite@4.5.0)(vue-tsc@1.8.22)
       nuxt-vitest:
         specifier: ^0.11.3
-        version: 0.11.3(@vitejs/plugin-vue-jsx@3.0.2)(@vitejs/plugin-vue@4.4.0)(happy-dom@12.10.3)(rollup@3.29.4)(vite@4.5.0)(vitest@0.33.0)(vue-router@4.2.5)(vue@3.3.8)
+        version: 0.11.3(@vitejs/plugin-vue-jsx@3.0.2)(@vitejs/plugin-vue@4.4.1)(happy-dom@12.10.3)(rollup@3.29.4)(vite@4.5.0)(vitest@0.33.0)(vue-router@4.2.5)(vue@3.3.8)
       playwright:
         specifier: ^1.39.0
         version: 1.39.0
@@ -118,7 +118,7 @@ importers:
         version: link:..
       '@nuxt/ui-pro':
         specifier: ^0.4.2
-        version: 0.4.2(rollup@3.29.4)(vue@3.3.8)(webpack@5.88.2)
+        version: 0.4.2(rollup@3.29.4)(vue@3.3.8)(webpack@5.89.0)
       '@nuxthq/studio':
         specifier: ^1.0.4
         version: 1.0.4(rollup@3.29.4)
@@ -1198,6 +1198,13 @@ packages:
       '@jridgewell/resolve-uri': 3.1.1
       '@jridgewell/sourcemap-codec': 1.4.15
 
+  /@jridgewell/trace-mapping@0.3.20:
+    resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==}
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.1
+      '@jridgewell/sourcemap-codec': 1.4.15
+    dev: false
+
   /@koa/router@12.0.1:
     resolution: {integrity: sha512-ribfPYfHb+Uw3b27Eiw6NPqjhIhTpVFzEWLwyc/1Xp+DCdwRRyIlAUODX+9bPARF6aQtUu1+/PHzdNvRzcs/+Q==}
     engines: {node: '>= 12'}
@@ -1633,15 +1640,15 @@ packages:
       - typescript
     dev: true
 
-  /@nuxt/postcss8@1.1.3(webpack@5.88.2):
+  /@nuxt/postcss8@1.1.3(webpack@5.89.0):
     resolution: {integrity: sha512-CdHtErhvQwueNZPBOmlAAKrNCK7aIpZDYhtS7TzXlSgPHHox1g3cSlf+Ke9oB/8t4mNNjdB+prclme2ibuCOEA==}
     dependencies:
       autoprefixer: 10.4.16(postcss@8.4.31)
-      css-loader: 5.2.7(webpack@5.88.2)
+      css-loader: 5.2.7(webpack@5.89.0)
       defu: 3.2.2
       postcss: 8.4.31
       postcss-import: 13.0.0(postcss@8.4.31)
-      postcss-loader: 4.3.0(postcss@8.4.31)(webpack@5.88.2)
+      postcss-loader: 4.3.0(postcss@8.4.31)(webpack@5.89.0)
       postcss-url: 10.1.3(postcss@8.4.31)
       semver: 7.5.4
     transitivePeerDependencies:
@@ -1723,10 +1730,10 @@ packages:
       - supports-color
     dev: true
 
-  /@nuxt/ui-pro@0.4.2(rollup@3.29.4)(vue@3.3.8)(webpack@5.88.2):
+  /@nuxt/ui-pro@0.4.2(rollup@3.29.4)(vue@3.3.8)(webpack@5.89.0):
     resolution: {integrity: sha512-TmP2+dAaulIaxoAKB6lxIckluflTeanZ6NVdtL7TTxMduscVgzEWZ3ierDUTHKf8u4D3KtB9jXL0vZcNdnf5zg==}
     dependencies:
-      '@nuxt/ui': 2.10.0(rollup@3.29.4)(vue@3.3.8)(webpack@5.88.2)
+      '@nuxt/ui': 2.10.0(rollup@3.29.4)(vue@3.3.8)(webpack@5.89.0)
       '@vueuse/core': 10.6.1(vue@3.3.8)
       defu: 6.1.3
       nuxt-icon: 0.6.1(rollup@3.29.4)(vue@3.3.8)
@@ -1756,7 +1763,7 @@ packages:
   /@nuxt/ui-templates@1.3.1:
     resolution: {integrity: sha512-5gc02Pu1HycOVUWJ8aYsWeeXcSTPe8iX8+KIrhyEtEoOSkY0eMBuo0ssljB8wALuEmepv31DlYe5gpiRwkjESA==}
 
-  /@nuxt/ui@2.10.0(rollup@3.29.4)(vue@3.3.8)(webpack@5.88.2):
+  /@nuxt/ui@2.10.0(rollup@3.29.4)(vue@3.3.8)(webpack@5.89.0):
     resolution: {integrity: sha512-pMv0BWWkeUOAJ+YkXr6xirbg2iHXKerIk9hYS7blp0aBehBTBq1gxHdtl+iA2hq9+LFahO6WyA7SJnw3h0thvQ==}
     engines: {node: '>=v16.20.2'}
     dependencies:
@@ -1766,7 +1773,7 @@ packages:
       '@iconify-json/heroicons': 1.1.13
       '@nuxt/kit': 3.8.1(rollup@3.29.4)
       '@nuxtjs/color-mode': 3.3.0(rollup@3.29.4)
-      '@nuxtjs/tailwindcss': 6.9.4(rollup@3.29.4)(webpack@5.88.2)
+      '@nuxtjs/tailwindcss': 6.9.4(rollup@3.29.4)(webpack@5.89.0)
       '@popperjs/core': 2.11.8
       '@tailwindcss/aspect-ratio': 0.4.2(tailwindcss@3.3.5)
       '@tailwindcss/container-queries': 0.1.1(tailwindcss@3.3.5)
@@ -2003,11 +2010,11 @@ packages:
       - supports-color
     dev: false
 
-  /@nuxtjs/tailwindcss@6.9.4(rollup@3.29.4)(webpack@5.88.2):
+  /@nuxtjs/tailwindcss@6.9.4(rollup@3.29.4)(webpack@5.89.0):
     resolution: {integrity: sha512-T3B3P7RgJ/WTW3plHziLWqWbMzCWctUHpjqhW1WCXB/U3FOQxGH5dG4uEOmQkA6Gj4cbTNStIU/cRxpZhbBMhg==}
     dependencies:
       '@nuxt/kit': 3.8.1(rollup@3.29.4)
-      '@nuxt/postcss8': 1.1.3(webpack@5.88.2)
+      '@nuxt/postcss8': 1.1.3(webpack@5.89.0)
       autoprefixer: 10.4.16(postcss@8.4.31)
       chokidar: 3.5.3
       clear-module: 4.1.2
@@ -2633,23 +2640,27 @@ packages:
       '@types/ms': 0.7.32
     dev: false
 
-  /@types/eslint-scope@3.7.5:
-    resolution: {integrity: sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA==}
+  /@types/eslint-scope@3.7.7:
+    resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
     dependencies:
-      '@types/eslint': 8.44.3
-      '@types/estree': 1.0.2
+      '@types/eslint': 8.44.7
+      '@types/estree': 1.0.5
     dev: false
 
-  /@types/eslint@8.44.3:
-    resolution: {integrity: sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g==}
+  /@types/eslint@8.44.7:
+    resolution: {integrity: sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==}
     dependencies:
-      '@types/estree': 1.0.2
-      '@types/json-schema': 7.0.13
+      '@types/estree': 1.0.5
+      '@types/json-schema': 7.0.15
     dev: false
 
   /@types/estree@1.0.2:
     resolution: {integrity: sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==}
 
+  /@types/estree@1.0.5:
+    resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+    dev: false
+
   /@types/fs-extra@11.0.3:
     resolution: {integrity: sha512-sF59BlXtUdzEAL1u0MSvuzWd7PdZvZEtnaVkzX5mjpdWTJ8brG0jUqve3jPCzSzvAKKMHTG8F8o/WMQLtleZdQ==}
     dependencies:
@@ -2681,6 +2692,10 @@ packages:
   /@types/json-schema@7.0.13:
     resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==}
 
+  /@types/json-schema@7.0.15:
+    resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+    dev: false
+
   /@types/json5@0.0.29:
     resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
     dev: true
@@ -3089,6 +3104,17 @@ packages:
       vite: 4.5.0(@types/node@20.9.0)
       vue: 3.3.8(typescript@5.2.2)
 
+  /@vitejs/plugin-vue@4.4.1(vite@4.5.0)(vue@3.3.8):
+    resolution: {integrity: sha512-HCQG8VDFDM7YDAdcj5QI5DvUi+r6xvo9LgvYdk7LSkUNwdpempdB5horkMSZsbdey9Ywsf5aaU8kEPw9M5kREA==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      vite: ^4.0.0
+      vue: ^3.2.25
+    dependencies:
+      vite: 4.5.0(@types/node@20.9.0)
+      vue: 3.3.8(typescript@5.2.2)
+    dev: true
+
   /@vitest/coverage-v8@0.34.4(vitest@0.33.0):
     resolution: {integrity: sha512-TZ5ghzhmg3COQqfBShL+zRQEInHmV9TSwghTdfkHpCTyTOr+rxo6x41vCNcVfWysWULtqtBVpY6YFNovxnESfA==}
     peerDependencies:
@@ -4574,7 +4600,7 @@ packages:
     resolution: {integrity: sha512-hZ8sTouIicEUhVqKEeeire6kePeCDoIBvWTSPbHc7dK4Za1odVmQ6gMgFcH701gkKGP6Uic3zcQACEqSP3sJig==}
     dev: false
 
-  /css-loader@5.2.7(webpack@5.88.2):
+  /css-loader@5.2.7(webpack@5.89.0):
     resolution: {integrity: sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==}
     engines: {node: '>= 10.13.0'}
     peerDependencies:
@@ -4590,7 +4616,7 @@ packages:
       postcss-value-parser: 4.2.0
       schema-utils: 3.3.0
       semver: 7.5.4
-      webpack: 5.88.2
+      webpack: 5.89.0
     dev: false
 
   /css-select@5.1.0:
@@ -5129,8 +5155,8 @@ packages:
       which-typed-array: 1.1.11
     dev: true
 
-  /es-module-lexer@1.3.1:
-    resolution: {integrity: sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==}
+  /es-module-lexer@1.4.1:
+    resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==}
     dev: false
 
   /es-set-tostringtag@2.0.1:
@@ -9213,7 +9239,7 @@ packages:
       - vue
     dev: false
 
-  /nuxt-vitest@0.11.3(@vitejs/plugin-vue-jsx@3.0.2)(@vitejs/plugin-vue@4.4.0)(happy-dom@12.10.3)(rollup@3.29.4)(vite@4.5.0)(vitest@0.33.0)(vue-router@4.2.5)(vue@3.3.8):
+  /nuxt-vitest@0.11.3(@vitejs/plugin-vue-jsx@3.0.2)(@vitejs/plugin-vue@4.4.1)(happy-dom@12.10.3)(rollup@3.29.4)(vite@4.5.0)(vitest@0.33.0)(vue-router@4.2.5)(vue@3.3.8):
     resolution: {integrity: sha512-jGyrOXbgwlakVaDsQCLtdttXXY2bX4J5r22rr0CTXqIFO3jhnf8e3kAU+zCQe/WSp/xtM+2HZEwrU+jqy5zuDQ==}
     peerDependencies:
       '@vitejs/plugin-vue': '*'
@@ -9222,7 +9248,7 @@ packages:
       vitest: ^0.24.5 || ^0.26.0 || ^0.27.0 || ^0.28.0 || ^0.29.0 || ^0.30.0 || ^0.33.0
     dependencies:
       '@nuxt/kit': 3.8.1(rollup@3.29.4)
-      '@vitejs/plugin-vue': 4.4.0(vite@4.5.0)(vue@3.3.8)
+      '@vitejs/plugin-vue': 4.4.1(vite@4.5.0)(vue@3.3.8)
       '@vitejs/plugin-vue-jsx': 3.0.2(vite@4.5.0)(vue@3.3.8)
       '@vitest/ui': 0.33.0(vitest@0.33.0)
       defu: 6.1.3
@@ -9297,7 +9323,7 @@ packages:
       pkg-types: 1.0.3
       radix3: 1.1.0
       scule: 1.0.0
-      std-env: 3.4.3
+      std-env: 3.5.0
       strip-literal: 1.3.0
       ufo: 1.3.1
       ultrahtml: 1.5.2
@@ -9902,7 +9928,7 @@ packages:
       yaml: 2.3.2
     dev: false
 
-  /postcss-loader@4.3.0(postcss@8.4.31)(webpack@5.88.2):
+  /postcss-loader@4.3.0(postcss@8.4.31)(webpack@5.89.0):
     resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==}
     engines: {node: '>= 10.13.0'}
     peerDependencies:
@@ -9915,7 +9941,7 @@ packages:
       postcss: 8.4.31
       schema-utils: 3.3.0
       semver: 7.5.4
-      webpack: 5.88.2
+      webpack: 5.89.0
     dev: false
 
   /postcss-merge-longhand@6.0.0(postcss@8.4.31):
@@ -11111,9 +11137,6 @@ packages:
     resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
     engines: {node: '>= 0.8'}
 
-  /std-env@3.4.3:
-    resolution: {integrity: sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==}
-
   /std-env@3.5.0:
     resolution: {integrity: sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==}
 
@@ -11446,7 +11469,7 @@ packages:
       ps-tree: 1.2.0
     dev: false
 
-  /terser-webpack-plugin@5.3.9(webpack@5.88.2):
+  /terser-webpack-plugin@5.3.9(webpack@5.89.0):
     resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
     engines: {node: '>= 10.13.0'}
     peerDependencies:
@@ -11462,12 +11485,12 @@ packages:
       uglify-js:
         optional: true
     dependencies:
-      '@jridgewell/trace-mapping': 0.3.19
+      '@jridgewell/trace-mapping': 0.3.20
       jest-worker: 27.5.1
       schema-utils: 3.3.0
       serialize-javascript: 6.0.1
-      terser: 5.21.0
-      webpack: 5.88.2
+      terser: 5.24.0
+      webpack: 5.89.0
     dev: false
 
   /terser@5.21.0:
@@ -11480,6 +11503,17 @@ packages:
       commander: 2.20.3
       source-map-support: 0.5.21
 
+  /terser@5.24.0:
+    resolution: {integrity: sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dependencies:
+      '@jridgewell/source-map': 0.3.5
+      acorn: 8.11.2
+      commander: 2.20.3
+      source-map-support: 0.5.21
+    dev: false
+
   /test-exclude@6.0.0:
     resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
     engines: {node: '>=8'}
@@ -12695,8 +12729,8 @@ packages:
   /webpack-virtual-modules@0.5.0:
     resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
 
-  /webpack@5.88.2:
-    resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==}
+  /webpack@5.89.0:
+    resolution: {integrity: sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==}
     engines: {node: '>=10.13.0'}
     hasBin: true
     peerDependencies:
@@ -12705,8 +12739,8 @@ packages:
       webpack-cli:
         optional: true
     dependencies:
-      '@types/eslint-scope': 3.7.5
-      '@types/estree': 1.0.2
+      '@types/eslint-scope': 3.7.7
+      '@types/estree': 1.0.5
       '@webassemblyjs/ast': 1.11.6
       '@webassemblyjs/wasm-edit': 1.11.6
       '@webassemblyjs/wasm-parser': 1.11.6
@@ -12715,7 +12749,7 @@ packages:
       browserslist: 4.22.1
       chrome-trace-event: 1.0.3
       enhanced-resolve: 5.15.0
-      es-module-lexer: 1.3.1
+      es-module-lexer: 1.4.1
       eslint-scope: 5.1.1
       events: 3.3.0
       glob-to-regexp: 0.4.1
@@ -12726,7 +12760,7 @@ packages:
       neo-async: 2.6.2
       schema-utils: 3.3.0
       tapable: 2.2.1
-      terser-webpack-plugin: 5.3.9(webpack@5.88.2)
+      terser-webpack-plugin: 5.3.9(webpack@5.89.0)
       watchpack: 2.4.0
       webpack-sources: 3.2.3
     transitivePeerDependencies:
diff --git a/src/provider.ts b/src/provider.ts
index 97b880d..a9b52d6 100644
--- a/src/provider.ts
+++ b/src/provider.ts
@@ -4,7 +4,7 @@ import type { Nuxt } from '@nuxt/schema'
 import type { NitroConfig } from 'nitropack'
 import { createResolver, resolvePath } from '@nuxt/kit'
 import { hash } from 'ohash'
-import { provider } from 'std-env'
+import { provider, type ProviderName } from 'std-env'
 import type { InputProvider, ImageModuleProvider, ProviderSetup } from './types'
 import type { ModuleOptions } from './module'
 import { ipxSetup } from './ipx'
@@ -12,6 +12,7 @@ import { ipxSetup } from './ipx'
 // Please add new providers alphabetically to the list below
 const BuiltInProviders = [
   'aliyun',
+  'awsAmplify',
   'cloudflare',
   'cloudimage',
   'cloudinary',
@@ -40,9 +41,11 @@ const BuiltInProviders = [
   'vercel',
   'wagtail',
   'sirv'
-]
+] as const
 
-export const providerSetup: Record<string, ProviderSetup> = {
+export type ImageProviderName = typeof BuiltInProviders[number]
+
+export const providerSetup: Partial<Record<ImageProviderName, ProviderSetup>> = {
   // IPX
   ipx: ipxSetup(),
   ipxStatic: ipxSetup({ isStatic: true }),
@@ -60,6 +63,25 @@ export const providerSetup: Record<string, ProviderSetup> = {
         }
       } satisfies NitroConfig['vercel']
     })
+  },
+
+  awsAmplify (_providerOptions, moduleOptions, nuxt: Nuxt) {
+    nuxt.options.nitro = defu(nuxt.options.nitro, {
+      awsAmplify: {
+        imageOptimization: {
+          path: '/_amplify/image',
+          cacheControl: 'public, max-age=300, immutable'
+        },
+        imageSettings: {
+          sizes: Array.from(new Set(Object.values(moduleOptions.screens || {}))),
+          formats: ['image/jpeg', 'image/png', 'image/webp', 'image/avif'],
+          minimumCacheTTL: 60 * 5,
+          domains: moduleOptions.domains,
+          remotePatterns: [], // Provided by domains
+          dangerouslyAllowSVG: false // TODO
+        }
+      }
+    })
   }
 }
 
@@ -67,7 +89,7 @@ export async function resolveProviders (nuxt: any, options: ModuleOptions): Prom
   const providers: ImageModuleProvider[] = []
 
   for (const key in options) {
-    if (BuiltInProviders.includes(key)) {
+    if (BuiltInProviders.includes(key as ImageProviderName)) {
       providers.push(await resolveProvider(nuxt, key, { provider: key, options: options[key] }))
     }
   }
@@ -93,11 +115,11 @@ export async function resolveProvider (_nuxt: any, key: string, input: InputProv
   }
 
   const resolver = createResolver(import.meta.url)
-  input.provider = BuiltInProviders.includes(input.provider)
+  input.provider = BuiltInProviders.includes(input.provider as ImageProviderName)
     ? await resolver.resolve('./runtime/providers/' + input.provider)
     : await resolvePath(input.provider)
 
-  const setup = input.setup || providerSetup[input.name]
+  const setup = input.setup || providerSetup[input.name as ImageProviderName]
 
   return <ImageModuleProvider> {
     ...input,
@@ -108,7 +130,12 @@ export async function resolveProvider (_nuxt: any, key: string, input: InputProv
   }
 }
 
-export function detectProvider (userInput?: string) {
+const autodetectableProviders: Partial<Record<ProviderName, ImageProviderName>> = {
+  vercel: 'vercel',
+  aws_amplify: 'awsAmplify'
+}
+
+export function detectProvider (userInput: string = '') {
   if (process.env.NUXT_IMAGE_PROVIDER) {
     return process.env.NUXT_IMAGE_PROVIDER
   }
@@ -117,7 +144,7 @@ export function detectProvider (userInput?: string) {
     return userInput
   }
 
-  if (provider === 'vercel') {
-    return 'vercel'
+  if (provider in autodetectableProviders) {
+    return autodetectableProviders[provider]
   }
 }
diff --git a/src/runtime/providers/awsAmplify.ts b/src/runtime/providers/awsAmplify.ts
new file mode 100644
index 0000000..a6d9971
--- /dev/null
+++ b/src/runtime/providers/awsAmplify.ts
@@ -0,0 +1,36 @@
+import { stringifyQuery } from 'ufo'
+import type { ProviderGetImage } from '../../types'
+
+export const getImage: ProviderGetImage = (src, { modifiers, baseURL = '/_amplify/image' } = {}, ctx) => {
+  const validWidths = Object.values(ctx.options.screens || {}).sort((a, b) => a - b)
+  const largestWidth = validWidths[validWidths.length - 1]
+  let width = Number(modifiers?.width || 0)
+
+  if (!width) {
+    width = largestWidth
+    if (process.env.NODE_ENV === 'development') {
+      // eslint-disable-next-line
+      console.warn(`A defined width should be provided to use the \`awsAmplify\` provider. Defaulting to \`${largestWidth}\`. Warning originated from \`${src}\`.`)
+    }
+  } else if (!validWidths.includes(width)) {
+    width = validWidths.find(validWidth => validWidth > width) || largestWidth
+    if (process.env.NODE_ENV === 'development') {
+      // eslint-disable-next-line
+      console.warn(`The width being used (\`${modifiers?.width}\`) should be added to \`image.screens\`. Defaulting to \`${width}\`. Warning originated from \`${src}\`.`)
+    }
+  }
+
+  if (process.env.NODE_ENV === 'development') {
+    return { url: src }
+  }
+
+  return {
+    url: baseURL + '?' + stringifyQuery({
+      url: src,
+      w: String(width),
+      q: String(modifiers?.quality || '100')
+    })
+  }
+}
+
+export const validateDomains = true


Test patch:
diff --git a/test/e2e/__snapshots__/no-ssr.test.ts.snap b/test/e2e/__snapshots__/no-ssr.test.ts.snap
index 8656ba7..606f4d7 100644
--- a/test/e2e/__snapshots__/no-ssr.test.ts.snap
+++ b/test/e2e/__snapshots__/no-ssr.test.ts.snap
@@ -18,6 +18,18 @@ exports[`browser (ssr: false) > aliyun should render images 2`] = `
 ]
 `;
 
+exports[`browser (ssr: false) > awsAmplify should render images 1`] = `
+[
+  "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100",
+]
+`;
+
+exports[`browser (ssr: false) > awsAmplify should render images 2`] = `
+[
+  "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100",
+]
+`;
+
 exports[`browser (ssr: false) > cloudflare should render images 1`] = `
 [
   "https://that-test.site/cdn-cgi/image/h=300,fit=contain/https://s3.that-test.site/burger.jpeg",
@@ -352,19 +364,6 @@ exports[`browser (ssr: false) > sirv should render images 2`] = `
 ]
 `;
 
-exports[`browser (ssr: false) > sirv should render images 3`] = `
-[
-  "https://demo.sirv.com/test.png?w=750&q=75",
-  "https://demo.sirv.com/harris-large.jpg?w=500&format=png",
-  "https://demo.sirv.com/lacoste.jpg?crop.type=trim&w=500&q=95",
-  "https://demo.sirv.com/look-big.jpg?h=500&scale.option=fit",
-  "https://demo.sirv.com/look-big.jpg?crop.type=face&h=500",
-  "https://demo.sirv.com/QW.pdf?page=1&w=500",
-  "https://demo.sirv.com/look-big.jpg?text=Hello&text.align=center&text.position.gravity=south&text.background.color=ffff&text.size=60&text.font.family=Arial&text.color=white&h=500",
-  "https://demo.sirv.com/t-shirt-man.jpg?watermark=/watermark-v1.png&watermark.position=center&watermark.scale.width=30%&h=500",
-]
-`;
-
 exports[`browser (ssr: false) > storyblok should render images 1`] = `
 [
   "https://a.storyblok.com/f/39898/3310x2192/e4ec08624e/demo-image.jpeg",
@@ -412,16 +411,6 @@ exports[`browser (ssr: false) > strapi should render images 2`] = `
 ]
 `;
 
-exports[`browser (ssr: false) > strapi should render images 3`] = `
-[
-  "http://localhost:1337/uploads/4d9z1eiyo2gmf6gd7xhp_823ae510e8.png",
-  "http://localhost:1337/uploads/thumbnail_4d9z1eiyo2gmf6gd7xhp_823ae510e8.png",
-  "http://localhost:1337/uploads/small_4d9z1eiyo2gmf6gd7xhp_823ae510e8.png",
-  "http://localhost:1337/uploads/medium_4d9z1eiyo2gmf6gd7xhp_823ae510e8.png",
-  "http://localhost:1337/uploads/large_4d9z1eiyo2gmf6gd7xhp_823ae510e8.png",
-]
-`;
-
 exports[`browser (ssr: false) > twicpics should render images 1`] = `
 [
   "https://demo.twic.pics/football.jpg",
diff --git a/test/e2e/__snapshots__/ssr.test.ts.snap b/test/e2e/__snapshots__/ssr.test.ts.snap
index 1dd87c0..4f5b529 100644
--- a/test/e2e/__snapshots__/ssr.test.ts.snap
+++ b/test/e2e/__snapshots__/ssr.test.ts.snap
@@ -18,6 +18,18 @@ exports[`browser (ssr: true) > aliyun should render images 2`] = `
 ]
 `;
 
+exports[`browser (ssr: true) > awsAmplify should render images 1`] = `
+[
+  "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100",
+]
+`;
+
+exports[`browser (ssr: true) > awsAmplify should render images 2`] = `
+[
+  "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100",
+]
+`;
+
 exports[`browser (ssr: true) > cloudflare should render images 1`] = `
 [
   "https://that-test.site/cdn-cgi/image/h=300,fit=contain/https://s3.that-test.site/burger.jpeg",
@@ -326,24 +338,6 @@ exports[`browser (ssr: true) > sanity should render images 2`] = `
 ]
 `;
 
-exports[`browser (ssr: true) > should emit load and error events 1`] = `
-[
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=600&h=900",
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=200&h=900",
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=600&h=200",
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=200&h=200&fit=crop",
-]
-`;
-
-exports[`browser (ssr: true) > should emit load and error events 2`] = `
-[
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=600&h=900",
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=200&h=900",
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=600&h=200",
-  "https://images.prismic.io/200629-sms-hoy/f596a543-d593-4296-9abd-3d3ac15f1e39_ray-hennessy-mpw37yXc_WQ-unsplash.jpg?auto=compress,format&w=200&h=200&fit=crop",
-]
-`;
-
 exports[`browser (ssr: true) > sirv should render images 1`] = `
 [
   "https://demo.sirv.com/test.png?w=750&q=75",
@@ -545,12 +539,6 @@ exports[`browser (ssr: true) > vercel should render images 2`] = `
 ]
 `;
 
-exports[`browser (ssr: true) > vercel should render images 3`] = `
-[
-  "https://image-component.nextjs.gallery/_next/image?url=/colors.jpg&w=750&q=75",
-]
-`;
-
 exports[`browser (ssr: true) > wagtail should render images 1`] = `
 [
   "https://cms.demo.nypr.digital/images/329944/original|format-webp|webpquality-70",
diff --git a/test/providers.ts b/test/providers.ts
index 2be396a..d9e2473 100644
--- a/test/providers.ts
+++ b/test/providers.ts
@@ -4,6 +4,7 @@ export const images = [
     none: { url: '/test.png' },
     ipx: { url: '/_ipx/_/test.png' },
     aliyun: { url: '/test.png' },
+    awsAmplify: { url: '/?url=/test.png&w=1536&q=100' },
     cloudflare: { url: '/test.png' },
     cloudinary: { url: '/f_auto,q_auto/test' },
     twicpics: { url: '/test.png' },
@@ -33,6 +34,7 @@ export const images = [
     none: { url: '/test.png' },
     ipx: { url: '/_ipx/w_200/test.png' },
     aliyun: { url: '/test.png?image_process=resize,w_200' },
+    awsAmplify: { url: '/?url=/test.png&w=320&q=100' },
     cloudflare: { url: '/cdn-cgi/image/w=200/test.png' },
     cloudinary: { url: '/f_auto,q_auto,w_200/test' },
     twicpics: { url: '/test.png?twic=v1/cover=200x-' },
@@ -62,6 +64,7 @@ export const images = [
     none: { url: '/test.png' },
     ipx: { url: '/_ipx/h_200/test.png' },
     aliyun: { url: '/test.png?image_process=resize,h_200' },
+    awsAmplify: { url: '/?url=/test.png&w=1536&q=100' },
     cloudflare: { url: '/cdn-cgi/image/h=200/test.png' },
     cloudinary: { url: '/f_auto,q_auto,h_200/test' },
     twicpics: { url: '/test.png?twic=v1/cover=-x200' },
@@ -91,6 +94,7 @@ export const images = [
     none: { url: '/test.png' },
     ipx: { url: '/_ipx/s_200x200/test.png' },
     aliyun: { url: '/test.png?image_process=resize,fw_200,fh_200' },
+    awsAmplify: { url: '/?url=/test.png&w=320&q=100' },
     cloudflare: { url: '/cdn-cgi/image/w=200,h=200/test.png' },
     cloudinary: { url: '/f_auto,q_auto,w_200,h_200/test' },
     twicpics: { url: '/test.png?twic=v1/cover=200x200' },
@@ -120,6 +124,7 @@ export const images = [
     none: { url: '/test.png' },
     ipx: { url: '/_ipx/fit_contain&s_200x200/test.png' },
     aliyun: { url: '/test.png?image_process=fit,contain/resize,fw_200,fh_200' },
+    awsAmplify: { url: '/?url=/test.png&w=320&q=100' },
     cloudflare: { url: '/cdn-cgi/image/w=200,h=200,fit=contain/test.png' },
     cloudinary: { url: '/f_auto,q_auto,w_200,h_200,c_scale/test' },
     twicpics: { url: '/test.png?twic=v1/inside=200x200' },
@@ -149,6 +154,7 @@ export const images = [
     none: { url: '/test.png' },
     ipx: { url: '/_ipx/fit_contain&f_jpeg&s_200x200/test.png' },
     aliyun: { url: '/test.png?image_process=fit,contain/format,jpeg/resize,fw_200,fh_200' },
+    awsAmplify: { url: '/?url=/test.png&w=320&q=100' },
     cloudflare: { url: '/cdn-cgi/image/w=200,h=200,fit=contain,f=jpeg/test.png' },
     cloudinary: { url: '/f_jpg,q_auto,w_200,h_200,c_scale/test' },
     twicpics: { url: '/test.png?twic=v1/output=jpeg/inside=200x200' },
diff --git a/test/unit/providers.test.ts b/test/unit/providers.test.ts
index 4e807ea..acf4785 100644
--- a/test/unit/providers.test.ts
+++ b/test/unit/providers.test.ts
@@ -8,6 +8,7 @@ import { cleanDoubleSlashes } from '#image/utils'
 import * as ipx from '#image/providers/ipx'
 import * as none from '~/src/runtime/providers/none'
 import * as aliyun from '#image/providers/aliyun'
+import * as awsAmplify from '#image/providers/awsAmplify'
 import * as cloudflare from '#image/providers/cloudflare'
 import * as cloudinary from '#image/providers/cloudinary'
 import * as twicpics from '#image/providers/twicpics'
@@ -80,6 +81,16 @@ describe('Providers', () => {
       expect(generated).toMatchObject(image.aliyun)
     }
   })
+  it('awsAmplify', () => {
+    const providerOptions = {
+      baseURL: '/'
+    }
+    for (const image of images) {
+      const [src, modifiers] = image.args
+      const generated = awsAmplify.getImage(src, { modifiers, ...providerOptions }, emptyContext)
+      expect(generated).toMatchObject(image.awsAmplify)
+    }
+  })
   it('cloudflare', () => {
     const providerOptions = {
       baseURL: '/'