From c0de6d8c552e8c20dba1ab1e9eefb5baace3511b Mon Sep 17 00:00:00 2001 From: Michael Law <1365977+lawmicha@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:18:24 -0400 Subject: [PATCH 01/48] Update versions.ts Android Amplify V2.19.1 (#7767) --- src/constants/versions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/versions.ts b/src/constants/versions.ts index 1668ae0a280..70b7f83baf0 100644 --- a/src/constants/versions.ts +++ b/src/constants/versions.ts @@ -1,5 +1,5 @@ export const versions = { - ANDROID_VERSION: '2.19.0', + ANDROID_VERSION: '2.19.1', ANDROID_DEVPREVIEW: '1.36.5-dev-preview.0', ANDROID_V1_VERSION: '1.38.8', ANDROID_V1_GEO_VERSION: '1.0.1', From f6eb7bc446cf33f29efe5a48b6d45e76f9f7698f Mon Sep 17 00:00:00 2001 From: Jordan Nelson Date: Fri, 21 Jun 2024 12:31:32 -0400 Subject: [PATCH 02/48] chore(flutter): update android section of Amplify Flutter getting started guide (#7760) * chore: update android section of Flutter getting started guide * chore: update gen 2 flutter platform setup * chore: add info to enable network permissions on android * chore: update H3 headers to H2 * chore: update min Xcode version to 15 * chore: update xcode verison to 15.0 for macOS * chore: update ios and macos setup to be consistent with Android, add callout for missing podfile --- cspell.json | 1 + .../flutter/getting-started/20_installLib.mdx | 4 +- .../flutter/platform-setup/android.mdx | 97 +++++--- .../flutter/platform-setup/ios.mdx | 2 +- .../flutter/platform-setup/macos.mdx | 2 +- .../[platform]/start/platform-setup/index.mdx | 223 ++++++++++++++++-- 6 files changed, 274 insertions(+), 55 deletions(-) diff --git a/cspell.json b/cspell.json index 7627a76a2b7..2e5736a237e 100644 --- a/cspell.json +++ b/cspell.json @@ -532,6 +532,7 @@ "Didfinishlaunchingwithoptions", "displayMode", "displayOrder", + "dists", "DocSet", "DocSets", "Donef", diff --git a/src/fragments/lib/datastore/flutter/getting-started/20_installLib.mdx b/src/fragments/lib/datastore/flutter/getting-started/20_installLib.mdx index e10d4d2f91d..c9767d981dd 100644 --- a/src/fragments/lib/datastore/flutter/getting-started/20_installLib.mdx +++ b/src/fragments/lib/datastore/flutter/getting-started/20_installLib.mdx @@ -20,8 +20,8 @@ compileOptions { // add this line to support Java8 features coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } ``` diff --git a/src/fragments/lib/project-setup/flutter/platform-setup/android.mdx b/src/fragments/lib/project-setup/flutter/platform-setup/android.mdx index 9f00442753b..6bf26008f56 100644 --- a/src/fragments/lib/project-setup/flutter/platform-setup/android.mdx +++ b/src/fragments/lib/project-setup/flutter/platform-setup/android.mdx @@ -1,48 +1,81 @@ -Amplify requires a minimum of API level 24 (Android 7.0), Gradle 7 and Kotlin > 1.9 when targeting Android. +Amplify Flutter supports API level 24+ (Android 7.0+), and requires Gradle 8+, Kotlin 1.9+, and Java 17+ when targeting Android. Follow the steps below to apply these changes in your app. -_If your Flutter app was generated with Flutter 3.16 or lower, please follow the migration guide [here](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply)._ + +The steps below are intended for Flutter apps created with Flutter version 3.16+. If your app was created prior to version 3.16, please follow the guide [here](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply) to migrate to Gradle's declarative plugins block before following the steps below. + -From your project root, navigate to the `android/` directory and open `settings.gradle` in the text editor of your choice. Update the Gradle plugin version to 7.4.2 or higher: +1. Open `android/settings.gradle` and update the Android Gradle plugin and kotlin versions: -```diff - plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" -- id "com.android.application" version "7.3.0" apply false -+ id "com.android.application" version "7.4.2" apply false - id "org.jetbrains.kotlin.android" version "1.9.10" apply false - } +```diff title="android/settings.gradle" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" +- id "com.android.application" version "7.3.0" apply false +- id "org.jetbrains.kotlin.android" version "1.7.10" apply false ++ id "com.android.application" version "8.1.0" apply false ++ id "org.jetbrains.kotlin.android" version "1.9.10" apply false +} ``` -Go to the `android/` directory and open `settings.gradle`. Update the Kotlin plugin version to 1.9.10 or higher: - -```diff - plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false -- id "org.jetbrains.kotlin.android" version "1.7.10" apply false -+ id "org.jetbrains.kotlin.android" version "1.9.10" apply false - } -``` +2. Open `android/gradle/wrapper/gradle-wrapper.properties` and update the Gradle `distributionUrl`. -Then, open `android/gradle/wrapper/gradle-wrapper.properties`. Update the Gradle `distributionUrl` to a version between 7.3 and 7.6.1 (see the [Flutter docs](https://docs.flutter.dev/release/breaking-changes/android-java-gradle-migration-guide) for more info). - -```diff +```diff title="android/gradle/wrapper/gradle-wrapper.properties" +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip -+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip ++distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip ``` -Then, open `android/app/build.gradle`. Update the minimum Android SDK version to 24 or higher: +3. Open `android/app/build.gradle` and update the Java version and minimum Android SDK version. + +```diff title="android/app/build.gradle" +android { + namespace = "com.example.myapp" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + compileOptions { +- sourceCompatibility = JavaVersion.VERSION_1_8 +- targetCompatibility = JavaVersion.VERSION_1_8 ++ sourceCompatibility = JavaVersion.VERSION_17 ++ targetCompatibility = JavaVersion.VERSION_17 + } -```diff defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.myapp" + applicationId = "com.example.myapp" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. -- minSdkVersion flutter.minSdkVersion -+ minSdkVersion 24 - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName +- minSdk = flutter.minSdkVersion ++ minSdk = 24 + targetSdk = flutter.targetSdkVersion + versionCode = flutterVersionCode.toInteger() + versionName = flutterVersionName } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.debug + } + } +} +``` + + +If you would like to use a higher version of Gradle or Android Gradle plugin see the compatibility matrix [here](https://developer.android.com/build/releases/gradle-plugin#updating-gradle). + + +### Network Permissions for Release Builds + +Flutter apps have access to make network requests by default in debug mode. This permission needs to be added when building in release mode. To do this, open `android/app/src/main/AndroidManifest.xml` and make the following addition. + +```xml title="android/app/src/main/AndroidManifest.xml" + +// highlight-start + +// highlight-end +... + ``` diff --git a/src/fragments/lib/project-setup/flutter/platform-setup/ios.mdx b/src/fragments/lib/project-setup/flutter/platform-setup/ios.mdx index 3d8c79becf4..4a05745764c 100644 --- a/src/fragments/lib/project-setup/flutter/platform-setup/ios.mdx +++ b/src/fragments/lib/project-setup/flutter/platform-setup/ios.mdx @@ -1,4 +1,4 @@ -Amplify requires a minimum deployment target of 13.0 and Xcode 13.2 or higher when targeting iOS. +Amplify requires a minimum deployment target of 13.0 and Xcode 15.0 or higher when targeting iOS. From your project root, navigate to the `ios/` directory and open the `Podfile` in a text editor of your choice. At the top of the file, update the target iOS platform to 13.0 or higher. diff --git a/src/fragments/lib/project-setup/flutter/platform-setup/macos.mdx b/src/fragments/lib/project-setup/flutter/platform-setup/macos.mdx index 2e02deac857..12399795561 100644 --- a/src/fragments/lib/project-setup/flutter/platform-setup/macos.mdx +++ b/src/fragments/lib/project-setup/flutter/platform-setup/macos.mdx @@ -1,4 +1,4 @@ -Amplify requires a minimum deployment target of 10.15 and Xcode 13.2 or higher when targeting macOS. Additionally, you will need to enable networking, keychain entitlements, and code signing. +Amplify requires a minimum deployment target of 10.15 and Xcode 15.0 or higher when targeting macOS. Additionally, you will need to enable networking, keychain entitlements, and code signing. ### Update Minimum Version diff --git a/src/pages/[platform]/start/platform-setup/index.mdx b/src/pages/[platform]/start/platform-setup/index.mdx index 09987d6b6dd..02be15665bf 100644 --- a/src/pages/[platform]/start/platform-setup/index.mdx +++ b/src/pages/[platform]/start/platform-setup/index.mdx @@ -22,38 +22,223 @@ export function getStaticProps(context) { } -### iOS -From your project root, navigate to the `ios/` directory and modify the `Podfile` using a text editor of your choice and update the target iOS platform to 11.0 or higher. +## iOS -```bash -platform :ios, '11.0' +Amplify requires a minimum deployment target of 13.0 and Xcode 15.0 or higher when targeting iOS. Follow the steps below to update the minimum deployment target. + +Open `ios/Podfile` and update the target iOS platform to 13.0 or higher. + + +If there is no file located at `ios/Podfile`, add `amplify_flutter` to your `pubspec.yaml` and run `pub get`. This will automatically create the file. + + +```diff title="ios/Podfile" +- # Uncomment this line to define a global platform for your project +- # platform :ios, '12.0' ++ platform :ios, '13.0' ``` - +Open your project in Xcode and select Runner, Targets -> Runner and then the "General" tab. Under the "Minimum Deployments" section, update the iOS version to 13.0 or higher. + +![Setting the iOS version to 13.0 or higher in the minimum deployments section of the Runner general window.](/images/project-setup/flutter/ios/target-min-deployment-version.png) -When preparing your application for deployment, you should also update your iOS Deployment Target to at least 11.0. See the [Flutter docs](https://docs.flutter.dev/deployment/ios) to learn more about building your iOS app for release. +Select Runner, Project -> Runner and then the "Info" tab. Update "iOS Deployment Target" to 13.0 or higher. +![Setting the iOS version to 13.0 or higher in the deployment targets section of the Runner info window.](/images/project-setup/flutter/ios/project-min-deployment-version.png) + +## Android + +Amplify Flutter supports API level 24+ (Android 7.0+), and requires Gradle 8+, Kotlin 1.9+, and Java 17+ when targeting Android. Follow the steps below to apply these changes in your app. + + +The steps below are intended for Flutter apps created with Flutter version 3.16+. If your app was created prior to version 3.16, please follow the guide [here](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply) to migrate to Gradle's declarative plugins block before following the steps below. -### Android -From your project root, navigate to the `android/app/` directory and modify `build.gradle` using a text editor of your choice and update the target Android SDK version to 21 or higher: +1. Open `android/settings.gradle` and update the Android Gradle plugin and kotlin versions: -```bash -minSdkVersion 21 +```diff title="android/settings.gradle" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" +- id "com.android.application" version "7.3.0" apply false +- id "org.jetbrains.kotlin.android" version "1.7.10" apply false ++ id "com.android.application" version "8.1.0" apply false ++ id "org.jetbrains.kotlin.android" version "1.9.10" apply false +} ``` - +2. Open `android/gradle/wrapper/gradle-wrapper.properties` and update the Gradle `distributionUrl`. -If you are using Flutter 2.10 or above, you will need to ensure that your app supports an [up-to-date Kotlin version](https://docs.flutter.dev/release/breaking-changes/kotlin-version). -This will typically be version 1.5.31 or higher. -
-You can do this by updating the Kotlin version in your app's `android/build.gradle` file: +```diff title="android/gradle/wrapper/gradle-wrapper.properties" +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip ++distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +``` -```yaml -buildscript { - ext.kotlin_version = '1.5.31' - ... +3. Open `android/app/build.gradle` and update the Java version and minimum Android SDK version. + +```diff title="android/app/build.gradle" +android { + namespace = "com.example.myapp" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + compileOptions { +- sourceCompatibility = JavaVersion.VERSION_1_8 +- targetCompatibility = JavaVersion.VERSION_1_8 ++ sourceCompatibility = JavaVersion.VERSION_17 ++ targetCompatibility = JavaVersion.VERSION_17 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.myapp" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. +- minSdk = flutter.minSdkVersion ++ minSdk = 24 + targetSdk = flutter.targetSdkVersion + versionCode = flutterVersionCode.toInteger() + versionName = flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.debug + } + } } ``` + +If you would like to use a higher version of Gradle or Android Gradle plugin see the compatibility matrix [here](https://developer.android.com/build/releases/gradle-plugin#updating-gradle). + + +### Network Permissions for Release Builds + +Flutter apps have access to make network requests by default in debug mode. This permission needs to be added when building in release mode. To do this, open `android/app/src/main/AndroidManifest.xml` and make the following addition. + +```xml title="android/app/src/main/AndroidManifest.xml" + +// highlight-start + +// highlight-end +... + +``` + +## Web + +There are no Amplify specific requirements or setup instructions when targeting web. You will need to use a browser supported by Flutter. See the following Flutter docs for more info: + +- [Supported deployment platforms](https://docs.flutter.dev/reference/supported-platforms) +- [FAQ: Which web browsers are supported by Flutter?](https://docs.flutter.dev/development/platform-integration/web/faq#which-web-browsers-are-supported-by-flutter) + +## macOS + +Amplify requires a minimum deployment target of 10.15 and Xcode 15.0 or higher when targeting macOS. Additionally, you will need to enable networking, keychain entitlements, and code signing. + +### Update Minimum Version + +Open `macos/Podfile` and update the target macOS platform to 10.15 or higher. + + +If there is no file located at `macos/Podfile`, add `amplify_flutter` to your `pubspec.yaml` and run `pub get`. This will automatically create the file. + +```diff title="ios/Podfile" +- platform :osx, '10.14' ++ platform :osx, '10.15' +``` + +Open your project in Xcode and select Runner, Targets -> Runner and then the "General" tab. Under the "Minimum Deployments" section, update the macOS version to 10.15 or higher. + +![Setting the macOS version to 10.15 or higher in the Minimum Deployments tab of the Runner general section.](/images/project-setup/flutter/mac/target-min-deployment-version.png) + +Select Runner, Project -> Runner and then the "Info" tab. Update "macOS Deployment Target" to 10.15 or higher. + +![Setting the macOS version to 10.15 or higher in the macOS Deployment Target tab of the Runner info section.](/images/project-setup/flutter/mac/project-min-deployment-version.png) + +### Enable Network Calls + +Open your project in Xcode and select Runner, Targets -> Runner and then the "Signing and Capabilities" tab. Under "App Sandbox" select "Outgoing Connections (Client)". + +![Selecting outgoing connections in the app sandbox section of the runner signing and capabilities tab.](/images/project-setup/flutter/mac/xcode-entitlements.png) + +For more info on the Networking entitlement, see Apple's documentation on [com.apple.security.network.client](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_network_client). + +### Enable Keychain Sharing + + + +This capability is required because Amplify uses the Data Protection Keychain on macOS as a platform best practice. +See [TN3137: macOS keychain APIs and implementations](https://developer.apple.com/documentation/technotes/tn3137-on-mac-keychains) +for more information on how Keychain works on macOS and the Keychain Sharing entitlement. + + + +Open your project in Xcode and select Runner, Targets -> Runner and then the "Signing and Capabilities" tab. + +1. Click the "+ icon". + +![Plus icon circled in the signing and capabilities section of the runner tab.](/images/project-setup/flutter/mac/enable-keychain-access.png) + +2. Search for "Keychain Sharing" in the subsequent modal, and add it. + +![Keychain Sharing search result after searching keychain.](/images/project-setup/flutter/mac/search-keychain-sharing.png) + +3. Scroll down to "Keychain Sharing" in the "Signing and Capabilities" and click the "+" icon. By default, your bundle ID will be used. + +![Plus icon highlighted in the keychain sharing section of the signing and capabilities section of runner.](/images/project-setup/flutter/mac/adding-keychain-access-group.png) + +4. Finally, add a development team and enable signing. + +![Team selector and Enable Development Signing button highlighted in the signing and capabilities section of the runner tab.](/images/project-setup/flutter/mac/enable-signing.png) + + +## Windows + +There are no Amplify specific requirements or setup instructions when targeting Windows. You will need to use a Windows version supported by Flutter. See the following Flutter docs for more info: + +- [Supported deployment platforms](https://docs.flutter.dev/reference/supported-platforms) + +## Linux + +Amplify Flutter depends on the [libsecret](https://wiki.gnome.org/Projects/Libsecret) library when targeting Linux. + +### Local Development + +To run and debug an app that depends on Amplify Flutter, you must install `libsecret-1-dev`. Run the following commands to install `libsecret-1-dev`. this will also install dependencies of `libsecret-1-dev`, such as `libglib2.0-dev`. + + + The command below is intended for Ubuntu. The command may vary on other Linux distributions. + + +{/* cSpell:disable */} + +```terminal +sudo apt-get update +sudo apt-get install -y libsecret-1-dev +``` + +{/* cSpell:enable */} + +### Packaging Your App + +To include the required dependencies when packaging your app with Snapcraft, include them in your `snapcraft.yaml` file. For more info, see [Flutter's documentation on releasing to the Snap Store](https://docs.flutter.dev/deployment/linux). + +```yaml +parts: + my-app: + plugin: flutter + source: . + flutter-target: lib/main.dart + build-packages: + - libsecret-1-dev + stage-packages: + - libsecret-1-0 +``` + From f75809ddad1b869ee5936ee3620ac6286fbca09c Mon Sep 17 00:00:00 2001 From: josef Date: Mon, 24 Jun 2024 13:13:53 -0500 Subject: [PATCH 03/48] update mobile quickstarts with link to fullstack branch deployment guide #7741 (#7746) --- src/pages/[platform]/start/quickstart/index.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/[platform]/start/quickstart/index.mdx b/src/pages/[platform]/start/quickstart/index.mdx index 9a41210aeff..84692d6cfad 100644 --- a/src/pages/[platform]/start/quickstart/index.mdx +++ b/src/pages/[platform]/start/quickstart/index.mdx @@ -1680,7 +1680,7 @@ You can terminate the sandbox environment now to clean up the project. ### Publishing changes to cloud -For publishing the changes to cloud, you need to create a remote git repository. For a detailed guide, you can follow the link [here](/[platform]/deploy-and-host/fullstack-branching/branch-deployments). +Publishing changes to the cloud requires a remote git repository. Amplify offers fullstack branch deployments that allow you to automatically deploy infrastructure and application code changes from feature branches. To learn more, visit the [fullstack branch deployments guide](/[platform]/deploy-and-host/fullstack-branching/branch-deployments). @@ -2128,7 +2128,7 @@ You can terminate the sandbox environment now to clean up the project. ## Publishing changes to cloud -For publishing the changes to cloud, you need to create a remote git repository. For a detailed guide, you can follow the link [here](/[platform]/start/quickstart/#create-remote-git-repository). +Publishing changes to the cloud requires a remote git repository. Amplify offers fullstack branch deployments that allow you to automatically deploy infrastructure and application code changes from feature branches. To learn more, visit the [fullstack branch deployments guide](/[platform]/deploy-and-host/fullstack-branching/branch-deployments). @@ -2925,7 +2925,7 @@ You can terminate the sandbox environment now to clean up the project. ### Publishing changes to cloud -For publishing the changes to cloud, you need to create a remote git repository. For a detailed guide, you can follow the link [here](/[platform]/start/quickstart/#publishing-changes-to-cloud). +Publishing changes to the cloud requires a remote git repository. Amplify offers fullstack branch deployments that allow you to automatically deploy infrastructure and application code changes from feature branches. To learn more, visit the [fullstack branch deployments guide](/[platform]/deploy-and-host/fullstack-branching/branch-deployments). From ddd3717bccf056ba799eeffff15e2037e966ef6e Mon Sep 17 00:00:00 2001 From: Hui Zhao <10602282+HuiSF@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:07:39 -0700 Subject: [PATCH 04/48] chore: add serverComponentsExternalPackages callout for Next.js (#7757) * chore: add serverComponentsExternalPackages callout for Next.js * Apply suggestions from code review Co-authored-by: Jim Blanchard * Apply suggestions from code review * Update src/pages/gen1/[platform]/build-a-backend/server-side-rendering/nextjs/index.mdx Co-authored-by: Jim Blanchard * Update src/pages/gen1/[platform]/build-a-backend/server-side-rendering/nextjs/index.mdx Co-authored-by: josef * Update src/pages/[platform]/build-a-backend/server-side-rendering/index.mdx Co-authored-by: josef --------- Co-authored-by: Jim Blanchard Co-authored-by: josef --- .../server-side-rendering/index.mdx | 24 +++++++++++++++++++ .../server-side-rendering/nextjs/index.mdx | 24 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/pages/[platform]/build-a-backend/server-side-rendering/index.mdx b/src/pages/[platform]/build-a-backend/server-side-rendering/index.mdx index f364aa2aef0..b9cd7d07acc 100644 --- a/src/pages/[platform]/build-a-backend/server-side-rendering/index.mdx +++ b/src/pages/[platform]/build-a-backend/server-side-rendering/index.mdx @@ -230,6 +230,30 @@ For the **GraphQL API** category, review [Connect to data from Server-side Runti
+ + +**Note:** If you use the Amplify server-side APIs in a [server action](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations) and encounter the following error running `next build`: + +> ./node_modules/@aws-amplify/core/node_modules/@aws-crypto/sha256-js/build/module/index.js + 12 modules + +> Cannot get final name for export 'fromUtf8' of ./node_modules/@smithy/util-utf8/dist-es/index.js + +You can add the following to your `next.config.js`: + +```ts title="next.config.js" +/** @type {import('next').NextConfig} */ +const nextConfig = { + // highlight-start + experimental: { + serverComponentsExternalPackages: ['@aws-crypto'], + }, + // highlight-end +}; +``` + +See Next.js documentation on [`serverComponentsExternalPackages`](https://nextjs.org/docs/app/api-reference/next-config-js/serverComponentsExternalPackages) for more details. + + ### With Next.js App Router #### Dynamic rendering in React server component diff --git a/src/pages/gen1/[platform]/build-a-backend/server-side-rendering/nextjs/index.mdx b/src/pages/gen1/[platform]/build-a-backend/server-side-rendering/nextjs/index.mdx index 55b56b3c3f5..7bf1590334a 100644 --- a/src/pages/gen1/[platform]/build-a-backend/server-side-rendering/nextjs/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/server-side-rendering/nextjs/index.mdx @@ -232,6 +232,30 @@ For the **GraphQL API** category, review [Connect to GraphQL API from server-sid
+ + +**Note:** If you use the Amplify server-side APIs in a [server action](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations) and encounter the following error running `next build`: + +> ./node_modules/@aws-amplify/core/node_modules/@aws-crypto/sha256-js/build/module/index.js + 12 modules + +> Cannot get final name for export 'fromUtf8' of ./node_modules/@smithy/util-utf8/dist-es/index.js + +You can add the following to your `next.config.js`: + +```ts title="next.config.js" +/** @type {import('next').NextConfig} */ +const nextConfig = { + // highlight-start + experimental: { + serverComponentsExternalPackages: ['@aws-crypto'], + }, + // highlight-end +}; +``` + +See Next.js documentation on [`serverComponentsExternalPackages`](https://nextjs.org/docs/app/api-reference/next-config-js/serverComponentsExternalPackages) for more details. + + ### With Next.js App Router #### In React Server Component From 0cee76eeebd43a311055cef61ce03d95ebc69da0 Mon Sep 17 00:00:00 2001 From: josef Date: Mon, 24 Jun 2024 21:42:03 -0500 Subject: [PATCH 05/48] add warning callout to gen1 backend-config (#7773) --- .../gen1/[platform]/tools/cli/reference/files/index.mdx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pages/gen1/[platform]/tools/cli/reference/files/index.mdx b/src/pages/gen1/[platform]/tools/cli/reference/files/index.mdx index 0cc65d302a8..e52427aa18a 100644 --- a/src/pages/gen1/[platform]/tools/cli/reference/files/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli/reference/files/index.mdx @@ -82,7 +82,13 @@ These files work together to maintain the overall state of the Amplify project s > Add to version control: YES -The `backend-config.json` in the `backend` directory contains configuration about your project's backend, such as how connects to AWS resources (eg. Cognito for auth or AppSync for an API backend). Typically, this file is updated by the CLI commands like `amplify add auth` or `amplify add api`. It can also be [extended manually](/gen1/[platform]/tools/cli/custom/cloudformation/) to configure your backend beyond Amplify CLI's features. Both the `amplify/backend` and `amplify/#current-cloud-backend` directories contain a `backend-config.json` file. +The `backend-config.json` in the `backend` directory contains configuration about your project's backend, such as how connects to AWS resources (e.g. Cognito for auth or AppSync for an API backend). Typically, this file is updated by the CLI commands like `amplify add auth` or `amplify add api`. It can also be [extended manually](/gen1/[platform]/tools/cli/custom/cloudformation/) to configure your backend beyond Amplify CLI's features. Both the `amplify/backend` and `amplify/#current-cloud-backend` directories contain a `backend-config.json` file. + + + +**Warning:** this file contains the resource structure of your Amplify backend. Edits to this file can yield unexpected results and have a negative impact on the integrity of your backend. + + ### amplify-meta.json From be293f59b2877d474d520965bf891750a9790ab8 Mon Sep 17 00:00:00 2001 From: Heather Buchel Date: Thu, 27 Jun 2024 14:16:05 -0400 Subject: [PATCH 06/48] Revert "chore: add region to scrollable table (#7744)" (#7784) This reverts commit 67496c5da1702d4338c42299778ff7b963424250. --- src/components/MDXComponents/MDXTable.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/MDXComponents/MDXTable.tsx b/src/components/MDXComponents/MDXTable.tsx index c17e28afa37..31f07b8142f 100644 --- a/src/components/MDXComponents/MDXTable.tsx +++ b/src/components/MDXComponents/MDXTable.tsx @@ -9,7 +9,6 @@ export const MDXTable: React.FC = ({ children, ...props }) => { return ( From 2ee5be366e160928beba4f8a2dedb17d2863b221 Mon Sep 17 00:00:00 2001 From: Kha Truong <64438356+khatruong2009@users.noreply.github.com> Date: Fri, 28 Jun 2024 15:11:01 -0700 Subject: [PATCH 07/48] chore: change outputs to amplifyConfig in flutter gen 2 docs (#7764) * chore: change outputs to amplifyConfig in flutter gen 2 docs * chore: change amplifyconfiguration.dart import to amplify_outputs.dart * chore: remove --outputs-version 0 and downgrade config file callout * chore: remove --outputs-version 0 from snippets * chore: remove gen 2 config conversion callout * chore: remove amplifyconfiguration.dart references from gen 2 --- .../analytics/record-events/index.mdx | 2 +- .../analytics/set-up-analytics/index.mdx | 12 ++++++------ .../build-a-backend/auth/set-up-auth/index.mdx | 10 ++-------- .../build-a-backend/data/set-up-data/index.mdx | 4 ++-- .../build-a-backend/storage/set-up-storage/index.mdx | 4 ++-- .../storage/use-with-custom-s3/index.mdx | 4 ++-- .../[platform]/reference/cli-commands/index.mdx | 2 +- src/pages/[platform]/start/quickstart/index.mdx | 9 ++------- 8 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx index 3c7017249f0..cb02018a996 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx @@ -305,7 +305,7 @@ However, it can take upwards of 30 minutes for the event to display in the Filte ## Flush events -Events have default configuration to flush out to the network every 30 seconds. If you would like to change this, update `amplifyconfiguration.dart` with the value in milliseconds you would like for `autoFlushEventsInterval`. This configuration will flush events every 10 seconds: +Events have default configuration to flush out to the network every 30 seconds. If you would like to change this, update `amplify_outputs.dart` with the value in milliseconds you would like for `autoFlushEventsInterval`. This configuration will flush events every 10 seconds: ```json { diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx index 6c4d61a2d6f..34d70a829c4 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx @@ -300,7 +300,7 @@ import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:flutter/material.dart'; -import 'amplifyconfiguration.dart'; +import 'amplify_outputs.dart'; Future _configureAmplify() async { // Add Pinpoint and Cognito Plugins, and any other plugins you want to use @@ -316,7 +316,7 @@ When running your app on macOS you will need to enable keychain sharing in Xcode -Make sure that the amplifyconfiguration.dart file generated in the project setup is included and sent to Amplify.configure: +Make sure that the amplify_outputs.dart file generated in the project setup is included and sent to Amplify.configure: ```dart import 'package:amplify_analytics_pinpoint/amplify_analytics_pinpoint.dart'; @@ -324,7 +324,7 @@ import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:flutter/material.dart'; -import 'amplifyconfiguration.dart'; +import 'amplify_outputs.dart'; Future _configureAmplify() async { // ... @@ -333,7 +333,7 @@ Future _configureAmplify() async { // Once Plugins are added, configure Amplify // Note: Amplify can only be configured once. try { - await Amplify.configure(outputs); + await Amplify.configure(amplifyConfig); } on AmplifyAlreadyConfiguredException { safePrint( 'Tried to reconfigure Amplify; this can occur when your app restarts on Android.', @@ -350,7 +350,7 @@ import 'package:amplify_analytics_pinpoint/amplify_analytics_pinpoint.dart'; import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; import 'package:flutter/material.dart'; -import 'amplifyconfiguration.dart'; +import 'amplify_outputs.dart'; Future _configureAmplify() async { // Add any Amplify plugins you want to use @@ -361,7 +361,7 @@ Future _configureAmplify() async { // Once Plugins are added, configure Amplify // Note: Amplify can only be configured once. try { - await Amplify.configure(outputs); + await Amplify.configure(amplifyConfig); } on AmplifyAlreadyConfiguredException { safePrint( 'Tried to reconfigure Amplify; this can occur when your app restarts on Android.', diff --git a/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx b/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx index 211b0e429ab..1903fe1750c 100644 --- a/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx @@ -69,15 +69,9 @@ npx ampx sandbox ```bash title="Terminal" showLineNumbers={false} -npx ampx sandbox --outputs-format dart --outputs-out-dir lib --outputs-version 0 +npx ampx sandbox --outputs-format dart --outputs-out-dir lib ``` - - -**Note:** when using Amplify Gen 2 with Flutter, you must downgrade the generated client configuration file (`amplify_outputs.dart`) with [`--outputs-version 0`](/[platform]/reference/cli-commands/#npx-ampx-generate-outputs) - - - @@ -394,7 +388,7 @@ import 'package:amplify_authenticator/amplify_authenticator.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:flutter/material.dart'; -import 'amplifyconfiguration.dart'; +import 'amplify_outputs.dart'; Future main() async { try { diff --git a/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx b/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx index f6f9f6b08bd..1183a641169 100644 --- a/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx @@ -332,7 +332,7 @@ import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:flutter/material.dart'; // highlight-start -import 'amplifyconfiguration.dart'; +import 'amplify_outputs.dart'; import 'models/ModelProvider.dart'; // highlight-end @@ -345,7 +345,7 @@ Future main() async { ) ); await Amplify.addPlugins([api]); - await Amplify.configure(outputs); + await Amplify.configure(amplifyConfig); safePrint('Successfully configured Amplify'); } on Exception catch (e) { diff --git a/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx b/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx index ebb27227d3b..0918ea16bbe 100644 --- a/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx +++ b/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx @@ -446,7 +446,7 @@ import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:amplify_storage_s3/amplify_storage_s3.dart'; import 'package:flutter/material.dart'; -import 'amplifyconfiguration.dart'; +import 'amplify_outputs.dart'; Future _configureAmplify() async { try { @@ -455,7 +455,7 @@ Future _configureAmplify() async { await Amplify.addPlugins([auth, storage]); // call Amplify.configure to use the initialized categories in your app - await Amplify.configure(outputs); + await Amplify.configure(amplifyConfig); } on Exception catch (e) { safePrint('An error occurred configuring Amplify: $e'); } diff --git a/src/pages/[platform]/build-a-backend/storage/use-with-custom-s3/index.mdx b/src/pages/[platform]/build-a-backend/storage/use-with-custom-s3/index.mdx index fdfa9ee9621..0df45abfa00 100644 --- a/src/pages/[platform]/build-a-backend/storage/use-with-custom-s3/index.mdx +++ b/src/pages/[platform]/build-a-backend/storage/use-with-custom-s3/index.mdx @@ -120,9 +120,9 @@ To ensure the local **amplify_outputs.json** file is up-to-date, you can run [th -## Step 3 - Import latest amplifyconfiguration.dart file +## Step 3 - Import latest amplify_outputs.dart file -To ensure the local **amplifyconfiguration.dart** file is up-to-date, you can run [the npx ampx generate outputs command](/[platform]/reference/cli-commands/#npx-ampx-generate-outputs). +To ensure the local **amplify_outputs.dart** file is up-to-date, you can run [the npx ampx generate outputs command](/[platform]/reference/cli-commands/#npx-ampx-generate-outputs). diff --git a/src/pages/[platform]/reference/cli-commands/index.mdx b/src/pages/[platform]/reference/cli-commands/index.mdx index 4e2c576c09a..216be33f4e5 100644 --- a/src/pages/[platform]/reference/cli-commands/index.mdx +++ b/src/pages/[platform]/reference/cli-commands/index.mdx @@ -101,7 +101,7 @@ npx ampx sandbox ```bash title="Terminal" showLineNumbers={false} # for Flutter -npx ampx sandbox --outputs-format dart --outputs-out-dir lib --outputs-version 0 +npx ampx sandbox --outputs-format dart --outputs-out-dir lib ``` ## npx ampx sandbox delete diff --git a/src/pages/[platform]/start/quickstart/index.mdx b/src/pages/[platform]/start/quickstart/index.mdx index 84692d6cfad..1cdb47c3fee 100644 --- a/src/pages/[platform]/start/quickstart/index.mdx +++ b/src/pages/[platform]/start/quickstart/index.mdx @@ -1313,14 +1313,9 @@ npx ampx sandbox ```bash title="Terminal" showLineNumbers={false} -npx ampx sandbox --outputs-format dart --outputs-out-dir lib --outputs-version 0 +npx ampx sandbox --outputs-format dart --outputs-out-dir lib ``` - - -**Note:** when using Amplify Gen 2 with Flutter, you must downgrade the generated client configuration file (`amplify_outputs.dart`) with [`--outputs-version 0`](/[platform]/reference/cli-commands/#npx-ampx-generate-outputs) - - ## Adding Authentication @@ -1358,7 +1353,7 @@ import 'package:amplify_authenticator/amplify_authenticator.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; import 'package:flutter/material.dart'; -import 'amplifyconfiguration.dart'; +import 'amplify_outputs.dart'; Future main() async { try { From a6409040b22da4ee16279e4ee72af222f0c9cb94 Mon Sep 17 00:00:00 2001 From: Heather Buchel Date: Mon, 1 Jul 2024 11:49:53 -0400 Subject: [PATCH 08/48] fix: heading order on gen1/prev subscribe-data page (#7790) --- src/fragments/lib-v1/graphqlapi/flutter/subscribe-data.mdx | 2 +- src/fragments/lib-v1/graphqlapi/ios/subscribe-data.mdx | 6 +++--- src/fragments/lib/graphqlapi/flutter/subscribe-data.mdx | 2 +- src/fragments/lib/graphqlapi/ios/subscribe-data.mdx | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/fragments/lib-v1/graphqlapi/flutter/subscribe-data.mdx b/src/fragments/lib-v1/graphqlapi/flutter/subscribe-data.mdx index 11ced1c1351..45a12cf4a24 100644 --- a/src/fragments/lib-v1/graphqlapi/flutter/subscribe-data.mdx +++ b/src/fragments/lib-v1/graphqlapi/flutter/subscribe-data.mdx @@ -76,7 +76,7 @@ Amplify.Hub.listen( ); ``` -#### SubscriptionStatus +### SubscriptionStatus - **`connected`** - Connected and working with no issues - **`connecting`** - Attempting to connect (both initial connection and reconnection) diff --git a/src/fragments/lib-v1/graphqlapi/ios/subscribe-data.mdx b/src/fragments/lib-v1/graphqlapi/ios/subscribe-data.mdx index c4f51356633..c446e8c3e54 100644 --- a/src/fragments/lib-v1/graphqlapi/ios/subscribe-data.mdx +++ b/src/fragments/lib-v1/graphqlapi/ios/subscribe-data.mdx @@ -82,9 +82,9 @@ func createSubscription() { -### Unsubscribing from updates +## Unsubscribing from updates -#### Listener (iOS 11+) +### Listener (iOS 11+) To unsubscribe from updates, you can call `cancel()` on the subscription @@ -95,7 +95,7 @@ func cancelSubscription() { } ``` -#### Combine (iOS 13+) +### Combine (iOS 13+) With the Combine flavor of the `subscribe()` API, you have the option of canceling just the downstream Combine subscriber, or the entire GraphQL subscription. diff --git a/src/fragments/lib/graphqlapi/flutter/subscribe-data.mdx b/src/fragments/lib/graphqlapi/flutter/subscribe-data.mdx index 94f62434e52..a27c521b8ff 100644 --- a/src/fragments/lib/graphqlapi/flutter/subscribe-data.mdx +++ b/src/fragments/lib/graphqlapi/flutter/subscribe-data.mdx @@ -76,7 +76,7 @@ Amplify.Hub.listen( ); ``` -#### SubscriptionStatus +### SubscriptionStatus - **`connected`** - Connected and working with no issues - **`connecting`** - Attempting to connect (both initial connection and reconnection) diff --git a/src/fragments/lib/graphqlapi/ios/subscribe-data.mdx b/src/fragments/lib/graphqlapi/ios/subscribe-data.mdx index 8aed3a7d48a..72008794ea5 100644 --- a/src/fragments/lib/graphqlapi/ios/subscribe-data.mdx +++ b/src/fragments/lib/graphqlapi/ios/subscribe-data.mdx @@ -87,9 +87,9 @@ func createSubscription() { -### Unsubscribing from updates +## Unsubscribing from updates -#### Async/Await +### Async/Await To unsubscribe from updates, you can call `cancel()` on the subscription. @@ -100,7 +100,7 @@ func cancelSubscription() { } ``` -#### Combine +### Combine Calling `cancel()` on the sequence will disconnect the subscription from the backend. Any downstream subscribers will also be cancelled. From 9e79e978f377a0e7ce4b7badd6baed3008bfc5e0 Mon Sep 17 00:00:00 2001 From: Chris Bonifacio Date: Mon, 1 Jul 2024 13:40:04 -0400 Subject: [PATCH 09/48] add warning regarding subscription and mutation redaction of relational fields (#7768) * add warning regarding subscription and mutation redaction of relational fields * replace authn with authz in warning * chore(api): Callout for field redaction on Swift Android relational models * Update src/pages/gen1/[platform]/build-a-backend/graphqlapi/relational-models/index.mdx * add feature flag to warning for gen 1 * Fix heading order in fragments affecting this page * add protected redaction message components * Add tests for redaction message Gen 1 and Gen 2 components * add snapshots for redaction Gen 1 and Gen 2 component tests * Adds ProtectedRedactionMessage components for Gen 1 and Gen2 * Render ProtectedRedactionGen1Message component on Gen 1 realtime page * Render ProtectedRedactionGen1Message component on Gen 2 data modeling page * Render ProtectedRedactionGen2Message component on Gen 2 realtime page * Render ProtectedRedactionGen1Message component on Gen 1 data modeling page * Render ProtectedRedactionGen1Message component on Gen 1 V5 realtime page * add subscriptionsInheritPrimaryAuth as a feature flag * correct version for subscriptionsInheritPrimaryAuth * remove commented code * fix heading order --------- Co-authored-by: Michael Law <1365977+lawmicha@users.noreply.github.com> Co-authored-by: Heather Co-authored-by: katiegoines --- .../FeatureFlags/feature-flags.json | 20 +++ .../data-modeling/relationships/index.mdx | 8 +- .../data/subscribe-data/index.mdx | 6 + .../graphqlapi/data-modeling/index.mdx | 12 +- .../graphqlapi/relational-models/index.mdx | 24 +++ .../graphqlapi/subscribe-data/index.mdx | 6 + .../graphqlapi/subscribe-data/index.mdx | 6 + .../ProtectedRedactionMessage.test.tsx | 81 +++++++++++ .../ProtectedRedactionMessage.test.tsx.snap | 137 ++++++++++++++++++ .../ProtectedRedactionMessage/index.tsx | 84 +++++++++++ 10 files changed, 380 insertions(+), 4 deletions(-) create mode 100644 src/protected/ProtectedRedactionMessage/__tests__/ProtectedRedactionMessage.test.tsx create mode 100644 src/protected/ProtectedRedactionMessage/__tests__/__snapshots__/ProtectedRedactionMessage.test.tsx.snap create mode 100644 src/protected/ProtectedRedactionMessage/index.tsx diff --git a/src/components/FeatureFlags/feature-flags.json b/src/components/FeatureFlags/feature-flags.json index a2e95d99bf9..73f774d3b88 100644 --- a/src/components/FeatureFlags/feature-flags.json +++ b/src/components/FeatureFlags/feature-flags.json @@ -371,6 +371,26 @@ "defaultExistingProject": false } ] + }, + "subscriptionsInheritPrimaryAuth": { + "description": "Toggles whether subscriptions will inherit related authorization when relational fields are set as required", + "type": "Feature", + "valueType": "Boolean", + "versionAdded": "12.12.4", + "values": [ + { + "value": "true", + "description": "Subscriptions will inherit the primary model authorization rules for the relational fields", + "defaultNewProject": false, + "defaultExistingProject": true + }, + { + "value": "false", + "description": "Relational fields will be redacted in mutation response when there is a difference between auth rules between primary and related models.", + "defaultNewProject": true, + "defaultExistingProject": false + } + ] } } }, diff --git a/src/pages/[platform]/build-a-backend/data/data-modeling/relationships/index.mdx b/src/pages/[platform]/build-a-backend/data/data-modeling/relationships/index.mdx index 5a36e4a1ba1..e7d030c32fd 100644 --- a/src/pages/[platform]/build-a-backend/data/data-modeling/relationships/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/data-modeling/relationships/index.mdx @@ -24,7 +24,7 @@ export const getStaticPaths = async () => { export function getStaticProps(context) { return { props: { - + meta } }; @@ -32,6 +32,12 @@ export function getStaticProps(context) { When modeling application data, you often need to establish relationships between different data models. In Amplify Data, you can create one-to-many, one-to-one, and many-to-many relationships in your Data schema. On the client-side, Amplify Data allows you to lazy or eager load of related data. +{/* This component contains approved messaging and cannot be removed or modified without prior approval */} + +import { ProtectedRedactionGen2Message } from "@/protected/ProtectedRedactionMessage" + + + ## Types of relationships |Relationship|Code|Description|Example| diff --git a/src/pages/[platform]/build-a-backend/data/subscribe-data/index.mdx b/src/pages/[platform]/build-a-backend/data/subscribe-data/index.mdx index 93591efd0da..58894b78cb0 100644 --- a/src/pages/[platform]/build-a-backend/data/subscribe-data/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/subscribe-data/index.mdx @@ -38,6 +38,12 @@ Before you begin, you will need: - An [application connected to the API](/[platform]/build-a-backend/data/connect-to-API/) - Data already created to modify +{/* This component contains approved messaging and cannot be removed or modified without prior approval */} + +import { ProtectedRedactionGen2Message } from "@/protected/ProtectedRedactionMessage" + + + ## Set up a real-time list query The recommended way to fetch a list of data is to use `observeQuery` to get a real-time list of your app data at all times. You can integrate `observeQuery` with React's `useState` and `useEffect` hooks in the following way: diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx index eea49006a3d..59c389676cb 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx @@ -292,6 +292,12 @@ Create "has one", "has many", "belongs to", and "many to many" relationships bet | `@belongsTo` | Use a "belongs to" relationship to make a "has one" or "has many" relationship bi-directional. For example, a Project has one Team and a Team belongs to a Project. This allows you to query the team from the project record and vice versa. | | `@manyToMany` | Configures a "join table" between two models to facilitate a many-to-many relationship. For example, a Blog has many Tags and a Tag has many Blogs. | +{/* This component contains approved messaging and cannot be removed or modified without prior approval */} + +import { ProtectedRedactionGen1Message } from "@/protected/ProtectedRedactionMessage" + + + ### Has One relationship import gqlv2callout from '/src/fragments/cli/gqlv2callout.mdx'; @@ -794,11 +800,11 @@ You can use the `@default` directive to specify a default value for optional [sc ```graphql type Todo @model { content: String @default(value: "My new Todo") - # Note: all "value" parameters must be passed as a string value. + # Note: all "value" parameters must be passed as a string value. # Under the hood, Amplify will parse the string values into respective types. - # For example, to set a default value for an integer field, + # For example, to set a default value for an integer field, # you must pass in `"0"` instead of `0` without the double-quotes. - likes: Int @default(value: "0") # + likes: Int @default(value: "0") # } ``` diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/relational-models/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/relational-models/index.mdx index 59813b96137..ed7851b5522 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/relational-models/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/relational-models/index.mdx @@ -29,6 +29,30 @@ API (GraphQL) has the capability to handle relationships between Models, such as By default, GraphQL APIs requests generate a selection set with a depth of 0. Connected relationship models are not returned in the initial request, but can be lazily loaded as needed with an additional API request. We provide mechanisms to customize the selection set, which allows connected relationships to be eagerly loaded on the initial request. + + +With versions of Amplify CLI `@aws-amplify/cli@12.12.2` and API Category `@aws-amplify/amplify-category-api@5.11.5`, an improvement was made to how relational field data is handled in subscriptions when different authorization rules apply to related models in a schema. The improvement redacts the values for the relational fields, displaying them as null or empty, to prevent unauthorized access to relational data. + +This redaction occurs whenever it cannot be determined that the child model will be protected by the same permissions as the parent model. + +Because subscriptions are tied to mutations and the selection set provided in the result of a mutation is then passed through to the subscription, relational fields in the result of mutations must be redacted. + +If an authorized end-user needs access to the redacted relational fields, they should perform a query to read the relational data. + +Additionally, subscriptions will inherit related authorization when relational fields are set as required. To better protect relational data, consider modifying the schema to use optional relational fields. + +- **Lazy and Eager Loading**: Lazy and eager loading relationships is no longer supported for Mutations and Subscriptions. However, you can continue to perform eager or lazy loading for Queries. + +- **Subscriptions and Related Models**: When performing a subscription and you need to retrieve the related model, perform a lazy or eager loaded query using the model identifier from the subscription event to continue to retrieve the related data. + +Based on the security posture of your application, you can choose to revert to the subscription behavior before this improvement was made. +To do so, use the `subscriptionsInheritPrimaryAuth` feature flag under `graphqltransformer` in the `amplify/backend/cli.json` file. + +- If enabled, subscriptions will inherit the primary model authorization rules for the relational fields. +- If disabled, relational fields will be redacted in mutation response when there is a difference between auth rules between primary and related models. + + + ## Prerequisites The following examples have a minimum version requirement of the following: diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/subscribe-data/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/subscribe-data/index.mdx index 50adb8b5abf..51af5300967 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/subscribe-data/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/subscribe-data/index.mdx @@ -49,6 +49,12 @@ Before you begin, you will need: +{/* This component contains approved messaging and cannot be removed or modified without prior approval */} + +import { ProtectedRedactionGen1Message } from "@/protected/ProtectedRedactionMessage" + + + ## Set up a real-time subscription Subscriptions is a GraphQL feature that allows the server to send data to its clients when a specific event happens. For example, you can subscribe to an event when a new record is created, updated, or deleted through the API. You can enable real-time data integration in your app with a subscription. diff --git a/src/pages/gen1/[platform]/prev/build-a-backend/graphqlapi/subscribe-data/index.mdx b/src/pages/gen1/[platform]/prev/build-a-backend/graphqlapi/subscribe-data/index.mdx index 9fd2e89d703..0f758f8ec05 100644 --- a/src/pages/gen1/[platform]/prev/build-a-backend/graphqlapi/subscribe-data/index.mdx +++ b/src/pages/gen1/[platform]/prev/build-a-backend/graphqlapi/subscribe-data/index.mdx @@ -38,6 +38,12 @@ Before you begin, you will need: - An [application connected to the API](/gen1/[platform]/prev/build-a-backend/graphqlapi/connect-to-api/) - Data already created to modify +{/* This component contains approved messaging and cannot be removed or modified without prior approval */} + +import { ProtectedRedactionGen1Message } from "@/protected/ProtectedRedactionMessage" + + + ## Set up a real-time subscription Subscriptions is a GraphQL feature that allows the server to send data to its clients when a specific event happens. For example, you can subscribe to an event when a new record is created, updated, or deleted through the API. You can enable real-time data integration in your app with a subscription. diff --git a/src/protected/ProtectedRedactionMessage/__tests__/ProtectedRedactionMessage.test.tsx b/src/protected/ProtectedRedactionMessage/__tests__/ProtectedRedactionMessage.test.tsx new file mode 100644 index 00000000000..53ec88223b1 --- /dev/null +++ b/src/protected/ProtectedRedactionMessage/__tests__/ProtectedRedactionMessage.test.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { + ProtectedRedactionGen1Message, + ProtectedRedactionGen2Message +} from '../index'; +import fs from 'fs'; + +// REALTIME DATA +const GEN1_V5_REALTIME_DATA_PAGE_PATH = + 'src/pages/gen1/[platform]/prev/build-a-backend/graphqlapi/subscribe-data/index.mdx'; + +const GEN1_V6_REALTIME_DATA_PAGE_PATH = + 'src/pages/gen1/[platform]/build-a-backend/graphqlapi/subscribe-data/index.mdx'; + +const GEN2_REALTIME_DATA_PAGE_PATH = + 'src/pages/[platform]/build-a-backend/data/subscribe-data/index.mdx'; + +// DATA MODELING + +const GEN1_V6_DATA_MODELING_PAGE_PATH = + 'src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx'; + +const GEN2_DATA_MODELING_PAGE_PATH = + 'src/pages/[platform]/build-a-backend/data/data-modeling/relationships/index.mdx'; + +describe('Protected Redaction Messages', () => { + /* + This test is to ensure that the ProtectedRedactionGen1Message component appears on the Gen 1 realtime data pages and cannot be removed or modified without approval. + */ + it('should render ProtectedRedactionGen1Message component on the Gen 1 V5 realtime data page', async () => { + const pageData = fs.readFileSync(GEN1_V5_REALTIME_DATA_PAGE_PATH, { + encoding: 'utf8' + }); + expect(pageData).toMatch(//); + }); + + it('should render ProtectedRedactionGen1Message component on the Gen 1 V6 realtime data page', async () => { + const pageData = fs.readFileSync(GEN1_V6_REALTIME_DATA_PAGE_PATH, { + encoding: 'utf8' + }); + expect(pageData).toMatch(//); + }); + + it('should render ProtectedRedactionGen1Message component on the Gen 2 realtime data page', async () => { + const pageData = fs.readFileSync(GEN2_REALTIME_DATA_PAGE_PATH, { + encoding: 'utf8' + }); + expect(pageData).toMatch(//); + }); + + it('should render ProtectedRedactionGen1Message component on the Gen 1 V6 data modeling page', async () => { + const pageData = fs.readFileSync(GEN1_V6_DATA_MODELING_PAGE_PATH, { + encoding: 'utf8' + }); + expect(pageData).toMatch(//); + }); + + it('should render ProtectedRedactionGen1Message component on the Gen 2 data modeling page', async () => { + const pageData = fs.readFileSync(GEN2_DATA_MODELING_PAGE_PATH, { + encoding: 'utf8' + }); + expect(pageData).toMatch(//); + }); + + /* + This test is to ensure that the messaging on the ProtectedRedactionGen1Message component does not change + and cannot be removed or modified without approval. + */ + it('should render the protected redaction message for Gen 1', async () => { + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + }); + + it('should render the protected redaction message for Gen 2', async () => { + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + }); +}); diff --git a/src/protected/ProtectedRedactionMessage/__tests__/__snapshots__/ProtectedRedactionMessage.test.tsx.snap b/src/protected/ProtectedRedactionMessage/__tests__/__snapshots__/ProtectedRedactionMessage.test.tsx.snap new file mode 100644 index 00000000000..42d72237658 --- /dev/null +++ b/src/protected/ProtectedRedactionMessage/__tests__/__snapshots__/ProtectedRedactionMessage.test.tsx.snap @@ -0,0 +1,137 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Protected Redaction Messages should render the protected redaction message for Gen 1 1`] = ` +
+ +
+
+

+ With versions of Amplify CLI + + @aws-amplify/cli@12.12.2 + + and API Category + + @aws-amplify/amplify-category-api@5.11.5 + + , an improvement was made to how relational field data is handled in subscriptions when different authorization rules apply to related models in a schema. The improvement redacts the values for the relational fields, displaying them as null or empty, to prevent unauthorized access to relational data. This redaction occurs whenever it cannot be determined that the child model will be protected by the same permissions as the parent model. +

+

+ Because subscriptions are tied to mutations and the selection set provided in the result of a mutation is then passed through to the subscription, relational fields in the result of mutations must be redacted. +

+

+ If an authorized end-user needs access to the redacted relational field they should perform a query to read the relational data. +

+

+ Additionally, subscriptions will inherit related authorization when relational fields are set as required. To better protect relational data, consider modifying the schema to use optional relational fields. +

+

+ Based on the security posture of your application, you can choose to revert to the subscription behavior before this improvement was made. +

+

+ To do so, use the + + subscriptionsInheritPrimaryAuth + + feature flag under + + graphqltransformer + + in the + + + amplify/backend/cli.json + + file. +

+
    +
  • + If enabled, subscriptions will inherit the primary model authorization rules for the relational fields. +
  • +
  • + If disabled, relational fields will be redacted in mutation response when there is a difference between auth rules between primary and related models. +
  • +
+
+
+
+`; + +exports[`Protected Redaction Messages should render the protected redaction message for Gen 2 1`] = ` +
+ +
+
+

+ With Amplify Data Construct + + @aws-amplify/data-construct@1.8.4 + + , an improvement was made to how relational field data is handled in subscriptions when different authorization rules apply to related models in a schema. The improvement redacts the values for the relational fields, displaying them as null or empty, to prevent unauthorized access to relational data. +

+

+ This redaction occurs whenever it cannot be determined that the child model will be protected by the same permissions as the parent model. +

+

+ Because subscriptions are tied to mutations and the selection set provided in the result of a mutation is then passed through to the subscription, relational fields in the result of mutations must be redacted. +

+

+ If an authorized end-user needs access to the redacted relational fields, they should perform a query to read the relational data. +

+

+ Additionally, subscriptions will inherit related authorization when relational fields are set as required. To better protect relational data, consider modifying the schema to use optional relational fields. +

+
+
+
+`; diff --git a/src/protected/ProtectedRedactionMessage/index.tsx b/src/protected/ProtectedRedactionMessage/index.tsx new file mode 100644 index 00000000000..c4180a29e42 --- /dev/null +++ b/src/protected/ProtectedRedactionMessage/index.tsx @@ -0,0 +1,84 @@ +import { Callout } from '@/components/Callout'; + +// WARNING: The messaging in this component should NOT be changed without the appropriate approvals +export const ProtectedRedactionGen1Message = () => ( + +

+ With versions of Amplify CLI @aws-amplify/cli@12.12.2 and API + Category + @aws-amplify/amplify-category-api@5.11.5, an improvement was + made to how relational field data is handled in subscriptions when + different authorization rules apply to related models in a schema. The + improvement redacts the values for the relational fields, displaying them + as null or empty, to prevent unauthorized access to relational data. This + redaction occurs whenever it cannot be determined that the child model + will be protected by the same permissions as the parent model. +

+

+ Because subscriptions are tied to mutations and the selection set provided + in the result of a mutation is then passed through to the subscription, + relational fields in the result of mutations must be redacted. +

+

+ If an authorized end-user needs access to the redacted relational field + they should perform a query to read the relational data. +

+

+ Additionally, subscriptions will inherit related authorization when + relational fields are set as required. To better protect relational data, + consider modifying the schema to use optional relational fields. +

+

+ Based on the security posture of your application, you can choose to + revert to the subscription behavior before this improvement was made. +

+

+ To do so, use the subscriptionsInheritPrimaryAuth feature + flag under graphqltransformer in the{' '} + amplify/backend/cli.json file. +

+
    +
  • + If enabled, subscriptions will inherit the primary model authorization + rules for the relational fields. +
  • +
  • + If disabled, relational fields will be redacted in mutation response + when there is a difference between auth rules between primary and + related models. +
  • +
+
+); + +// WARNING: The messaging in this component should NOT be changed without the appropriate approvals +export const ProtectedRedactionGen2Message = () => ( + +

+ With Amplify Data Construct @aws-amplify/data-construct@1.8.4 + , an improvement was made to how relational field data is handled in + subscriptions when different authorization rules apply to related models + in a schema. The improvement redacts the values for the relational fields, + displaying them as null or empty, to prevent unauthorized access to + relational data. +

+

+ This redaction occurs whenever it cannot be determined that the child + model will be protected by the same permissions as the parent model. +

+

+ Because subscriptions are tied to mutations and the selection set provided + in the result of a mutation is then passed through to the subscription, + relational fields in the result of mutations must be redacted. +

+

+ If an authorized end-user needs access to the redacted relational fields, + they should perform a query to read the relational data. +

+

+ Additionally, subscriptions will inherit related authorization when + relational fields are set as required. To better protect relational data, + consider modifying the schema to use optional relational fields. +

+
+); From 03372e22fdf5622f600109d2f171991e6d577e3e Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Tue, 2 Jul 2024 11:07:43 -0600 Subject: [PATCH 10/48] fix subscriptionsInheritPrimaryAuth default value (#7795) --- src/components/FeatureFlags/feature-flags.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/FeatureFlags/feature-flags.json b/src/components/FeatureFlags/feature-flags.json index 73f774d3b88..b4ccaf9c1b7 100644 --- a/src/components/FeatureFlags/feature-flags.json +++ b/src/components/FeatureFlags/feature-flags.json @@ -382,13 +382,13 @@ "value": "true", "description": "Subscriptions will inherit the primary model authorization rules for the relational fields", "defaultNewProject": false, - "defaultExistingProject": true + "defaultExistingProject": false }, { "value": "false", "description": "Relational fields will be redacted in mutation response when there is a difference between auth rules between primary and related models.", "defaultNewProject": true, - "defaultExistingProject": false + "defaultExistingProject": true } ] } From 3298bbadc2cb4f045841c3d606e22b52e27aa5db Mon Sep 17 00:00:00 2001 From: Katie Goines <30757403+katiegoines@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:23:02 -0400 Subject: [PATCH 11/48] change overview card titles from p to h2 (#7780) Co-authored-by: katiegoines --- src/components/Overview/Overview.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Overview/Overview.tsx b/src/components/Overview/Overview.tsx index 296f1ffcad5..c7f9a24fc7b 100644 --- a/src/components/Overview/Overview.tsx +++ b/src/components/Overview/Overview.tsx @@ -1,5 +1,5 @@ import { PageNode } from '@/directory/directory'; -import { Card, Flex, View, Text } from '@aws-amplify/ui-react'; +import { Card, Flex, View, Heading } from '@aws-amplify/ui-react'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { Platform } from '@/data/platforms'; @@ -40,9 +40,9 @@ export function Overview({ childPageNodes }: OverviewProps) { > - + {node.title} - + {node.description} From c550c1916644955729712ed2c5475a56afadc1f2 Mon Sep 17 00:00:00 2001 From: Katie Goines <30757403+katiegoines@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:23:20 -0400 Subject: [PATCH 12/48] remove conditional in aria-describedby={codeId} for MDXCopyCodeButton (#7779) Co-authored-by: katiegoines --- src/components/MDXComponents/MDXCopyCodeButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MDXComponents/MDXCopyCodeButton.tsx b/src/components/MDXComponents/MDXCopyCodeButton.tsx index ad76cf72a58..8c49bda7188 100644 --- a/src/components/MDXComponents/MDXCopyCodeButton.tsx +++ b/src/components/MDXComponents/MDXCopyCodeButton.tsx @@ -36,7 +36,7 @@ export const MDXCopyCodeButton = ({ disabled={copied} className="code-copy" testId={testId} - aria-describedby={title ? undefined : codeId} + aria-describedby={codeId} > {copied ? 'Copied!' : 'Copy'} From 9a5e77f353885a6757180969a85a683ca8d41189 Mon Sep 17 00:00:00 2001 From: Nikhil Swaminathan <2429410+swaminator@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:49:12 -0700 Subject: [PATCH 13/48] Update index.mdx to fix typo (#7798) Removed mention of create-vite-app --- src/pages/[platform]/start/quickstart/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/[platform]/start/quickstart/index.mdx b/src/pages/[platform]/start/quickstart/index.mdx index 1cdb47c3fee..4670a5e92a5 100644 --- a/src/pages/[platform]/start/quickstart/index.mdx +++ b/src/pages/[platform]/start/quickstart/index.mdx @@ -933,7 +933,7 @@ We've created a starter "To-do" application to help get started faster. First, y ### 1. Create the repository -Use our starter template to create a repository in your GitHub account. This template scaffolds `create-vite-app` with Amplify backend capabilities. +Use our starter template to create a repository in your GitHub account. This template scaffolds a starter Angular application with Amplify backend capabilities. Date: Wed, 3 Jul 2024 11:35:23 -0400 Subject: [PATCH 14/48] add workflow to validate redirects (#7726) * add workflow to validate redirects * change filename * removing testing errors * finding all invalid redirects * running validation to catch all issues * remove unneeded code --------- Co-authored-by: katiegoines --- .../workflows/scripts/validate-redirects.js | 58 +++++++++++++++++++ .github/workflows/validate_redirects.yml | 32 ++++++++++ package.json | 1 + redirects.json | 2 +- yarn.lock | 12 +++- 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/scripts/validate-redirects.js create mode 100644 .github/workflows/validate_redirects.yml diff --git a/.github/workflows/scripts/validate-redirects.js b/.github/workflows/scripts/validate-redirects.js new file mode 100644 index 00000000000..de89c1e3802 --- /dev/null +++ b/.github/workflows/scripts/validate-redirects.js @@ -0,0 +1,58 @@ +module.exports = { + invalidRedirects: () => { + const Ajv = require('ajv'); + const redirects = require('../../../redirects.json'); + const ajv = new Ajv(); + + const schema = { + type: 'array', + items: { + type: 'object', + required: ['source', 'target', 'status'], + properties: { + source: { + description: 'The address the user requested.', + type: 'string', + pattern: '^/' + }, + target: { + description: + 'The address that actually serves the content that the user sees', + type: 'string', + pattern: '^[(https)(/)]' + }, + status: { + description: + 'Types include a permanent redirect (301), a temporary redirect (302), a rewrite (200), or not found (404).', + type: 'string', + pattern: '^[0-5-]+$' + } + } + } + }; + + const errors = []; + const validate = ajv.compile(schema); + + const validateEntries = (redirects) => { + const valid = validate(redirects); + + if (!valid) { + const error = validate.errors[0]; + const invalidEntry = + JSON.stringify(redirects[error.instancePath.slice(1, -7)]); + const loc = error.schemaPath.slice(error.schemaPath.indexOf('properties') + 11, -8); + const errorMessage = '\n\n' + 'INVALID ENTRY: Please correct the error in the "' + loc +'" property of the following entry: \n' + invalidEntry + '\n' + 'ERROR MESSAGE: ' + error.message; + errors.push(errorMessage); + + validateEntries(redirects.splice(parseInt(error.instancePath.slice(1, -7)) + 1)); + + } + } + validateEntries(redirects); + + return errors; + } +} + + diff --git a/.github/workflows/validate_redirects.yml b/.github/workflows/validate_redirects.yml new file mode 100644 index 00000000000..e37598b26c2 --- /dev/null +++ b/.github/workflows/validate_redirects.yml @@ -0,0 +1,32 @@ +name: Validate Redirects +on: + pull_request: + branches: [main] + types: [opened, synchronize] +env: + BUILD_DIR: 'client/www/next-build' +permissions: + contents: read +jobs: + ValidateRedirects: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - name: Setup Node.js 20.x + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: 20.x + - name: Install Dependencies + run: yarn + - name: Validate redirects + id: redirects + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + result-encoding: string + script: | + const { invalidRedirects } = require('./.github/workflows/scripts/validate-redirects.js'); + return await invalidRedirects(); + - name: Fail if any invalid redirects have been found + if: ${{ steps.redirects.outputs.result }} + run: exit 1 && echo ${{ steps.redirects.outputs.result }} diff --git a/package.json b/package.json index 492baeac11c..cb13c85ffaf 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@aws-amplify/amplify-cli-core": "^4.3.8", "@aws-amplify/ui-react": "^6.1.12", "@docsearch/react": "3", + "ajv": "^8.16.0", "aws-amplify": "^6.0.9", "next": "^14.2.3", "next-image-export-optimizer": "^1.8.3", diff --git a/redirects.json b/redirects.json index 9d74a7b3294..1655fdaae20 100644 --- a/redirects.json +++ b/redirects.json @@ -3011,7 +3011,7 @@ }, { "source": "/lib/client-configuration/configuring-amplify-categories/q/platform/react-native/", - "target": "react-native/tools/libraries/configure-categories/", + "target": "/react-native/tools/libraries/configure-categories/", "status": "301" }, { diff --git a/yarn.lock b/yarn.lock index cf335895a30..9afbdd468d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3547,6 +3547,16 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.16.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" + integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== + dependencies: + fast-deep-equal "^3.1.3" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.4.1" + algoliasearch@^4.19.1: version "4.22.1" resolved "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.22.1.tgz" @@ -11493,7 +11503,7 @@ upper-case@^2.0.2: dependencies: tslib "^2.0.3" -uri-js@^4.2.2: +uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== From 6efa947841b6434ee61c0b347fff6b040e67e621 Mon Sep 17 00:00:00 2001 From: josef Date: Thu, 4 Jul 2024 09:52:37 -0500 Subject: [PATCH 15/48] update set up function guide with data example (#7759) * update set up function guide with data example * add mobile snippets --- .../functions/set-up-function/index.mdx | 206 +++++++++++++++++- 1 file changed, 204 insertions(+), 2 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx b/src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx index 7249046ed9f..d625e60207d 100644 --- a/src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx +++ b/src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx @@ -53,7 +53,7 @@ export const sayHello = defineFunction({ Next, create the corresponding handler file at `amplify/functions/say-hello/handler.ts`. This is where your function code will go. ```ts title="amplify/functions/say-hello/handler.ts" -import { Handler } from 'aws-lambda'; +import type { Handler } from 'aws-lambda'; export const handler: Handler = async (event, context) => { // your function code goes here @@ -76,7 +76,209 @@ defineBackend({ }); ``` -Now when you run `npx ampx sandbox` or deploy your app on Amplify, it will include your backend function. See the [examples](../examples/) below for connecting your functions to event sources. +Now when you run `npx ampx sandbox` or deploy your app on Amplify, it will include your Function. + +To invoke your Function, we recommend adding your [Function as a handler for a custom query with your Amplify Data resource](/[platform]/build-a-backend/data/custom-business-logic/). This will enable you to strongly type Function arguments and the return statement, and use this to author your Function's business logic. To get started, open your `amplify/data/resource.ts` file and specify a new query in your schema: + +```ts title="amplify/data/resource.ts" +import { type ClientSchema, a, defineData } from "@aws-amplify/backend" +import { sayHello } from "../functions/say-hello/resource" + +const schema = a.schema({ + // highlight-start + sayHello: a + .query() + .arguments({ + name: a.string().default("World"), + }) + .returns(a.string()) + .handler(a.handler.function(sayHello)), + // highlight-end +}) + +export type Schema = ClientSchema + +export const data = defineData({ + schema, + authorizationModes: { + defaultAuthorizationMode: "iam", + }, +}) +``` + +Now you can use this query from the `Schema` export to strongly type your Function handler: + +```ts title="amplify/functions/say-hello/handler.ts" +import type { Schema } from "../../data/resource" + +export const handler: Schema["sayHello"]["functionHandler"] = async (event) => { + // arguments typed from `.arguments()` + const { name } = event.arguments + // return typed from `.returns()` + return `Hello, ${name}!` +} +``` + +Finally, use the data client to invoke your Function by calling its associated query. + + + +```ts title="src/main.ts" +import type { Schema } from "./amplify/data/resource" +import { Amplify } from "aws-amplify" +import { generateClient } from "aws-amplify/api" +import outputs from "./amplify_outputs.json" + +Amplify.configure(outputs) + +const client = generateClient() + +// highlight-start +client.queries.sayHello({ + name: "Amplify", +}) +// highlight-end +``` + + + + +```kt +data class SayHelloDetails( + val name: String, +) + +data class SayHelloResponse( + val sayHello: SayHelloDetails +) + +val document = """ + query SayHelloQuery(${'$'}name: String!) { + sayHello(name: ${'$'}name) { + name + executionDuration + } + } +""".trimIndent() +val sayHelloQuery = SimpleGraphQLRequest( + document, + mapOf("name" to "Amplify"), + String::class.java, + GsonVariablesSerializer()) + +Amplify.API.query( + sayHelloQuery, + { + var gson = Gson() + val response = gson.fromJson(it.data, SayHelloResponse::class.java) + Log.i("MyAmplifyApp", "${response.sayHello.name}") + }, + { Log.e("MyAmplifyApp", "$it")} +) +``` + + + + +First define a class that matches your response shape: + +```dart +class SayHelloResponse { + final SayHello sayHello; + + SayHelloResponse({required this.sayHello}); + + factory SayHelloResponse.fromJson(Map json) { + return SayHelloResponse( + sayHello: SayHello.fromJson(json['sayHello']), + ); + } +} + +class SayHello { + final String name; + final double executionDuration; + + SayHello({required this.name, required this.executionDuration}); + + factory SayHello.fromJson(Map json) { + return SayHello( + name: json['name'], + executionDuration: json['executionDuration'], + ); + } +} +``` + +Next, make the request and map the response to the classes defined above: + +```dart +// highlight-next-line +import 'dart:convert'; + +// highlight-start +const graphQLDocument = ''' + query SayHello(\$name: String!) { + sayHello(name: \$name) { + name + executionDuration + } + } +'''; + +final echoRequest = GraphQLRequest( + document: graphQLDocument, + variables: {"name": "Amplify"}, +); + +final response = + await Amplify.API.query(request: echoRequest).response; +safePrint(response); + +Map jsonMap = json.decode(response.data!); +SayHelloResponse SayHelloResponse = SayHelloResponse.fromJson(jsonMap); +safePrint(SayHelloResponse.sayHello.name); +// highlight-end +``` + + + + +```swift +struct SayHelloResponse: Codable { + public let sayHello: SayHello + + struct SayHello: Codable { + public let name: String + public let executionDuration: Float + } +} + +let document = """ + query EchoQuery($name: String!) { + sayHello(name: $name) { + name + executionDuration + } + } + """ + +let result = try await Amplify.API.query(request: GraphQLRequest( + document: document, + variables: [ + "name": "Amplify" + ], + responseType: SayHelloResponse.self +)) +switch result { +case .success(let response): + print(response.sayHello) +case .failure(let error): + print(error) +} +``` + + ## Next steps From 6966a11714cfcc39d51af7a7707f55114e805654 Mon Sep 17 00:00:00 2001 From: Kethan sai Date: Fri, 5 Jul 2024 12:07:02 -0400 Subject: [PATCH 16/48] remove checkboxes and circle (#7783) --- .../connect-postgres-mysql-database/index.mdx | 22 +++++-------------- .../start/migrate-to-gen2/index.mdx | 4 ++-- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx b/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx index a720275fa95..e968a0571ac 100644 --- a/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx @@ -34,23 +34,11 @@ Amplify's native integration supports any MySQL or Postgres database, no matter You must create a connection string using the following database information to get started: -
    -
  • - Database **hostname** -
  • -
  • - Database **port** -
  • -
  • - Database **username** -
  • -
  • - Database **user password** -
  • -
  • - Database **name** -
  • -
+- Database **hostname** +- Database **port** +- Database **username** +- Database **user password** +- Database **name** diff --git a/src/pages/[platform]/start/migrate-to-gen2/index.mdx b/src/pages/[platform]/start/migrate-to-gen2/index.mdx index 41c660245c5..46794d16100 100644 --- a/src/pages/[platform]/start/migrate-to-gen2/index.mdx +++ b/src/pages/[platform]/start/migrate-to-gen2/index.mdx @@ -185,8 +185,8 @@ The tables below present a feature matrix for Gen 1 customers who are considerin | Function templates: Hello World | Yes | Yes | | Function templates: Lambda trigger | Yes | Yes | | Function logs in console | Yes | Yes | -| Function resource access permissions: ◯ geo | Yes | Yes with CDK | -| Function resource access permissions: ◯ analytics | Yes | Yes with CDK | +| Function resource access permissions: geo | Yes | Yes with CDK | +| Function resource access permissions: analytics | Yes | Yes with CDK | | Function runtime: .NET 6 | Yes | Yes with CDK | | Function runtime: Go | Yes | Yes with CDK | | Function runtime: Java | Yes | Yes with CDK | From 09779ce6babc7958477f6960804a5750f217de7a Mon Sep 17 00:00:00 2001 From: Heather Buchel Date: Fri, 5 Jul 2024 14:02:48 -0400 Subject: [PATCH 17/48] fix: heading order (#7803) --- .../auth/grant-access-to-auth-resources/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx b/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx index c9603d43a4f..6c9858236d8 100644 --- a/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx @@ -54,7 +54,7 @@ When you grant a function access to another resource in your Amplify backend it -### List of actions +## List of actions |Action Name|Description|Cognito IAM Actions| |-|-|-| From 1fba05c8c4d717469b22bedafd8e4c0e162d4591 Mon Sep 17 00:00:00 2001 From: Joon Choi Date: Fri, 5 Jul 2024 11:57:49 -0700 Subject: [PATCH 18/48] restore autoSignIn section for SignIn page, and Switching Authentication Flows page for js categories (#7769) Co-authored-by: JoonWon Choi --- .../connect-your-frontend/sign-in/index.mdx | 13 +++ .../switching-authentication-flows/index.mdx | 91 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 5087c231df3..bdf0f7a648d 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -659,6 +659,19 @@ signInWithRedirect({ provider: { }}) ``` +### Auto sign-in + +The `autoSignIn` API will automatically sign-in a user when it was previously enabled by the `signUp` API and after any of the following cases has completed: + +- User confirmed their account with a verification code sent to their phone or email (default option). +- User confirmed their account with a verification link sent to their phone or email. In order to enable this option you need to go to the [Amazon Cognito console](https://aws.amazon.com/pm/cognito), look for your userpool, then go to the `Messaging` tab and enable `link` mode inside the `Verification message` option. Finally you need to define the `signUpVerificationMethod` to `link` inside the `Cognito` option of your `Auth` config. + +```ts title="src/main.ts" +import { autoSignIn } from 'aws-amplify/auth'; + +await autoSignIn(); +``` + diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 6d7f829154f..e18fd879ad7 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -4,7 +4,13 @@ export const meta = { title: 'Switching authentication flows', description: 'Learn how to switch between different auth flows', platforms: [ + 'angular', + 'javascript', + 'nextjs', + 'react', + 'react-native', 'swift', + 'vue' ] }; @@ -20,6 +26,8 @@ export function getStaticProps() { }; } + + `AWSCognitoAuthPlugin` allows you to switch between different auth flows while initiating signIn. You can configure the flow in the `amplifyconfiguration.json` file or pass the `authFlowType` as a runtime parameter to the `signIn` api call. For client side authentication there are four different flows that can be configured during runtime: @@ -105,6 +113,89 @@ The flow is initiated by calling `signIn` with `AuthSignInOptions` configured wi Follow the instructions in [Custom Auth Sign In](/gen1/[platform]/build-a-backend/auth/sign-in-custom-flow/) to learn about how to integrate custom authentication flow in your application with the Auth APIs. + + + + +For client side authentication there are three different flows: + +1. `USER_SRP_AUTH`: The `USER_SRP_AUTH` flow uses the [SRP protocol (Secure Remote Password)](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) where the password never leaves the client and is unknown to the server. This is the recommended flow and is used by default. + +2. `USER_PASSWORD_AUTH`: The `USER_PASSWORD_AUTH` flow will send user credentials to the backend without applying SRP encryption. If you want to migrate users to Cognito using the "Migration" trigger and avoid forcing users to reset their passwords, you will need to use this authentication type because the Lambda function invoked by the trigger needs to verify the supplied credentials. + +3. `CUSTOM_WITH_SRP` & `CUSTOM_WITHOUT_SRP`: Allows for a series of challenge and response cycles that can be customized to meet different requirements. + +The Auth flow can be customized when calling `signIn`, for example: + +```ts title="src/main.ts" +await signIn({ + username: "hello@mycompany.com", + password: "hunter2", + options: { + authFlowType: 'USER_PASSWORD_AUTH' + } +}) +``` + +> For more information about authentication flows, please visit [AWS Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow) + +## USER_PASSWORD_AUTH flow + +A use case for the `USER_PASSWORD_AUTH` authentication flow is migrating users into Amazon Cognito + +### Set up auth backend + +In order to use the authentication flow `USER_PASSWORD_AUTH`, your Cognito app client has to be configured to allow it. In the AWS Console, this is done by ticking the checkbox at General settings > App clients > Show Details (for the affected client) > Enable username-password (non-SRP) flow. If you're using the AWS CLI or CloudFormation, update your app client by adding `USER_PASSWORD_AUTH` to the list of "Explicit Auth Flows". + +### Migrate users with Amazon Cognito + +Amazon Cognito provides a trigger to migrate users from your existing user directory seamlessly into Cognito. You achieve this by configuring your User Pool's "Migration" trigger which invokes a Lambda function whenever a user that does not already exist in the user pool authenticates, or resets their password. + +In short, the Lambda function will validate the user credentials against your existing user directory and return a response object containing the user attributes and status on success. An error message will be returned if an error occurs. Visit [Amazon Cognito user pools import guide](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html) for migration flow and more detailed instruction, and [Amazon Cognito Lambda trigger guide](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html#cognito-user-pools-lambda-trigger-syntax-user-migration) on how to set up lambda to handle request and response objects. + +## `CUSTOM_WITH_SRP` & `CUSTOM_WITHOUT_SRP` flows + +Amazon Cognito user pools supports customizing the authentication flow to enable custom challenge types, +in addition to a password in order to verify the identity of users. These challenge types may include CAPTCHAs +or dynamic challenge questions. The `CUSTOM_WITH_SRP` flow requires a password when calling `signIn`. Both of +these flows map to the `CUSTOM_AUTH` flow in Cognito. + +To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito. + + + +For more information about working with Lambda Triggers for custom authentication challenges, please visit [Amazon Cognito Developer Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html). + + + +### Custom authentication flow + +To initiate a custom authentication flow in your app, call `signIn` without a password. A custom challenge needs to be answered using the `confirmSignIn` API: + +```ts title="src/main.ts" +import { signIn, confirmSignIn } from 'aws-amplify/auth'; + +const challengeResponse = 'the answer for the challenge'; + +const { nextStep } = await signIn({ + username, + options: { + authFlowType: 'CUSTOM_WITHOUT_SRP', + }, +}); + +if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') { + // to send the answer of the custom challenge + await confirmSignIn({ challengeResponse }); +} +``` + +### CAPTCHA authentication + +To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples. + + + For more information about working with Lambda Triggers for custom authentication challenges, please visit [Amazon Cognito Developer Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html). From 2548f29bd573da8245dc989d1dd8ea59ed709290 Mon Sep 17 00:00:00 2001 From: MURAKAMI Masahiko Date: Tue, 9 Jul 2024 03:10:40 +0900 Subject: [PATCH 19/48] replace `amplify` to `ampx` (#7804) --- .../fullstack-branching/share-resources/index.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/[platform]/deploy-and-host/fullstack-branching/share-resources/index.mdx b/src/pages/[platform]/deploy-and-host/fullstack-branching/share-resources/index.mdx index 4722f180b2c..765422a4039 100644 --- a/src/pages/[platform]/deploy-and-host/fullstack-branching/share-resources/index.mdx +++ b/src/pages/[platform]/deploy-and-host/fullstack-branching/share-resources/index.mdx @@ -56,15 +56,15 @@ backend: ;; dev) echo "Deploying dev branch..." - npx amplify pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID + npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID ;; pr-*) echo "Deploying pull request branch..." - npx ampx generate outputs --branch previews --app-id $AWS_APP_ID + npx ampx generate outputs --branch previews --app-id $AWS_APP_ID ;; *) echo "Deploying to staging branch..." - npx ampx generate outputs --branch dev --app-id $AWS_APP_ID + npx ampx generate outputs --branch dev --app-id $AWS_APP_ID ;; esac frontend: From 8bda64e6a753ed263782aed229f181b15d9a1588 Mon Sep 17 00:00:00 2001 From: Dustin Noyes Date: Tue, 9 Jul 2024 10:08:49 -0700 Subject: [PATCH 20/48] feat(js): list api subpathStrategy parameter (#7794) * feat(js): list api subpathStrategy parameter * fix: adds style guide suggestions * fix: adds result structure * fix: tried to delineate between recursive exploration of entire path and subpathStrategy option * Update src/pages/[platform]/build-a-backend/storage/list-files/index.mdx Co-authored-by: Harshita Daddala * Update src/pages/[platform]/build-a-backend/storage/list-files/index.mdx Co-authored-by: Harshita Daddala * Update src/pages/[platform]/build-a-backend/storage/list-files/index.mdx Co-authored-by: Harshita Daddala * Update src/pages/[platform]/build-a-backend/storage/list-files/index.mdx Co-authored-by: Harshita Daddala * Update src/pages/[platform]/build-a-backend/storage/list-files/index.mdx Co-authored-by: ashika112 <155593080+ashika112@users.noreply.github.com> * Update src/pages/[platform]/build-a-backend/storage/list-files/index.mdx Co-authored-by: josef * comments and prettier * undid prettier table change * Update src/pages/[platform]/build-a-backend/storage/list-files/index.mdx Co-authored-by: josef --------- Co-authored-by: haverchuck Co-authored-by: Harshita Daddala Co-authored-by: ashika112 <155593080+ashika112@users.noreply.github.com> Co-authored-by: josef --- .../storage/list-files/index.mdx | 111 ++++++++++++++---- 1 file changed, 87 insertions(+), 24 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx b/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx index 37d01b40b9c..3eb8a2613a3 100644 --- a/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx +++ b/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx @@ -29,7 +29,7 @@ export function getStaticProps(context) { }; } -You can list files without having to download all the files. You can do this by using the listFile API from the Amplify Library for Storage. You can also get properties individually for a file using the getProperties API. +You can list files without having to download all the files. You can do this by using the `list` API from the Amplify Library for Storage. You can also get properties individually for a file using the getProperties API. ## List Files @@ -37,14 +37,10 @@ You can list files without having to download all the files. You can do this by ```javascript import { list } from 'aws-amplify/storage'; -try { - const result = await list({ - path: 'photos/', - // Alternatively, path: ({identityId}) => `album/{identityId}/photos/` - }); -} catch (error) { - console.log(error); -} +const result = await list({ + path: 'photos/', + // Alternatively, path: ({identityId}) => `album/{identityId}/photos/` +}); ``` Note the trailing slash `/` - if you had requested `list({ path : 'photos' })` it would also match against files like `photos123.jpg` alongside `photos/123.jpg`. @@ -63,9 +59,18 @@ The format of the response will look similar to the below example: // ... ], } -``` -{/* in other files we're referring to paths instead of folders, can we be consistent on terminology? */} -Manually created folders will show up as files with a `size` of 0, but you can also match keys against a regex like `file.key.match(/\.[0-9a-z]+$/i)` to distinguish files from folders. Since "folders" are a virtual concept in Amazon S3, any file may declare any depth of folder just by having a `/` in its name. If you need to list all the folders, you'll have to parse them accordingly to get an authoritative list of files and folders: +```` + +{/* in other files we're referring to paths instead of folders, can we be consistent on terminology? */} Manually created folders will show up as files with a `size` of 0, but you can also match keys against a regex like `file.key.match(/\.[0-9a-z]+$/i)` to distinguish files from folders. Since "folders" are a virtual concept in Amazon S3, any file may declare any depth of folder just by having a `/` in its name. + +To access the contents and subpaths of a "folder", you have two options: + +1. Request the entire path and parse the contents. +2. Use the subpathStrategy option to retrieve only the files within the specified path (i.e. exclude files under subpaths). + +### Get all nested files within a path + +This retrieves all files and folders under a given path. You may need to parse the result to get only the files within the specified path. ```js function processStorageList(response) { @@ -109,10 +114,66 @@ function processStorageList(response) { This places each item's data inside a special `__data` key. +### Excluding subpaths + +In addition to using the `list` API to get all the contents of a path, you can also use it to get only the files within a path while excluding files under subpaths. + +For example, given the following keys in your `path` you may want to return only the jpg object, and not the "vacation" subpath and its contents: + +``` +photos/photo1.jpg +photos/vacation/ +``` + +This can be accomplished with the `subpathStrategy` option: + +```ts title="src/main.ts" +import { list } from "aws-amplify/storage"; +const result = await list({ + path: "photos/", + options:{ + subpathStrategy: { strategy:'exclude' } + } +}); +``` + +The response will include only the objects within the `photos/` path and will also communicate any excluded subpaths: + +```js +{ + excludedSubpaths: [ + 'photos/vacation/' + ], + items: [ + { + path: "photos/photo1.jpg", + eTag: "30074401292215403a42b0739f3b5262", + lastModified: "Thu Oct 08 2020 23:59:31 GMT+0800 (Singapore Standard Time)", + size: 138256 + }, + ] +} +``` + +The default delimiter character is '/', but this can be changed by supplying a custom delimiter: + +```ts title="src/main.ts" +const result = await list({ + // Path uses '-' character to organize files rather than '/' + path: 'photos-', + options: { + subpathStrategy: { + strategy: 'exclude', + delimiter: '-' + } + } +}); +``` + ### More `list` options -Option | Type | Description | -| -- | -- | ----------- | +| Option | Type | Description | +| --- | --- | --- | | listAll | boolean | Set to true to list all files within the specified `path` | | pageSize | number | Sets the maximum number of files to be return. The range is 0 - 1000 | | nextToken | string | Indicates whether the list is being continued on this bucket with a token | @@ -242,7 +303,7 @@ You can list all of the objects uploaded under a given path by setting the `page ```swift let options = StorageListRequest.Options(pageSize: 1000) let listResult = try await Amplify.Storage.list( - path: .fromString("public/example/path"), + path: .fromString("public/example/path"), options: options ) listResult.items.forEach { item in @@ -258,7 +319,7 @@ listResult.items.forEach { item in let sink = Amplify.Publisher.create { let options = StorageListRequest.Options(pageSize: 1000) try await Amplify.Storage.list( - path: .fromString("public/example/path"), + path: .fromString("public/example/path"), options: options ) }.sink { @@ -280,18 +341,19 @@ receiveValue: { listResult in ### More `list` options -Option | Type | Description | -| -- | -- | ----------- | +| Option | Type | Description | +| --- | --- | --- | | pageSize | UInt | Number between 1 and 1,000 that indicates the limit of how many entries to fetch when retrieving file lists from the server | | nextToken | String | String indicating the page offset at which to resume a listing. | - + This will list all files located under path `album` that: -* have `private` access level -* are in the root of `album/` (the result doesn't include files under any sub path) + +- have `private` access level +- are in the root of `album/` (the result doesn't include files under any sub path) ```dart Future listAlbum() async { @@ -347,8 +409,8 @@ Future listAllUnderPublicPath() async { ### More `list` options -Option | Type | Description | -| -- | -- | ----------- | +| Option | Type | Description | +| --- | --- | --- | | excludeSubPaths | boolean | Whether to exclude objects under the sub paths of the path to list. Defaults to false. | | delimiter | String | The delimiter to use when evaluating sub paths. If excludeSubPaths is false, this value has no impact on behavior. | @@ -365,7 +427,7 @@ import { getProperties } from 'aws-amplify/storage'; try { const result = await getProperties({ - path: "album/2024/1.jpg", + path: 'album/2024/1.jpg' // Alternatively, path: ({ identityId }) => `album/{identityId}/1.jpg` }); console.log('File Properties ', result); @@ -373,6 +435,7 @@ try { console.log('Error ', error); } ``` + The properties and metadata will look similar to the below example ```js From cc6e6f82d89db3c957833d3fb11f2ffa2e832d31 Mon Sep 17 00:00:00 2001 From: MJ Zhang <0618@users.noreply.github.com> Date: Tue, 9 Jul 2024 11:50:57 -0700 Subject: [PATCH 21/48] chore: update domains for proxy (#7808) --- .../tools/cli/project/troubleshooting/index.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/pages/gen1/[platform]/tools/cli/project/troubleshooting/index.mdx b/src/pages/gen1/[platform]/tools/cli/project/troubleshooting/index.mdx index a89af5eff36..70405821378 100644 --- a/src/pages/gen1/[platform]/tools/cli/project/troubleshooting/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli/project/troubleshooting/index.mdx @@ -41,6 +41,14 @@ To debug deployment issues, it's helpful to understand the [file structure of yo 1. Amplify CLI walkthrough input parameters artifacts: All inputs provided by the user during a CLI walkthrough are stored in JSON files in the `/amplify/backend` folder. For example, `cli-inputs.json` or `amplify-meta.json`. These files let you inspect the configurations, both developer-provided and Amplify-generated, to root cause potential problems. Refer to [Amplify backend files documentation](/gen1/[platform]/tools/cli/reference/files/#backend-configjson) to determine if a file is safe to edit manually. +#### Domains that Amplify CLI requests when running `init`, `publish`, and `push`. + +If you run Amplify CLI via proxy, make sure to add the following domains to the allowlist. + +- amazonaws.com +- amplifyapp.com +- aws-amplify.github.io + ### For Amplify CLI projects with GraphQL API To debug deployment issues in projects with GraphQL API, it's helpful to understand the various artifacts generated by Amplify in a GraphQL project. From 14caad46000eaddcacb62b05f6d2db0023a117f8 Mon Sep 17 00:00:00 2001 From: Heather Buchel Date: Tue, 9 Jul 2024 16:11:46 -0400 Subject: [PATCH 22/48] fix: typo on client code generation page (#7809) --- .../build-a-backend/graphqlapi/client-code-generation/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/client-code-generation/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/client-code-generation/index.mdx index e3e2b176bac..9a70f7cbb99 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/client-code-generation/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/client-code-generation/index.mdx @@ -90,7 +90,7 @@ Each time you will be prompted to update the code in your API and also ask you i ### No API changes, just update GraphQL statements & generate code -One of the benefits of GraphQL is the client can define it's data fetching requirements independently of the API. Amplify codegen supports this by allowing you to modify the selection set (e.g. add/remove fields inside the curly braces) for the GraphQL statements and running type generation again. This gives you fine-grained control over the network requests that your application is making. Modify your GraphQL statements (default in the `./graphql` folder unless you changed it) then save the files and run: +One of the benefits of GraphQL is the client can define its data fetching requirements independently of the API. Amplify codegen supports this by allowing you to modify the selection set (e.g. add/remove fields inside the curly braces) for the GraphQL statements and running type generation again. This gives you fine-grained control over the network requests that your application is making. Modify your GraphQL statements (default in the `./graphql` folder unless you changed it) then save the files and run: ```bash amplify codegen types From 5c25e923b5c25aa1eccca4f528ce6644f0b9753d Mon Sep 17 00:00:00 2001 From: Heather Buchel Date: Tue, 9 Jul 2024 16:26:20 -0400 Subject: [PATCH 23/48] Fix anchor link, add some scroll margin to h4 headings (#7810) --- .../build-a-backend/graphqlapi/data-modeling/index.mdx | 4 ++-- src/styles/base.scss | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx index 59c389676cb..50778e981c1 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/index.mdx @@ -907,7 +907,7 @@ type Query { The example above creates a custom query that utilizes the `@function` directive to call a Lambda function for this query. -For the type definitions of queries, mutations, and subscriptions, see [Type Definitions of the `@model` Directive](#type-definition-of-the-`@model`-directive). +For the type definitions of queries, mutations, and subscriptions, see [Type Definitions of the `@model` Directive](#type-definition-of-the-model-directive). ### Customize creation and update timestamps @@ -1151,7 +1151,7 @@ The `@model` directive will generate: - Filter input objects that allow you to filter objects in list queries and relationship fields. - For list queries the default number of objects returned is 100. You can override this behavior by setting the limit argument. -**Type definition of the `@model` directive** +#### Type definition of the `@model` directive ```graphql directive @model( diff --git a/src/styles/base.scss b/src/styles/base.scss index 4bfde6571a6..0a40b20b1c8 100644 --- a/src/styles/base.scss +++ b/src/styles/base.scss @@ -116,7 +116,8 @@ kbd { .main { & > h2, - & > h3 { + & > h3, + & > h4 { scroll-margin-block: 9rem; } } From 597ddd4393b7bde2a7743ddd53e088b82138e60c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 12:16:26 -0400 Subject: [PATCH 24/48] chore(deps): bump @aws-amplify/amplify-cli-core from 4.3.8 to 4.3.9 (#7788) Bumps [@aws-amplify/amplify-cli-core](https://github.com/aws-amplify/amplify-cli/tree/HEAD/packages/amplify-cli-core) from 4.3.8 to 4.3.9. - [Release notes](https://github.com/aws-amplify/amplify-cli/releases) - [Changelog](https://github.com/aws-amplify/amplify-cli/blob/dev/packages/amplify-cli-core/CHANGELOG.md) - [Commits](https://github.com/aws-amplify/amplify-cli/commits/@aws-amplify/amplify-cli-core@4.3.9/packages/amplify-cli-core) --- updated-dependencies: - dependency-name: "@aws-amplify/amplify-cli-core" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 34 ++++++++++++---------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index cb13c85ffaf..0861e00620d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "private": true, "dependencies": { - "@aws-amplify/amplify-cli-core": "^4.3.8", + "@aws-amplify/amplify-cli-core": "^4.3.9", "@aws-amplify/ui-react": "^6.1.12", "@docsearch/react": "3", "ajv": "^8.16.0", diff --git a/yarn.lock b/yarn.lock index 9afbdd468d5..66f41874147 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,19 +167,19 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@aws-amplify/amplify-cli-core@^4.3.8": - version "4.3.8" - resolved "https://registry.yarnpkg.com/@aws-amplify/amplify-cli-core/-/amplify-cli-core-4.3.8.tgz#308a384ba7d1251e11ea503b63ebdb7c32f52cbe" - integrity sha512-t+CqRR1nkMnh/lhD5CPOFD4aebP33ggvp0A7SyqcHCgkemEESYEakI/a7Bk7yiXaZ85/Ybq4s7EV2W/tczvt6Q== +"@aws-amplify/amplify-cli-core@^4.3.9": + version "4.3.9" + resolved "https://registry.yarnpkg.com/@aws-amplify/amplify-cli-core/-/amplify-cli-core-4.3.9.tgz#48feec280b22695dce144407beb7372713b1bb1a" + integrity sha512-J0YNhrajaziU38Amb+bh18VYk6gqNiV65QccwanQ99tRDen1iZ8IPJqR/k1FgnkgEbiocZKFSV0T/MeIoi0Ntg== dependencies: "@aws-amplify/amplify-cli-logger" "1.3.8" "@aws-amplify/amplify-function-plugin-interface" "1.12.1" "@aws-amplify/amplify-prompts" "2.8.6" - "@aws-amplify/graphql-transformer-interfaces" "^3.8.0" + "@aws-amplify/graphql-transformer-interfaces" "^3.9.0" "@aws-sdk/util-arn-parser" "^3.310.0" "@yarnpkg/lockfile" "^1.1.0" ajv "^6.12.6" - aws-cdk-lib "~2.80.0" + aws-cdk-lib "~2.129.0" chalk "^4.1.1" ci-info "^3.8.0" cli-table3 "^0.6.0" @@ -312,10 +312,10 @@ rxjs "^7.8.1" ulid "^2.3.0" -"@aws-amplify/graphql-transformer-interfaces@^3.8.0": - version "3.8.0" - resolved "https://registry.yarnpkg.com/@aws-amplify/graphql-transformer-interfaces/-/graphql-transformer-interfaces-3.8.0.tgz#6ca9baaab67b5639a67487d062fc81fc6ea83664" - integrity sha512-/VNL0x0CTGTQq/bcdytp7Q+o28nhIsvSZww2t/lpnF05My4EUDYHzmGoLIB6IB+1X1U6S+DiWVViqMPiLpkQNA== +"@aws-amplify/graphql-transformer-interfaces@^3.9.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@aws-amplify/graphql-transformer-interfaces/-/graphql-transformer-interfaces-3.10.0.tgz#263dcf3041d91f78539ebc08bfa1c7fb4e224989" + integrity sha512-8FOonxB58ytIXWIYNBGifUz4Y+6GW6QMajmdlMMjqlDIwdYbZg+HItPC22K2SewF93CgH1IOFYwNmZYk9L7wiQ== dependencies: graphql "^15.5.0" @@ -3537,17 +3537,7 @@ ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.12.0" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ajv@^8.16.0: +ajv@^8.0.1, ajv@^8.16.0: version "8.16.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== @@ -3850,7 +3840,7 @@ aws-amplify@^6.0.9: "@aws-amplify/storage" "6.0.16" tslib "^2.5.0" -aws-cdk-lib@2.80.0, aws-cdk-lib@~2.80.0: +aws-cdk-lib@2.80.0, aws-cdk-lib@~2.129.0: version "2.80.0" resolved "https://registry.yarnpkg.com/aws-cdk-lib/-/aws-cdk-lib-2.80.0.tgz#1118860637d33fab8f646551c29a75728404b64e" integrity sha512-PoqD3Yms5I0ajuTi071nTW/hpkH3XsdyZzn5gYsPv0qD7mqP3h6Qr+6RiGx+yQ1KcVFyxWdX15uK+DsC0KwvcQ== From 1e1c5db7dc8c63189c84320e71fa533d673d27c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 12:22:07 -0400 Subject: [PATCH 25/48] chore(deps): bump aws-actions/aws-secretsmanager-get-secrets (#7792) Bumps [aws-actions/aws-secretsmanager-get-secrets](https://github.com/aws-actions/aws-secretsmanager-get-secrets) from 2.0.3 to 2.0.5. - [Release notes](https://github.com/aws-actions/aws-secretsmanager-get-secrets/releases) - [Commits](https://github.com/aws-actions/aws-secretsmanager-get-secrets/compare/ff26a0aa6bd4dd5e51326b5afb3f5f6874c958c7...98c2d6bf1dd67c2575fa2bb14294aa64103d426c) --- updated-dependencies: - dependency-name: aws-actions/aws-secretsmanager-get-secrets dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/check_for_broken_links.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_for_broken_links.yml b/.github/workflows/check_for_broken_links.yml index f03377ccafc..181c6a1458b 100644 --- a/.github/workflows/check_for_broken_links.yml +++ b/.github/workflows/check_for_broken_links.yml @@ -32,7 +32,7 @@ jobs: role-to-assume: arn:aws:iam::464149486631:role/github_action_read_slack_webhook_url aws-region: us-west-2 - name: Read secrets from AWS Secrets Manager into environment variables - uses: aws-actions/aws-secretsmanager-get-secrets@ff26a0aa6bd4dd5e51326b5afb3f5f6874c958c7 # v2.0.3 + uses: aws-actions/aws-secretsmanager-get-secrets@98c2d6bf1dd67c2575fa2bb14294aa64103d426c # v2.0.5 with: secret-ids: | SLACK_WEBHOOK_URL From 96f9f1fd0cbdeb36143f45173a8d1836105420f0 Mon Sep 17 00:00:00 2001 From: Tuan Pham <103537251+phantumcode@users.noreply.github.com> Date: Thu, 11 Jul 2024 15:09:29 -0500 Subject: [PATCH 26/48] storage(android): update getURL options (#7736) * storage(android): update getURL options * add more code examples --- .../storage/download-files/index.mdx | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/pages/[platform]/build-a-backend/storage/download-files/index.mdx b/src/pages/[platform]/build-a-backend/storage/download-files/index.mdx index b7ea2e610ed..b2a3a6fb994 100644 --- a/src/pages/[platform]/build-a-backend/storage/download-files/index.mdx +++ b/src/pages/[platform]/build-a-backend/storage/download-files/index.mdx @@ -151,6 +151,84 @@ RxAmplify.Storage.getUrl(StoragePath.fromString("public/example")).subscribe( + +### Check the existence of a file + +When creating a downloadable URL, you can choose to check if the file exists by setting `validateObjectExistence` to +`true` in `AWSS3StorageGetPresignedUrlOptions`. If the file is inaccessible or does not exist, a `StorageException` is thrown. +This allows you to check if an object exists when generating the presigned URL, which you can then use to download +that object. + + + + +```java +AWSS3StorageGetPresignedUrlOptions options = AWSS3StorageGetPresignedUrlOptions + .builder() + .setValidateObjectExistence(true) + .build(); + +Amplify.Storage.getUrl( + StoragePath.fromString("public/example"), + options, + result -> Log.i("MyAmplifyApp", "Successfully generated: " + result.getUrl()), + error -> Log.e("MyAmplifyApp", "URL generation failure", error) +); +``` + + + +```kotlin +val options = AWSS3StorageGetPresignedUrlOptions + .builder() + .setValidateObjectExistence(true) + .build() + +Amplify.Storage.getUrl( + StoragePath.fromString("public/example"), + options, + { Log.i("MyAmplifyApp", "Successfully generated: ${it.url}") }, + { Log.e("MyAmplifyApp", "URL generation failure", it) } +) +``` + + +```kotlin +try { + val options = AWSS3StorageGetPresignedUrlOptions + .builder() + .setValidateObjectExistence(true) + .build() + + val url = Amplify.Storage.getUrl(StoragePath.fromString("public/example"), options).url + Log.i("MyAmplifyApp", "Successfully generated: $url") +} catch (error: StorageException) { + Log.e("MyAmplifyApp", "URL generation failure", error) +} +``` + + +```java +AWSS3StorageGetPresignedUrlOptions options = AWSS3StorageGetPresignedUrlOptions + .builder() + .setValidateObjectExistence(true) + .build(); + +RxAmplify.Storage.getUrl(StoragePath.fromString("public/example"), options).subscribe( + result -> Log.i("MyAmplifyApp", "Successfully generated: " + result.getUrl()), + error -> Log.e("MyAmplifyApp", "URL generation failure", error) +); +``` + + + +### More `getURL` options + +Option | Type | Description | +| -- | -- | ----------- | +| expires | Integer | Number of seconds before the URL expires | +| useAccelerateEndpoint | Boolean | Flag to configure use of acceleration mode | + From c454d67f5027fb03a09c6ff4977d3b397e8a20dd Mon Sep 17 00:00:00 2001 From: Dane Pilcher Date: Fri, 12 Jul 2024 11:02:33 -0600 Subject: [PATCH 27/48] Add Gen 2 SDL docs (#7793) * add gen 2 SDL docs * Update src/pages/[platform]/build-a-backend/data/data-modeling/index.mdx Co-authored-by: josef * Update src/pages/[platform]/build-a-backend/data/data-modeling/index.mdx Co-authored-by: josef * move support callout to migration page * update doc to state ddb-backed sources only * made updates to the sdl explanation --------- Co-authored-by: josef Co-authored-by: Nikhil Swaminathan --- .../data/data-modeling/index.mdx | 32 +++++++++++++++++++ .../start/migrate-to-gen2/index.mdx | 12 ++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/data/data-modeling/index.mdx b/src/pages/[platform]/build-a-backend/data/data-modeling/index.mdx index 607aa077d4c..2b4072013b8 100644 --- a/src/pages/[platform]/build-a-backend/data/data-modeling/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/data-modeling/index.mdx @@ -32,6 +32,7 @@ export function getStaticProps(context) { }; } +## Data modeling capabilities Every data model is defined as part of a data schema (`a.schema()`). You can enhance your data model with various fields, customize their identifiers, apply authorization rules, or model relationships. Every data model (`a.model()`) automatically provides create, read, update, and delete API operations as well as real-time subscription events. Below is a quick tour of the many functionalities you can add to your data model: @@ -84,3 +85,34 @@ export const data = defineData({ ``` + +## Gen 1 schema support + +If you are coming from Gen 1, you can continue to use the GraphQL Schema Definition Language (SDL) for defining your schema. However, we strongly recommend you use the TypeScript-first schema builder experience in your project as it provides type safety and is the recommended way of working with Amplify going forward. + + + +**Note:** Some features available in Gen 1 GraphQL SDL are not available in Gen 2. See the [feature matrix](/[platform]/start/migrate-to-gen2/#gen-1-vs-gen-2-feature-matrix) for features supported in Gen 2. + + + +```ts title="amplify/data/resource.ts" +import { defineData } from '@aws-amplify/backend'; + +const schema = /* GraphQL */` + type Todo @model @auth(rules: [{ allow: owner }]) { + content: String + isDone: Boolean + } +`; + +export const data = defineData({ + schema, + authorizationModes: { + defaultAuthorizationMode: "apiKey", + apiKeyAuthorizationMode: { + expiresInDays: 30, + }, + }, +}); +``` diff --git a/src/pages/[platform]/start/migrate-to-gen2/index.mdx b/src/pages/[platform]/start/migrate-to-gen2/index.mdx index 46794d16100..2ec72c4aee0 100644 --- a/src/pages/[platform]/start/migrate-to-gen2/index.mdx +++ b/src/pages/[platform]/start/migrate-to-gen2/index.mdx @@ -41,7 +41,7 @@ The tables below present a feature matrix for Gen 1 customers who are considerin ### Auth | Feature | Gen 1 | Gen 2 | -|---|---|---| +|---|---|---| | Configure username | Yes | Yes with CDK | | Configure email | Yes | Yes | | Configure phone number | Yes | Yes | @@ -92,7 +92,7 @@ The tables below present a feature matrix for Gen 1 customers who are considerin | hasOne | Yes | Yes | | hasMany | Yes | Yes | | belongsTo | Yes | Yes | -| manyToMany | Yes | Yes | +| manyToMany | Yes | No | | default | Yes | Yes | | **auth - model level** | | | | auth - public - apiKey | Yes | Yes | @@ -143,6 +143,8 @@ The tables below present a feature matrix for Gen 1 customers who are considerin | Custom GraphQL Transformer plugins | Yes | No | | MySQL and PostgreSQL support | No | Yes | | In-IDE end-to-end type safety | No | Yes | +| @hasOne, @hasMany, and @belongsTo on required fields | Yes | No | +| fields argument on @hasOne, @hasMany, and @belongsTo | Yes | No | ### Storage @@ -200,7 +202,7 @@ The tables below present a feature matrix for Gen 1 customers who are considerin | Feature | Gen 1 | Gen 2 | -|---|---|---| +|---|---|---| | REST API| Yes| No | Analytics| Yes| Yes with custom CDK | Geo| Yes| Yes with custom CDK @@ -212,7 +214,7 @@ The tables below present a feature matrix for Gen 1 customers who are considerin | Feature | Gen 1 | Gen 2 | -|---|---|---| +|---|---|---| | REST API| Yes| Yes with custom CDK | Analytics| Yes| Yes with custom CDK | Geo| No| No @@ -224,7 +226,7 @@ The tables below present a feature matrix for Gen 1 customers who are considerin | Feature | Gen 1 | Gen 2 | -|---|---|---| +|---|---|---| | REST API| Yes| Yes with custom CDK | Analytics| Yes| Yes with custom CDK | Geo| Yes| Yes with custom CDK From 729c600debb711e3701485c612a4fb3b1bbc04ad Mon Sep 17 00:00:00 2001 From: Chris Bonifacio Date: Fri, 12 Jul 2024 13:33:00 -0400 Subject: [PATCH 28/48] Cbonif/add-non-model-auth-section (#7817) * add callout for sql custom query/mutation return types with example * Merge branch 'main' of github.com:aws-amplify/docs * revert sql page change * revert change on gen 1 sql page --- .../data/customize-authz/index.mdx | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx index 7d24e395cb2..0d844331604 100644 --- a/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx @@ -144,6 +144,44 @@ const schema = a.schema({ }); ``` +### Non-model authorization rules + +**Non-model** types are any types added to the schema without using `a.model()`. These consist of modifiers such as `a.customType()`, `a.enum()`,`a.query()`, `a.mutation()`, or `a.subscription()`. + +Dynamic authorization rules such as `allow.owner()`, `allow.ownerDefinedIn()`, `allow.groupDefinedIn()` are not supported for **non-model** types. + +```ts +const schema = a.schema({ + // ... + listCustomType: a + .query() + .returns(a.ref("CustomType").array()) + .handler( + a.handler.custom({ + entry: "./handler.js", + }) + ) + .authorization((allow) => [ + // Static auth rules - Supported + allow.guest(), + allow.publicApiKey(), + allow.authenticated(), + allow.group("Admin"), + allow.groups(["Teacher", "Student"]), + + // Dynamic auth rules - Not supported + allow.owner(), + allow.ownerDefinedIn("owner"), + allow.ownersDefinedIn("otherOwners"), + allow.groupDefinedIn("group"), + allow.groupsDefinedIn("otherGroups"), + ]), +}); +``` + +There are TS warnings and validation checks in place that will cause a sandbox deployment to fail if unsupported auth rules are defined on custom queries and mutations. + + ### Configure multiple authorization rules When combining multiple authorization rules, they are "logically OR"-ed. In the following example: From 83e1a252ff81a2c671c32e410bbe31535165ceac Mon Sep 17 00:00:00 2001 From: Kethan sai Date: Fri, 12 Jul 2024 13:36:34 -0400 Subject: [PATCH 29/48] add auth permissions (#7796) * add auth permissions * fix accessibility error * fix heading --- .../auth/grant-access-to-auth-resources/index.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx b/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx index 6c9858236d8..0b8942e0470 100644 --- a/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/grant-access-to-auth-resources/index.mdx @@ -72,8 +72,10 @@ When you grant a function access to another resource in your Amplify backend it |forgetDevice | Grants permission to deregister any user's devices |
  • cognito-idp:AdminForgetDevice
|getDevice | Grants permission to get information about any user's devices |
  • cognito-idp:AdminGetDevice
|getUser | Grants permission to look up any user by user name |
  • cognito-idp:AdminGetUser
+|listUsers | Grants permission to list users and their basic details in the UserPool |
  • cognito-idp:ListUsers
|listDevices | Grants permission to list any user's remembered devices |
  • cognito-idp:AdminListDevices
|listGroupsForUser | Grants permission to list the groups that any user belongs to |
  • cognito-idp:AdminListGroupsForUser
+|listUsersInGroup | Grants permission to list users in the specified group |
  • cognito-idp:ListUsersInGroup
|removeUserFromGroup | Grants permission to remove any user from any group |
  • cognito-idp:AdminRemoveUserFromGroup
|resetUserPassword | Grants permission to reset any user's password |
  • cognito-idp:AdminResetUserPassword
|setUserMfaPreference | Grants permission to set any user's preferred MFA method |
  • cognito-idp:AdminSetUserMFAPreference
From 3372bcad5f26b38e96abfb2c37fb109ef8095f41 Mon Sep 17 00:00:00 2001 From: Chris Bonifacio Date: Fri, 12 Jul 2024 14:35:19 -0400 Subject: [PATCH 30/48] callout for mysql/postgres custom query return types (#7813) * add callout for sql custom query/mutation return types with example * add gen 1 example * shorten gen 2 example a bit * remove line breaks from gen 1 example * remove line break * Update index.mdx Co-authored-by: josef * Update src/pages/gen1/[platform]/build-a-backend/graphqlapi/connect-api-to-existing-database/index.mdx Co-authored-by: josef * remove ts import from bottom of page --------- Co-authored-by: josef --- .../connect-postgres-mysql-database/index.mdx | 25 +++++++++++++++++++ .../index.mdx | 13 ++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx b/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx index e968a0571ac..5b7f0242fd1 100644 --- a/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/connect-to-existing-data-sources/connect-postgres-mysql-database/index.mdx @@ -315,6 +315,30 @@ VALUES (:name, :address, ST_SetSRID(ST_MakePoint(:long, :lat), 4326)) + +The return type for custom queries and mutations expecting to return row data from SQL statements must be an array of the corresponding model. This is true even for custom `get` queries, where a single row is expected. + +**Example** + +```ts +getPostBySlug: a + .query() + .arguments({ + slug: a.string().required(), + }) + // highlight-start + .returns(a.ref("Post").array()) + // highlight-end + .handler( + a.handler.inlineSql(` + SELECT id, title, slug, content, created_at, updated_at + FROM posts + WHERE slug = :slug; + `) + ) +``` + + ## How does it work? The Amplify uses AWS Lambda functions to enable features like querying data from your database. To work properly, these Lambda functions need access to common logic and dependencies. @@ -407,3 +431,4 @@ To return the actual SQL error instead of a generic error from underlying API re ### My SQL table doesn't get generated when running `npx ampx generate schema-from-database` This is likely because the table doesn't have a designated primary key. A primary key is required for `npx ampx generate schema-from-database` to infer the table structure and create a create, read, update, and delete API. + diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/connect-api-to-existing-database/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/connect-api-to-existing-database/index.mdx index 1a09d114375..ddc737d0132 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/connect-api-to-existing-database/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/connect-api-to-existing-database/index.mdx @@ -498,8 +498,17 @@ type Mutation { - The return type for custom queries and mutations expecting row data must - be an array of the corresponding model. +The return type for custom queries and mutations expecting to return row data from SQL statements must be an array of the corresponding model. This is true even for custom `get` queries, where a single row is expected. + +**Example** + +```graphql title="schema.graphql" +type Query { + getPostBySlug(slug: String!): [Post] + @sql(statement: "SELECT * FROM posts WHERE slug = :slug LIMIT 1;") + @auth(rules: [{ allow: public }]) +} +``` From 539f79f00c92492a490e28d56aa04a7bb6b36254 Mon Sep 17 00:00:00 2001 From: Kazuki Hamasaki Date: Wed, 17 Jul 2024 01:29:19 +0900 Subject: [PATCH 31/48] Clarify Manual Loading of Environment Variables in Sandbox Environments (#7822) * Clarify Manual Loading of Environment Variables in Sandbox Environments * Update src/pages/[platform]/deploy-and-host/fullstack-branching/secrets-and-vars/index.mdx Co-authored-by: josef --------- Co-authored-by: josef --- cspell.json | 1 + .../fullstack-branching/secrets-and-vars/index.mdx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cspell.json b/cspell.json index 2e5736a237e..33fc3d5d2d9 100644 --- a/cspell.json +++ b/cspell.json @@ -537,6 +537,7 @@ "DocSets", "Donef", "Dont", + "dotenvx", "downcasting", "dropdown", "dynamoDB", diff --git a/src/pages/[platform]/deploy-and-host/fullstack-branching/secrets-and-vars/index.mdx b/src/pages/[platform]/deploy-and-host/fullstack-branching/secrets-and-vars/index.mdx index 34babc4924d..5b4b72f113a 100644 --- a/src/pages/[platform]/deploy-and-host/fullstack-branching/secrets-and-vars/index.mdx +++ b/src/pages/[platform]/deploy-and-host/fullstack-branching/secrets-and-vars/index.mdx @@ -152,4 +152,4 @@ console.log('REACT_APP_TEST_VARIABLE', process.env.REACT_APP_TEST_VARIABLE); ### Local environment -The same workflow applies when you're working on your local machine. First, add the environment variable in your `.env.local` file, and then reference the environment variable with `process.env`. +When working on your local machine, you must manually load the sandbox's environment variables. First, add the environment variable in your `.env.local` file. Then, a library such as [`@dotenvx/dotenvx`](https://www.npmjs.com/package/@dotenvx/dotenvx) can load the environment variables, which you can then reference with `process.env`. From 91dacfab123e5e8feb678d432a0ec30452443d9b Mon Sep 17 00:00:00 2001 From: josef Date: Tue, 16 Jul 2024 16:47:21 -0700 Subject: [PATCH 32/48] fix data env name in function example, ref #7825 (#7826) --- .../grant-lambda-function-access-to-api/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/grant-lambda-function-access-to-api/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/grant-lambda-function-access-to-api/index.mdx index a24d82cccd4..e0d025f2572 100644 --- a/src/pages/[platform]/build-a-backend/data/customize-authz/grant-lambda-function-access-to-api/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/customize-authz/grant-lambda-function-access-to-api/index.mdx @@ -77,7 +77,7 @@ const schema = a // highlight-end ``` -When configuring function access, the function will be provided the API endpoint as an environment variable named `_GRAPHQL_ENDPOINT`. The default name is `amplifyData_GRAPHQL_ENDPOINT` unless you have specified a different name in `defineData`. +When configuring function access, the function will be provided the API endpoint as an environment variable named `_GRAPHQL_ENDPOINT`, where `defineDataName` is transformed to SCREAMING_SNAKE_CASE. The default name is `AMPLIFY_DATA_GRAPHQL_ENDPOINT` unless you have specified a different name in `defineData`. From d230333fd2e69e71e558507199a591877bb76e1c Mon Sep 17 00:00:00 2001 From: Jay Raval Date: Wed, 17 Jul 2024 15:05:43 -0700 Subject: [PATCH 33/48] Update app id reference for CI/CD deployments (#7832) --- src/pages/[platform]/reference/cli-commands/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/[platform]/reference/cli-commands/index.mdx b/src/pages/[platform]/reference/cli-commands/index.mdx index 216be33f4e5..5a6a4d3d532 100644 --- a/src/pages/[platform]/reference/cli-commands/index.mdx +++ b/src/pages/[platform]/reference/cli-commands/index.mdx @@ -336,7 +336,7 @@ Generate React form components derived from your backend data models for your fr ### Usage ```bash title="Terminal" showLineNumbers={false} -npx ampx generate forms --branch $BRANCH_NAME --app-id $AMPLIFY_APP_ID --out-dir ./src +npx ampx generate forms --branch $BRANCH_NAME --app-id $AWS_APP_ID --out-dir ./src ``` ## npx ampx info @@ -389,5 +389,5 @@ Deploys the Amplify project in a CI/CD pipeline for a specified Amplify app and ### Usage ```bash title="Terminal" showLineNumbers={false} -npx ampx pipeline-deploy --branch $BRANCH_NAME --app-id $AMPLIFY_APP_ID +npx ampx pipeline-deploy --branch $BRANCH_NAME --app-id $AWS_APP_ID ``` From d955bc2bda3a11a173a932f6b005f428076eff75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Stormacq?= Date: Thu, 18 Jul 2024 17:30:26 +0200 Subject: [PATCH 34/48] fix(swift): updated concurrency in quickstart (#7828) --- .../[platform]/start/quickstart/index.mdx | 141 ++++++++++-------- 1 file changed, 76 insertions(+), 65 deletions(-) diff --git a/src/pages/[platform]/start/quickstart/index.mdx b/src/pages/[platform]/start/quickstart/index.mdx index 4670a5e92a5..831e20b7a53 100644 --- a/src/pages/[platform]/start/quickstart/index.mdx +++ b/src/pages/[platform]/start/quickstart/index.mdx @@ -1884,7 +1884,15 @@ Once you are done, add the API dependencies to your project. Select **File > Add ![Shows the Amplify API library for Swift selected](/images/lib/getting-started/ios/set-up-swift-9.png) -After adding the dependencies, update the `init` part of your `MyAmplifyAppApp.swift` file with the following code: +After adding the dependencies, update the `import` part of your `MyAmplifyAppApp.swift` file with the following code: + +```swift title="MyAmplifyAppApp.swift" +import Amplify +import AWSCognitoAuthPlugin +import AWSAPIPlugin +``` + +Then, update the `init()` part of your `MyAmplifyAppApp.swift` file with the following code: ```swift title="MyAmplifyAppApp.swift" init() { @@ -1902,31 +1910,31 @@ Create a new file called `TodoViewModel.swift` and the `createTodo` function wit ```swift title="TodoViewModel.swift" import Amplify +import SwiftUI @MainActor class TodoViewModel: ObservableObject { - func createTodo() { + func createTodo() async { let creationTime = Temporal.DateTime.now() let todo = Todo( - content: "Random Todo \(creationTime)", + content: "Random Todo \(creationTime.iso8601String)", isDone: false, createdAt: creationTime, updatedAt: creationTime ) - Task { - do { - let result = try await Amplify.API.mutate(request: .create(todo)) - switch result { - case .success(let todo): - print("Successfully created todo: \(todo)") - case .failure(let error): - print("Got failed result with \(error.errorDescription)") - } - } catch let error as APIError { - print("Failed to create todo: ", error) - } catch { - print("Unexpected error: \(error)") + do { + let result = try await Amplify.API.mutate(request: .create(todo)) + switch result { + case .success(let todo): + print("Successfully created todo: \(todo)") + todos.append(todo) + case .failure(let error): + print("Got failed result with \(error.errorDescription)") } + } catch let error as APIError { + print("Failed to create todo: ", error) + } catch { + print("Unexpected error: \(error)") } } } @@ -1946,23 +1954,21 @@ class TodoViewModel: ObservableObject { /// ... } - func listTodos() { + func listTodos() async { let request = GraphQLRequest.list(Todo.self) - Task { - do { - let result = try await Amplify.API.query(request: request) - switch result { - case .success(let todos): - print("Successfully retrieved list of todos: \(todos)") - self.todos = todos.elements - case .failure(let error): - print("Got failed result with \(error.errorDescription)") - } - } catch let error as APIError { - print("Failed to query list of todos: ", error) - } catch { - print("Unexpected error: \(error)") + do { + let result = try await Amplify.API.query(request: request) + switch result { + case .success(let todos): + print("Successfully retrieved list of todos: \(todos)") + self.todos = todos.elements + case .failure(let error): + print("Got failed result with \(error.errorDescription)") } + } catch let error as APIError { + print("Failed to query list of todos: ", error) + } catch { + print("Unexpected error: \(error)") } } } @@ -1987,8 +1993,7 @@ struct ContentView: View { } } Button(action: { - vm.createTodo() - vm.listTodos() + Task { await vm.createTodo() } }) { HStack { Text("Add a New Todo") @@ -2026,49 +2031,46 @@ class TodoViewModel: ObservableObject { // ... } - func deleteTodos(indexSet: IndexSet) { + func deleteTodos(indexSet: IndexSet) async { for index in indexSet { - let todo = todos[index] - Task { - do { - let result = try await Amplify.API.mutate(request: .delete(todo)) - switch result { - case .success(let todo): - print("Successfully deleted todo: \(todo)") - case .failure(let error): - print("Got failed result with \(error.errorDescription)") - } - } catch let error as APIError { - print("Failed to deleted todo: ", error) - } catch { - print("Unexpected error: \(error)") - } - } - } - } - - func updateTodo(todo: Todo) { - Task { do { - let result = try await Amplify.API.mutate(request: .update(todo)) + let todo = todos[index] + let result = try await Amplify.API.mutate(request: .delete(todo)) switch result { case .success(let todo): - print("Successfully updated todo: \(todo)") + print("Successfully deleted todo: \(todo)") + todos.remove(at: index) case .failure(let error): print("Got failed result with \(error.errorDescription)") } } catch let error as APIError { - print("Failed to updated todo: ", error) + print("Failed to deleted todo: ", error) } catch { print("Unexpected error: \(error)") } } } + + func updateTodo(todo: Todo) async { + do { + let result = try await Amplify.API.mutate(request: .update(todo)) + switch result { + case .success(let todo): + print("Successfully updated todo: \(todo)") + case .failure(let error): + print("Got failed result with \(error.errorDescription)") + } + } catch let error as APIError { + print("Failed to updated todo: ", error) + } catch { + print("Unexpected error: \(error)") + } + } } ``` -Update the `List` in the `ContentView.swift` file with the following code: +Update the `List` in the `ContentView.swift` file with code to fetch the todos when the View is displayed and to call `deleteTodos(indexSet:)` when the user left-swipe a todo. ```swift title="ContentView.swift" struct ContentView: View { @@ -2081,11 +2083,14 @@ struct ContentView: View { List { ForEach($vm.todos, id: \.id) { todo in TodoRow(vm: vm, todo: todo) - }.onDelete { indexSet in - vm.deleteTodos(indexSet: indexSet) - vm.listTodos() + } + .onDelete { indexSet in + Task { await vm.deleteTodos(indexSet: indexSet) } } } + .task { + await vm.listTodos() + } // ... Add new Todo button } } @@ -2096,6 +2101,8 @@ struct ContentView: View { Lastly, create a new file called `TodoRow.swift` with the following code: ```swift title="TodoRow.swift" +import SwiftUI + struct TodoRow: View { @ObservedObject var vm: TodoViewModel @Binding var todo: Todo @@ -2104,15 +2111,19 @@ struct TodoRow: View { Toggle(isOn: $todo.isDone) { Text(todo.content ?? "") } - .toggleStyle(SwitchToggleStyle()) + .toggleStyle(.switch) .onChange(of: todo.isDone) { _, newValue in var updatedTodo = todo updatedTodo.isDone = newValue - vm.updateTodo(todo: updatedTodo) - vm.listTodos() + Task { await vm.updateTodo(todo: updatedTodo) } } } } + +#Preview { + @State var todo = Todo(content: "Hello Todo World 20240706T15:23:42.256Z", isDone: false) + return TodoRow(vm: TodoViewModel(), todo: $todo) +} ``` This will update the UI to show a toggle to update the todo `isDone` and a swipe to delete the todo. Now if you run the application you should see the following flow. From fa7c5e1deb0a706080bd0bb4331ce3200e2b35b3 Mon Sep 17 00:00:00 2001 From: Michael Law <1365977+lawmicha@users.noreply.github.com> Date: Thu, 18 Jul 2024 13:54:18 -0400 Subject: [PATCH 35/48] chore(android): Update versions.ts - Android SDK 2.76.0(#7833) --- src/constants/versions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/versions.ts b/src/constants/versions.ts index 70b7f83baf0..9d46720b5a8 100644 --- a/src/constants/versions.ts +++ b/src/constants/versions.ts @@ -4,7 +4,7 @@ export const versions = { ANDROID_V1_VERSION: '1.38.8', ANDROID_V1_GEO_VERSION: '1.0.1', ANDROID_V1_KOTLIN_VERSION: '0.22.8', - ANDROID_SDK_VERSION: '2.75.2', + ANDROID_SDK_VERSION: '2.76.0', KOTLIN_SDK_VERSION: '1.2.8', ANDROID_AUTHENTICATOR_VERSION: '1.2.0' }; From 0863c08c9c99eb246a46196a1283049ea7460dab Mon Sep 17 00:00:00 2001 From: Sebastian Villena <97059974+ruisebas@users.noreply.github.com> Date: Thu, 18 Jul 2024 18:32:25 -0400 Subject: [PATCH 36/48] feat(Swift): Adding SubpathStrategy documentation for Storage.List (#7831) --- src/fragments/lib/storage/ios/list.mdx | 194 +++++++++++++++--- .../storage/list-files/index.mdx | 135 +++++++++++- 2 files changed, 293 insertions(+), 36 deletions(-) diff --git a/src/fragments/lib/storage/ios/list.mdx b/src/fragments/lib/storage/ios/list.mdx index a2d9cca05b2..c04616cd88a 100644 --- a/src/fragments/lib/storage/ios/list.mdx +++ b/src/fragments/lib/storage/ios/list.mdx @@ -1,15 +1,15 @@ -You can list all of the objects uploaded under a given prefix by setting the `pageSize`. If the `pageSize` is set lower than the total file size available, A single `Storage.list` call only returns a subset of all the files. To list all the files with multiple calls, the user can use the `nextToken` from the previous call response. +You can list files without having to download all the files. You can do this by using the list API from the Amplify Library for Storage. -#### With StoragePath +## With StoragePath + +The following example lists all objects inside the `public/photos/` path: ```swift -let options = StorageListRequest.Options(pageSize: 1000) let listResult = try await Amplify.Storage.list( - path: .fromString("public/example/path"), - options: options + path: .fromString("public/photos/") ) listResult.items.forEach { item in print("Path: \(item.path)") @@ -22,10 +22,8 @@ listResult.items.forEach { item in ```swift let sink = Amplify.Publisher.create { - let options = StorageListRequest.Options(pageSize: 1000) try await Amplify.Storage.list( - path: .fromString("public/example/path"), - options: options + path: .fromString("public/photos/") ) }.sink { if case let .failure(error) = $0 { @@ -33,7 +31,6 @@ let sink = Amplify.Publisher.create { } } receiveValue: { listResult in - print("Completed") listResult.items.forEach { item in print("Path: \(item.path)") } @@ -44,14 +41,135 @@ receiveValue: { listResult in -#### With Key (Deprecated) + +Note the trailing slash `/` in the given path. + +If you had used `public/photos` as path, it would also match against files like `public/photos01.jpg`. + + +### Exclude results from nested subpaths + +By default, the `list` API will return all objects contained within the given path, including objects inside nested subpaths. + +For example, the previous `public/photos/` path would include these objects: + +```bash +Path: public/photos/photo1.jpg +Path: public/photos/vacation/photo1.jpg +Path: public/photos/thumbnails/photo1.jpg +``` + +In order to exclude objects within the `vacation` and `thumbnails` subpaths, you can set the `subpathStrategy` option to `.exclude`: + + + + + +```swift +let listResult = try await Amplify.Storage.list( + path: .fromString("public/photos/"), + options: .init( + subpathStrategy: .exclude + ) +) +listResult.items.forEach { item in + print("Path: \(item.path)") +} +listResult.excludedSubpaths.forEach { subpath in + print("Subpath: \(subpath)") +} +``` + + + + + +```swift +let sink = Amplify.Publisher.create { + try await Amplify.Storage.list( + path: .fromString("public/photos/"), + options: .init( + subpathStrategy: .exclude + ) + ) +}.sink { + if case let .failure(error) = $0 { + print("Failed: \(error)") + } +} +receiveValue: { listResult in + listResult.items.forEach { item in + print("Path: \(item.path)") + } + listResult.excludedSubpaths.forEach { subpath in + print("Subpath: \(subpath)") + } +} +``` + + + + + +The response will only include objects within the `public/photos/` path and will also provide a list of the excluded subpaths: + +```bash +Path: public/photos/photo01.jpg +Subpath: public/photos/vacation/ +Subpath: public/photos/thumbnails/ +``` + +The default delimiter character is `"/"`, but this can be changed by supplying a custom delimiter: + + + + + +```swift +let listResult = try await Amplify.Storage.list( + path: .fromString("public/photos-"), + options: .init( + subpathStrategy: .exclude(delimitedBy: "-") + ) +) +``` + + + + + +```swift +let sink = Amplify.Publisher.create { + try await Amplify.Storage.list( + path: .fromString("public/photos-"), + options: .init( + subpathStrategy: .exclude(delimitedBy: "-") + ) + ) +}.sink { + if case let .failure(error) = $0 { + print("Failed: \(error)") + } +} +receiveValue: { listResult in + // ... +} +``` + + + + + + +## With Key (Deprecated) +The following example lists all public files: + ```swift -let options = StorageListRequest.Options(pageSize: 1000) -let listResult = try await Amplify.Storage.list(options: options) +let listResult = try await Amplify.Storage.list() listResult.items.forEach { item in print("Key: \(item.key)") } @@ -63,8 +181,7 @@ listResult.items.forEach { item in ```swift let sink = Amplify.Publisher.create { - let options = StorageListRequest.Options(pageSize: 1000) - try await Amplify.Storage.list(options: options) + try await Amplify.Storage.list() }.sink { if case let .failure(error) = $0 { print("Failed: \(error)") @@ -89,10 +206,14 @@ You can also list private or protected files by passing options. For example, to ```swift -let options = StorageListRequest.Options(accessLevel: .protected, targetIdentityId: "otherUserID", pageSize: 1000) -let listResult = try await Amplify.Storage.list(options: options) +let listResult = try await Amplify.Storage.list( + options: .init( + accessLevel: .protected, + targetIdentityId: "otherUserID" + ) +) listResult.items.forEach { item in - print("Path: \(item.path)") + print("Key: \(item.key)") } ``` @@ -102,17 +223,21 @@ listResult.items.forEach { item in ```swift let sink = Amplify.Publisher.create { - let options = StorageListRequest.Options(accessLevel: .protected, targetIdentityId: "otherUserID", pageSize: 1000) - try await Amplify.Storage.list(options: options) + let options = StorageListRequest.Options) + try await Amplify.Storage.list( + options: .init( + accessLevel: .protected, + targetIdentityId: "otherUserID" + ) + ) }.sink { if case let .failure(error) = $0 { print("Failed: \(error)") } } receiveValue: { listResult in - print("Completed") listResult.items.forEach { item in - print("Path: \(item.path)") + print("Key: \(item.path)") } } ``` @@ -128,8 +253,11 @@ If you like limit the response to keys that begin with the specified path provid ```swift -let options = StorageListRequest.Options(path: "path") -let listResult = try await Amplify.Storage.list(options: options) +let listResult = try await Amplify.Storage.list( + options: .init( + path: "path" + ) +) listResult.items.forEach { item in print("Key: \(item.key)") } @@ -141,15 +269,17 @@ listResult.items.forEach { item in ```swift let sink = Amplify.Publisher.create { - let options = StorageListRequest.Options(path: "path") - try await Amplify.Storage.list(options: options) + try await Amplify.Storage.list( + options: .init( + path: "path" + ) + ) }.sink { if case let .failure(error) = $0 { print("Failed: \(error)") } } receiveValue: { listResult in - print("Completed") listResult.items.forEach { item in print("Key: \(item.key)") } @@ -158,4 +288,14 @@ receiveValue: { listResult in - \ No newline at end of file + + +## More `list` options + +| Option | Type | Description | +| --- | --- | --- | +| pageSize | UInt | Number between 1 and 1,000 that indicates the limit of how many entries to fetch when retrieving file lists from the server | +| nextToken | String | String indicating the page offset at which to resume a listing. | + + +If the `pageSize` is set lower than the total file size available, a single `list` call only returns a subset of all the files. To list all the files with multiple calls, the user can use the `nextToken` value from the previous response. diff --git a/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx b/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx index 3eb8a2613a3..81258be3cf6 100644 --- a/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx +++ b/src/pages/[platform]/build-a-backend/storage/list-files/index.mdx @@ -29,7 +29,7 @@ export function getStaticProps(context) { }; } -You can list files without having to download all the files. You can do this by using the `list` API from the Amplify Library for Storage. You can also get properties individually for a file using the getProperties API. +You can list files without having to download all the files. You can do this by using the `list` API from the Amplify Library for Storage. You can also get properties individually for a file using the getProperties API. ## List Files @@ -294,17 +294,15 @@ RxAmplify.Storage.list(StoragePath.fromString("public/"), options) -You can list all of the objects uploaded under a given path by setting the `pageSize`. If the `pageSize` is set lower than the total file size available, A single `Storage.list` call only returns a subset of all the files. To list all the files with multiple calls, the user can use the `nextToken` from the previous call response. +The following example lists all objects inside the `public/photos/` path: ```swift -let options = StorageListRequest.Options(pageSize: 1000) let listResult = try await Amplify.Storage.list( - path: .fromString("public/example/path"), - options: options + path: .fromString("public/photos/") ) listResult.items.forEach { item in print("Path: \(item.path)") @@ -317,10 +315,8 @@ listResult.items.forEach { item in ```swift let sink = Amplify.Publisher.create { - let options = StorageListRequest.Options(pageSize: 1000) try await Amplify.Storage.list( - path: .fromString("public/example/path"), - options: options + path: .fromString("public/photos/") ) }.sink { if case let .failure(error) = $0 { @@ -328,7 +324,6 @@ let sink = Amplify.Publisher.create { } } receiveValue: { listResult in - print("Completed") listResult.items.forEach { item in print("Path: \(item.path)") } @@ -339,6 +334,125 @@ receiveValue: { listResult in + +Note the trailing slash `/` in the given path. + +If you had used `public/photos` as path, it would also match against files like `public/photos01.jpg`. + + +### Exclude results from nested subpaths + +By default, the `list` API will return all objects contained within the given path, including objects inside nested subpaths. + +For example, the previous `public/photos/` path would include these objects: + +```bash +Path: public/photos/photo1.jpg +Path: public/photos/vacation/photo1.jpg +Path: public/photos/thumbnails/photo1.jpg +``` + +In order to exclude objects within the `vacation` and `thumbnails` subpaths, you can set the `subpathStrategy` option to `.exclude`: + + + + + +```swift +let listResult = try await Amplify.Storage.list( + path: .fromString("public/photos/"), + options: .init( + subpathStrategy: .exclude + ) +) +listResult.items.forEach { item in + print("Path: \(item.path)") +} +listResult.excludedSubpaths.forEach { subpath in + print("Subpath: \(subpath)") +} +``` + + + + + +```swift +let sink = Amplify.Publisher.create { + try await Amplify.Storage.list( + path: .fromString("public/photos/"), + options: .init( + subpathStrategy: .exclude + ) + ) +}.sink { + if case let .failure(error) = $0 { + print("Failed: \(error)") + } +} +receiveValue: { listResult in + listResult.items.forEach { item in + print("Path: \(item.path)") + } + listResult.excludedSubpaths.forEach { subpath in + print("Subpath: \(subpath)") + } +} +``` + + + + + +The response will only include objects within the `public/photos/` path and will also provide a list of the excluded subpaths: + +```bash +Path: public/photos/photo01.jpg +Subpath: public/photos/vacation/ +Subpath: public/photos/thumbnails/ +``` + +The default delimiter character is `"/"`, but this can be changed by supplying a custom delimiter: + + + + + +```swift +let listResult = try await Amplify.Storage.list( + path: .fromString("public/photos-"), + options: .init( + subpathStrategy: .exclude(delimitedBy: "-") + ) +) +``` + + + + + +```swift +let sink = Amplify.Publisher.create { + try await Amplify.Storage.list( + path: .fromString("public/photos-"), + options: .init( + subpathStrategy: .exclude(delimitedBy: "-") + ) + ) +}.sink { + if case let .failure(error) = $0 { + print("Failed: \(error)") + } +} +receiveValue: { listResult in + // ... +} +``` + + + + + ### More `list` options | Option | Type | Description | @@ -346,6 +460,9 @@ receiveValue: { listResult in | pageSize | UInt | Number between 1 and 1,000 that indicates the limit of how many entries to fetch when retrieving file lists from the server | | nextToken | String | String indicating the page offset at which to resume a listing. | + +If the `pageSize` is set lower than the total file size available, a single `list` call only returns a subset of all the files. To list all the files with multiple calls, the user can use the `nextToken` value from the previous response. + From 4a8ce41284db8705a706cd38dfd6ce6051f06416 Mon Sep 17 00:00:00 2001 From: jacoblogan Date: Mon, 22 Jul 2024 11:02:20 -0700 Subject: [PATCH 37/48] Add Gen1 banner to getting started pages (#7839) * add Gen1 Banner to all gen 1 getting started pages * update link location and add banner to how amplify works --------- Co-authored-by: Jacob Logan --- src/components/Callout/Callout.tsx | 13 ++++++++++-- .../Callout/__tests__/Callout.test.tsx | 13 ++++++++++++ src/components/Gen1Banner/Gen1Banner.tsx | 20 +++++++++++++++++++ src/components/Gen1Banner/index.ts | 1 + src/components/Layout/Layout.tsx | 11 ++++++++++ 5 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/components/Gen1Banner/Gen1Banner.tsx create mode 100644 src/components/Gen1Banner/index.ts diff --git a/src/components/Callout/Callout.tsx b/src/components/Callout/Callout.tsx index 0d40770c0e2..b1b785ea002 100644 --- a/src/components/Callout/Callout.tsx +++ b/src/components/Callout/Callout.tsx @@ -3,12 +3,21 @@ import { Message, View } from '@aws-amplify/ui-react'; interface CalloutProps { info?: boolean; warning?: boolean; + backgroundColor?: string; children?: React.ReactNode; } -export const Callout = ({ warning, children }: CalloutProps) => { +export const Callout = ({ + warning, + backgroundColor, + children +}: CalloutProps) => { return ( - + {children} ); diff --git a/src/components/Callout/__tests__/Callout.test.tsx b/src/components/Callout/__tests__/Callout.test.tsx index 260069dc805..6b5b32f5d73 100644 --- a/src/components/Callout/__tests__/Callout.test.tsx +++ b/src/components/Callout/__tests__/Callout.test.tsx @@ -19,4 +19,17 @@ describe('Callout', () => { consoleErrorFn.mockRestore(); }); + + it('should pass the backgroundColor through to the Message component', async () => { + const child =
Callout Child
; + const ele = render( + + {child} + + ); + + const styles = getComputedStyle(ele.container.children[0]); + console.log(styles); + expect(styles.backgroundColor).toBe('red'); + }); }); diff --git a/src/components/Gen1Banner/Gen1Banner.tsx b/src/components/Gen1Banner/Gen1Banner.tsx new file mode 100644 index 00000000000..c39fff78707 --- /dev/null +++ b/src/components/Gen1Banner/Gen1Banner.tsx @@ -0,0 +1,20 @@ +import { Callout } from '@/components/Callout'; +import Link from 'next/link'; +import classNames from 'classnames'; + +export const Gen1Banner = ({ currentPlatform }) => { + return ( + + For new Amplify apps, we recommend using Amplify Gen 2. You can learn more + in our{' '} + + Gen 2 Docs + + . + + ); +}; diff --git a/src/components/Gen1Banner/index.ts b/src/components/Gen1Banner/index.ts new file mode 100644 index 00000000000..36949bf086f --- /dev/null +++ b/src/components/Gen1Banner/index.ts @@ -0,0 +1 @@ +export { Gen1Banner } from './Gen1Banner'; diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index b4404b201aa..4b73cc128cc 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -35,6 +35,7 @@ import { NEXT_PREVIOUS_SECTIONS } from '@/components/NextPrevious'; import { Modal } from '@/components/Modal'; +import { Gen1Banner } from '@/components/Gen1Banner'; export const Layout = ({ children, @@ -127,6 +128,13 @@ export const Layout = ({ } }, 20); + const isGen1GettingStarted = /\/gen1\/\w+\/start\/getting-started\//.test( + asPathWithNoHash + ); + const isGen1HowAmplifyWorks = /\/gen1\/\w+\/how-amplify-works\//.test( + asPathWithNoHash + ); + useEffect(() => { const headings: HeadingInterface[] = []; @@ -254,6 +262,9 @@ export const Layout = ({ {useCustomTitle ? null : ( {pageTitle} )} + {(isGen1GettingStarted || isGen1HowAmplifyWorks) && ( + + )} {children} {showNextPrev && }
From 8ab9f6326b575d359091dea5206d6bf238e884b8 Mon Sep 17 00:00:00 2001 From: Katie Goines <30757403+katiegoines@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:58:56 -0700 Subject: [PATCH 38/48] remove temporary disabling of copy-code button (#7835) Co-authored-by: katiegoines --- src/components/MDXComponents/MDXCopyCodeButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/MDXComponents/MDXCopyCodeButton.tsx b/src/components/MDXComponents/MDXCopyCodeButton.tsx index 8c49bda7188..d3502af303d 100644 --- a/src/components/MDXComponents/MDXCopyCodeButton.tsx +++ b/src/components/MDXComponents/MDXCopyCodeButton.tsx @@ -33,7 +33,6 @@ export const MDXCopyCodeButton = ({