diff --git a/.circleci/config.yml b/.circleci/config.yml index fd8bab0d98d..a8f56b33551 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -344,6 +344,7 @@ jobs: command: | mv .yarnrc ._yarnrc yarn + - run: yarn bootstrap - run: yarn build # storing yarn.lock as an artifact, so that we can quickly get a dependency diff # with the last working build in the event that some upstream deps break the build in the future diff --git a/.github/ISSUE_TEMPLATE/5.bug_report.md b/.github/ISSUE_TEMPLATE/5.bug_report.md deleted file mode 100644 index fd26f14f260..00000000000 --- a/.github/ISSUE_TEMPLATE/5.bug_report.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: Old Bug report -about: Create a report to help us improve -title: '' -labels: to-be-reproduced -assignees: '' ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Code Snippet** -Please provide a code snippet or a link to sample code of the issue you are experiencing to help us reproduce the issue. (Be sure to remove any sensitive data) - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**What is Configured?** -If applicable, please provide what is configured for Amplify CLI: - -- Which steps did you follow via Amplify CLI when configuring your resources. -- Which resources do you have configured? - - If applicable, please provide your `aws-exports` file: - ``` - const awsmobile = { - "aws_project_region": "us-east-1", - "aws_cognito_identity_pool_id": "us-east-1:xxx-xxxx-xxxx-xxxx-xxxxxxxx", - "aws_cognito_region": "us-east-1", - "aws_user_pools_id": "us-east-1_xxx", - "aws_user_pools_web_client_id": "xxxx", - "oauth": {} - }; - ``` - - If applicable, please provide your manual configuration example: - ``` - { - Auth: { - identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab', - region: 'XX-XXXX-X', - identityPoolRegion: 'XX-XXXX-X', - userPoolId: 'XX-XXXX-X_abcd1234', - userPoolWebClientId: 'a1b2c3d4e5f6g7h8i9j0k1l2m3', - mandatorySignIn: false, - authenticationFlowType: 'USER_PASSWORD_AUTH', - oauth: { - domain: 'your_cognito_domain', - scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'], - redirectSignIn: 'http://localhost:3000/', - redirectSignOut: 'http://localhost:3000/', - responseType: 'code' // or 'token', note that REFRESH token will only be generated when the responseType is code - } - } - } - ``` -- If applicable, provide more configuration data, for example for Amazon Cognito, run `aws cognito-idp describe-user-pool --user-pool-id us-west-2_xxxxxx` (Be sure to remove any sensitive data) - -
- Environment - - - -``` -npx envinfo --system --binaries --browsers --npmPackages --npmGlobalPackages -``` - -
- -**Smartphone (please complete the following information):** - -- Device: [e.g. iPhone6] -- OS: [e.g. iOS8.1] -- Browser [e.g. stock browser, safari] -- Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. - -**_You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app._** diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 1ed20431c67..4ad66549f48 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: + - name: Amplify UI Component Issue? + url: https://github.com/aws-amplify/amplify-ui/issues/new/choose + about: Open an issue in the Amplify-UI repository - name: Usage Question url: https://github.com/aws-amplify/amplify-js/discussions about: Ask a question about AWS Amplify usage diff --git a/.github/workflows/lock.yaml b/.github/workflows/lock.yaml index c0a1caffe9d..16d97cf42ca 100644 --- a/.github/workflows/lock.yaml +++ b/.github/workflows/lock.yaml @@ -2,7 +2,7 @@ name: 'Lock Threads' on: schedule: - - cron: '0 * * * *' + - cron: '30 1 * * *' jobs: lock: diff --git a/README.md b/README.md index 66ccdd182e3..6a1f2e5c059 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@

- Discord Chat + Discord Chat @@ -17,7 +17,7 @@

-### Reporting Bugs/Feature Requests +### Reporting Bugs / Feature Requests [![Open Bugs](https://img.shields.io/github/issues/aws-amplify/amplify-js/bug?color=d73a4a&label=bugs)](https://github.com/aws-amplify/amplify-js/issues?q=is%3Aissue+is%3Aopen+label%3Abug) [![Feature Requests](https://img.shields.io/github/issues/aws-amplify/amplify-js/feature-request?color=ff9001&label=feature%20requests)](https://github.com/aws-amplify/amplify-js/issues?q=is%3Aissue+label%3Afeature-request+is%3Aopen) @@ -29,66 +29,34 @@ AWS Amplify provides a declarative and easy-to-use interface across different ca Our default implementation works with Amazon Web Services (AWS), but AWS Amplify is designed to be open and pluggable for any custom backend or service. -## Notice: - -### Amplify 4.x.x has breaking changes for React Native. Please see the breaking changes below: - -- If you are using React Native or Expo, you will need add `@react-native-async-storage/async-storage` as a dependency to your application, in addition to the other React Native dependencies: - -``` -// React Native -yarn add aws-amplify amazon-cognito-identity-js @react-native-community/netinfo @react-native-async-storage/async-storage -npx pod-install - -// Expo -yarn add aws-amplify @react-native-community/netinfo @react-native-async-storage/async-storage -``` - -### Amplify 3.x.x has breaking changes. Please see the breaking changes below: - -- `AWS.credentials` and `AWS.config` don’t exist anymore anywhere in Amplify JavaScript. - - Both options will not be available to use in version 3. You will not be able to use and set your own credentials. - - For more information on this change, please see the [AWS SDK for JavaScript v3](https://github.com/aws/aws-sdk-js-v3/#configuration) -- `aws-sdk@2.x` has been removed from `Amplify@3.x.x` in favor of [version 3 of aws-sdk-js](https://github.com/aws/aws-sdk-js-v3). We recommend to migrate to [aws-sdk-js-v3](https://github.com/aws/aws-sdk-js-v3) if you rely on AWS services that are not supported by Amplify, since [aws-sdk-js-v3](https://github.com/aws/aws-sdk-js-v3) is imported modularly. - -If you can't migrate to [aws-sdk-js-v3](https://github.com/aws/aws-sdk-js-v3) or rely on aws-sdk@2.x, you will need to import it separately. - -- If you are using exported paths within your Amplify JS application, (e.g. `import from "@aws-amplify/analytics/lib/Analytics"`) this will now break and no longer will be supported. You will need to change to named imports: - - ```js - import { Analytics } from 'aws-amplify'; - ``` - -- If you are using categories as `Amplify.`, this will no longer work and we recommend to import the category you are needing to use: - - ```js - import { Auth } from 'aws-amplify'; - ``` - -### Features / APIs - -- [**Authentication**](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js): APIs and building blocks for developers who want to create user authentication experiences. -- [**Analytics**](https://docs.amplify.aws/lib/analytics/getting-started/q/platform/js): Easily collect analytics data for your app. Analytics data includes user sessions and other custom events that you want to track in your app. -- [**REST API**](https://docs.amplify.aws/lib/restapi/getting-started/q/platform/js): Provides a simple solution when making HTTP requests. It provides an automatic, lightweight signing process which complies with AWS Signature Version 4. -- [**GraphQL API**](https://docs.amplify.aws/lib/graphqlapi/getting-started/q/platform/js): Interact with your GraphQL server or AWS AppSync API with an easy-to-use & configured GraphQL client. -- [**DataStore**](https://docs.amplify.aws/lib/datastore/getting-started/q/platform/js): A programming model for leveraging shared and distributed data without writing additional code for offline and online scenarios, which makes working with distributed, cross-user data just as simple as working with local-only data. -- [**Storage**](https://docs.amplify.aws/lib/storage/getting-started/q/platform/js): Provides a simple mechanism for managing user content for your app in public, protected or private storage buckets. -- [**Push Notifications**](https://docs.amplify.aws/lib/push-notifications/getting-started/q/platform/js): Allows you to integrate push notifications in your app with Amazon Pinpoint targeting and campaign management support. -- [**Interactions**](https://docs.amplify.aws/lib/interactions/getting-started/q/platform/js#interactions-with-aws): Create conversational bots powered by deep learning technologies. -- [**PubSub**](https://docs.amplify.aws/lib/pubsub/getting-started/q/platform/js): Provides connectivity with cloud-based message-oriented middleware. -- [**Internationalization**](https://docs.amplify.aws/lib/utilities/i18n/q/platform/js): A lightweight internationalization solution. -- [**Cache**](https://docs.amplify.aws/lib/utilities/cache/q/platform/js): Provides a generic LRU cache for JavaScript developers to store data with priority and expiration settings. -- [**Predictions**](https://docs.amplify.aws/lib/predictions/getting-started/q/platform/js): Provides a solution for using AI and ML cloud services to enhance your application. - -#### Visit our [Web Site](https://docs.amplify.aws/) to learn more about AWS Amplify. +#### Visit our [Documentation site](https://docs.amplify.aws/) to learn more about AWS Amplify. Please see our [Amplify JavaScript](https://docs.amplify.aws/lib/q/platform/js/) page within our Documentation site for information around the full list of features we support. -- [Documentation](https://docs.amplify.aws/) - [Demo Applications](https://github.com/aws-amplify/amplify-js-samples) - [Contributing](https://github.com/aws-amplify/amplify-js/blob/main/CONTRIBUTING.md) +### Features + +| Category | AWS Provider | Description | +| ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| [**Authentication**](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js) | [Amazon Cognito](https://aws.amazon.com/cognito/) | APIs and Building blocks to create Authentication experiences. | +| [**Analytics**](https://docs.amplify.aws/lib/analytics/getting-started/q/platform/js) | [Amazon Pinpoint](https://aws.amazon.com/pinpoint/) | Collect Analytics data for your application including tracking user sessions. | +| [**REST API**](https://docs.amplify.aws/lib/restapi/getting-started/q/platform/js) | [Amazon API Gateway](https://aws.amazon.com/api-gateway/) | Sigv4 signing and AWS auth for API Gateway and other REST endpoints. | +| [**GraphQL API**](https://docs.amplify.aws/lib/graphqlapi/getting-started/q/platform/js) | [AWS AppSync](https://aws.amazon.com/appsync/) | Interact with your GraphQL or AWS AppSync endpoint(s). | +| [**DataStore**](https://docs.amplify.aws/lib/datastore/getting-started/q/platform/js) | [AWS AppSync](https://aws.amazon.com/appsync/) | Programming model for shared and distributed data, with simple online/offline synchronization. | +| [**Storage**](https://docs.amplify.aws/lib/storage/getting-started/q/platform/js) | [Amazon S3](https://aws.amazon.com/s3/) | Manages content in public, protected, private storage buckets. | +| [**Geo (Developer preview)**](https://docs.amplify.aws/lib/geo/getting-started/q/platform/js) | [Amazon Location Service](https://aws.amazon.com/location/) | Provides APIs and UI components for maps and location search for JavaScript-based web apps. | +| [**Push Notifications**](https://docs.amplify.aws/lib/push-notifications/getting-started/q/platform/js) | [Amazon Pinpoint](https://aws.amazon.com/pinpoint/) | Allows you to integrate push notifications in your app with Amazon Pinpoint targeting and campaign management support. | +| [**Interactions**](https://docs.amplify.aws/lib/interactions/getting-started/q/platform/js#interactions-with-aws) | [Amazon Lex](https://aws.amazon.com/lex/) | Create conversational bots powered by deep learning technologies. | +| [**PubSub**](https://docs.amplify.aws/lib/pubsub/getting-started/q/platform/js) | [AWS IoT](https://aws.amazon.com/iot/) | Provides connectivity with cloud-based message-oriented middleware. | +| [**Internationalization**](https://docs.amplify.aws/lib/utilities/i18n/q/platform/js) | --- | A lightweight internationalization solution. | +| [**Cache**](https://docs.amplify.aws/lib/utilities/cache/q/platform/js) | --- | Provides a generic LRU cache for JavaScript developers to store data with priority and expiration settings. | +| [**Predictions**](https://docs.amplify.aws/lib/predictions/getting-started/q/platform/js) | Various\* | Connect your app with machine learning services like NLP, computer vision, TTS, and more. | + +- Predictions utilizes a range of Amazon's Machine Learning services, including: Amazon Comprehend, Amazon Polly, Amazon Rekognition, Amazon Textract, and Amazon Translate. + ## Getting Started -AWS Amplify is available as `aws-amplify` package on [npm](https://www.npmjs.com/). +AWS Amplify is available as `aws-amplify` package on [npm](https://www.npmjs.com/package/aws-amplify). **Web** @@ -121,3 +89,39 @@ $ npm install aws-amplify-react-native --save ``` Visit our [Installation Guide for React Native](https://docs.amplify.aws/start/q/integration/react-native) to start building your web app. + +## Notice: + +### Amplify 4.x.x has breaking changes for React Native. Please see the breaking changes below: + +- If you are using React Native or Expo, you will need to add `@react-native-async-storage/async-storage` as a dependency to your application, in addition to the other React Native dependencies: + +``` +// React Native +yarn add aws-amplify amazon-cognito-identity-js @react-native-community/netinfo @react-native-async-storage/async-storage +npx pod-install + +// Expo +yarn add aws-amplify @react-native-community/netinfo @react-native-async-storage/async-storage +``` + +### Amplify 3.x.x has breaking changes. Please see the breaking changes below: + +- `AWS.credentials` and `AWS.config` don’t exist anymore in Amplify JavaScript. + - Both options will not be available to use in version 3. You will not be able to use and set your own credentials. + - For more information on this change, please see the [AWS SDK for JavaScript v3](https://github.com/aws/aws-sdk-js-v3/#configuration) +- `aws-sdk@2.x` has been removed from `Amplify@3.x.x` in favor of [version 3 of aws-sdk-js](https://github.com/aws/aws-sdk-js-v3). We recommend to migrate to [aws-sdk-js-v3](https://github.com/aws/aws-sdk-js-v3) if you rely on AWS services that are not supported by Amplify, since [aws-sdk-js-v3](https://github.com/aws/aws-sdk-js-v3) is imported modularly. + +If you can't migrate to [aws-sdk-js-v3](https://github.com/aws/aws-sdk-js-v3) or rely on aws-sdk@2.x, you will need to import it separately. + +- If you are using exported paths within your Amplify JS application, (e.g. `import from "@aws-amplify/analytics/lib/Analytics"`) this will now break and no longer will be supported. You will need to change to named imports: + + ```js + import { Analytics } from 'aws-amplify'; + ``` + +- If you are using categories as `Amplify.`, this will no longer work and we recommend to import the category you are needing to use: + + ```js + import { Auth } from 'aws-amplify'; + ``` diff --git a/packages/amazon-cognito-identity-js/CHANGELOG.md b/packages/amazon-cognito-identity-js/CHANGELOG.md index 29de356d567..894bd6c5613 100644 --- a/packages/amazon-cognito-identity-js/CHANGELOG.md +++ b/packages/amazon-cognito-identity-js/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.1.0](https://github.com/aws-amplify/amplify-js/compare/amazon-cognito-identity-js@5.0.6...amazon-cognito-identity-js@5.1.0) (2021-08-19) + + +### Features + +* **@aws-amplify/auth:** Add a 'SUCCESS' response on successful call to forgotPasswordSubmit and verifyUserAttributes([#8744](https://github.com/aws-amplify/amplify-js/issues/8744)) ([1bd6c35](https://github.com/aws-amplify/amplify-js/commit/1bd6c35c115321d77f48a3954942dd57d7cf9056)) + + + + + ## [5.0.6](https://github.com/aws-amplify/amplify-js/compare/amazon-cognito-identity-js@5.0.5...amazon-cognito-identity-js@5.0.6) (2021-07-22) diff --git a/packages/amazon-cognito-identity-js/__tests__/CognitoUser.test.js b/packages/amazon-cognito-identity-js/__tests__/CognitoUser.test.js index 73a67da5eeb..6649c45d011 100644 --- a/packages/amazon-cognito-identity-js/__tests__/CognitoUser.test.js +++ b/packages/amazon-cognito-identity-js/__tests__/CognitoUser.test.js @@ -1120,7 +1120,7 @@ describe('verifyAttribute(), getAttributeVerificationCode', () => { netRequestMockSuccess(true); cognitoUser.getAttributeVerificationCode(...getAttrsVerifCodeDefaults); callback.inputVerificationCode = jest.fn(); - expect(callback.onSuccess.mock.calls.length).toEqual(1); + expect(callback.onSuccess).toHaveBeenCalledWith('SUCCESS'); }); test('when inputVerificationCode exists in the callback, call inputVerifier with the data', () => { @@ -1169,7 +1169,7 @@ describe('confirmPassword() and forgotPassword()', () => { test('happy path should callback onSuccess', () => { netRequestMockSuccess(true); cognitoUser.confirmPassword(...confirmPasswordDefaults); - expect(callback.onSuccess.mock.calls.length).toEqual(1); + expect(callback.onSuccess).toHaveBeenCalledWith('SUCCESS') }); test('client request throws an error', () => { diff --git a/packages/amazon-cognito-identity-js/index.d.ts b/packages/amazon-cognito-identity-js/index.d.ts index 720a135c54e..90312b6afda 100644 --- a/packages/amazon-cognito-identity-js/index.d.ts +++ b/packages/amazon-cognito-identity-js/index.d.ts @@ -129,7 +129,7 @@ declare module 'amazon-cognito-identity-js' { verificationCode: string, newPassword: string, callbacks: { - onSuccess: () => void; + onSuccess: (success: string) => void; onFailure: (err: Error) => void; }, clientMetaData?: ClientMetadata @@ -216,7 +216,7 @@ declare module 'amazon-cognito-identity-js' { public getAttributeVerificationCode( name: string, callback: { - onSuccess: () => void; + onSuccess: (success: string) => void; onFailure: (err: Error) => void; inputVerificationCode?: (data: string) => void | null; } diff --git a/packages/amazon-cognito-identity-js/package.json b/packages/amazon-cognito-identity-js/package.json index e81df6d8e34..7933d373042 100644 --- a/packages/amazon-cognito-identity-js/package.json +++ b/packages/amazon-cognito-identity-js/package.json @@ -1,7 +1,7 @@ { "name": "amazon-cognito-identity-js", "description": "Amazon Cognito Identity Provider JavaScript SDK", - "version": "5.0.6", + "version": "5.1.0", "author": { "name": "Amazon Web Services", "email": "aws@amazon.com", diff --git a/packages/amazon-cognito-identity-js/src/CognitoUser.js b/packages/amazon-cognito-identity-js/src/CognitoUser.js index b9756925c2e..3e2d6008858 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoUser.js +++ b/packages/amazon-cognito-identity-js/src/CognitoUser.js @@ -1700,7 +1700,7 @@ export default class CognitoUser { if (err) { return callback.onFailure(err); } - return callback.onSuccess(); + return callback.onSuccess('SUCCESS'); }); } @@ -1732,7 +1732,7 @@ export default class CognitoUser { if (typeof callback.inputVerificationCode === 'function') { return callback.inputVerificationCode(data); } - return callback.onSuccess(); + return callback.onSuccess('SUCCESS'); } ); return undefined; diff --git a/packages/amplify-ui-angular/CHANGELOG.md b/packages/amplify-ui-angular/CHANGELOG.md index 1e3e03f4285..1863fadb3c1 100644 --- a/packages/amplify-ui-angular/CHANGELOG.md +++ b/packages/amplify-ui-angular/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.0.24](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.23...@aws-amplify/ui-angular@1.0.24) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + +## [1.0.23](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.22...@aws-amplify/ui-angular@1.0.23) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + +## [1.0.22](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.21...@aws-amplify/ui-angular@1.0.22) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + +## [1.0.21](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.20...@aws-amplify/ui-angular@1.0.21) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + +## [1.0.20](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.19...@aws-amplify/ui-angular@1.0.20) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + +## [1.0.19](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.18...@aws-amplify/ui-angular@1.0.19) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + +## [1.0.18](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.17...@aws-amplify/ui-angular@1.0.18) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + +## [1.0.17](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.16...@aws-amplify/ui-angular@1.0.17) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/ui-angular + + + + + ## [1.0.16](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-angular@1.0.15...@aws-amplify/ui-angular@1.0.16) (2021-07-22) **Note:** Version bump only for package @aws-amplify/ui-angular diff --git a/packages/amplify-ui-angular/package.json b/packages/amplify-ui-angular/package.json index 6ecab8104f0..9c35a91818d 100644 --- a/packages/amplify-ui-angular/package.json +++ b/packages/amplify-ui-angular/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/ui-angular", - "version": "1.0.16", + "version": "1.0.24", "description": "Angular specific wrapper for @aws-amplify/ui-components", "publishConfig": { "access": "public" @@ -31,7 +31,7 @@ "dist/" ], "dependencies": { - "@aws-amplify/ui-components": "1.7.0" + "@aws-amplify/ui-components": "1.7.8" }, "devDependencies": { "@angular/compiler-cli": "^7.2.1", diff --git a/packages/amplify-ui-components/CHANGELOG.md b/packages/amplify-ui-components/CHANGELOG.md index 36d466fe081..8ed89b2ea11 100644 --- a/packages/amplify-ui-components/CHANGELOG.md +++ b/packages/amplify-ui-components/CHANGELOG.md @@ -3,6 +3,76 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.7.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.7...@aws-amplify/ui-components@1.7.8) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/ui-components + + + + + +## [1.7.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.6...@aws-amplify/ui-components@1.7.7) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/ui-components + + + + + +## [1.7.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.5...@aws-amplify/ui-components@1.7.6) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/ui-components + + + + + +## [1.7.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.4...@aws-amplify/ui-components@1.7.5) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/ui-components + + + + + +## [1.7.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.3...@aws-amplify/ui-components@1.7.4) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/ui-components + + + + + +## [1.7.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.2...@aws-amplify/ui-components@1.7.3) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/ui-components + + + + + +## [1.7.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.1...@aws-amplify/ui-components@1.7.2) (2021-08-12) + + +### Bug Fixes + +* **@aws-amplify/ui-components:** Remove local storage check ([#8730](https://github.com/aws-amplify/amplify-js/issues/8730)) ([fc7f8ab](https://github.com/aws-amplify/amplify-js/commit/fc7f8ab6c965b980b87d9a0d47583672813162bf)) + + + + + +## [1.7.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.7.0...@aws-amplify/ui-components@1.7.1) (2021-07-28) + + +### Bug Fixes + +* **@aws-amplify/ui-components:** Empty `newFormfFields` array on rebuild ([#8633](https://github.com/aws-amplify/amplify-js/issues/8633)) ([908cd16](https://github.com/aws-amplify/amplify-js/commit/908cd166779fd40f09d8034c05c3bb2590ba3771)) + + + + + # [1.7.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-components@1.6.2...@aws-amplify/ui-components@1.7.0) (2021-07-22) diff --git a/packages/amplify-ui-components/package.json b/packages/amplify-ui-components/package.json index d6eac70c784..41261ad339a 100644 --- a/packages/amplify-ui-components/package.json +++ b/packages/amplify-ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/ui-components", - "version": "1.7.0", + "version": "1.7.8", "description": "Core Amplify UI Component Library", "module": "dist/index.mjs", "main": "dist/index.js", @@ -42,7 +42,7 @@ "uuid": "^8.2.0" }, "devDependencies": { - "@aws-amplify/auth": "4.1.3", + "@aws-amplify/auth": "4.3.5", "@stencil/angular-output-target": "^0.0.2", "@stencil/core": "1.15.0", "@stencil/eslint-plugin": "0.2.1", diff --git a/packages/amplify-ui-components/src/components/amplify-authenticator/amplify-authenticator.tsx b/packages/amplify-ui-components/src/components/amplify-authenticator/amplify-authenticator.tsx index 0faaf60480e..cfddae46477 100644 --- a/packages/amplify-ui-components/src/components/amplify-authenticator/amplify-authenticator.tsx +++ b/packages/amplify-ui-components/src/components/amplify-authenticator/amplify-authenticator.tsx @@ -9,7 +9,6 @@ import { import { AUTH_CHANNEL, NO_AUTH_MODULE_FOUND, - AUTHENTICATOR_AUTHSTATE, UI_AUTH_CHANNEL, TOAST_AUTH_ERROR_EVENT, } from '../../common/constants'; @@ -106,24 +105,8 @@ export class AmplifyAuthenticator { .then(user => { dispatchAuthStateChangeEvent(AuthState.SignedIn, user); }) - .catch(async () => { - let cachedAuthState = null; - try { - cachedAuthState = localStorage.getItem(AUTHENTICATOR_AUTHSTATE); - } catch (error) { - logger.debug( - 'Failed to get the auth state from local storage', - error - ); - } - try { - if (cachedAuthState === AuthState.SignedIn) { - await Auth.signOut(); - } - dispatchAuthStateChangeEvent(this.initialAuthState); - } catch (error) { - logger.debug('Failed to sign out', error); - } + .catch(() => { + dispatchAuthStateChangeEvent(this.initialAuthState); }); } diff --git a/packages/amplify-ui-react/CHANGELOG.md b/packages/amplify-ui-react/CHANGELOG.md index 1737c4f9059..b663afad4b9 100644 --- a/packages/amplify-ui-react/CHANGELOG.md +++ b/packages/amplify-ui-react/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.2.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.14...@aws-amplify/ui-react@1.2.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + +## [1.2.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.13...@aws-amplify/ui-react@1.2.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + +## [1.2.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.12...@aws-amplify/ui-react@1.2.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + +## [1.2.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.11...@aws-amplify/ui-react@1.2.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + +## [1.2.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.10...@aws-amplify/ui-react@1.2.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + +## [1.2.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.9...@aws-amplify/ui-react@1.2.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + +## [1.2.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.8...@aws-amplify/ui-react@1.2.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + +## [1.2.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.7...@aws-amplify/ui-react@1.2.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/ui-react + + + + + ## [1.2.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-react@1.2.6...@aws-amplify/ui-react@1.2.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/ui-react diff --git a/packages/amplify-ui-react/package.json b/packages/amplify-ui-react/package.json index aa9ab52af3f..8683f87d87d 100755 --- a/packages/amplify-ui-react/package.json +++ b/packages/amplify-ui-react/package.json @@ -1,7 +1,7 @@ { "name": "@aws-amplify/ui-react", "sideEffects": false, - "version": "1.2.7", + "version": "1.2.15", "description": "React specific wrapper for @aws-amplify/ui-components", "publishConfig": { "access": "public" @@ -32,7 +32,7 @@ "typescript": "^3.3.4000" }, "dependencies": { - "@aws-amplify/ui-components": "1.7.0" + "@aws-amplify/ui-components": "1.7.8" }, "peerDependencies": { "react": ">= 16.7.0", diff --git a/packages/amplify-ui-storybook/CHANGELOG.md b/packages/amplify-ui-storybook/CHANGELOG.md index aa4d3bad13a..20d96e1ee66 100644 --- a/packages/amplify-ui-storybook/CHANGELOG.md +++ b/packages/amplify-ui-storybook/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.14...@aws-amplify/ui-storybook@2.0.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + +## [2.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.13...@aws-amplify/ui-storybook@2.0.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + +## [2.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.12...@aws-amplify/ui-storybook@2.0.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + +## [2.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.11...@aws-amplify/ui-storybook@2.0.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + +## [2.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.10...@aws-amplify/ui-storybook@2.0.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + +## [2.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.9...@aws-amplify/ui-storybook@2.0.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + +## [2.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.8...@aws-amplify/ui-storybook@2.0.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + +## [2.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.7...@aws-amplify/ui-storybook@2.0.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/ui-storybook + + + + + ## [2.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-storybook@2.0.6...@aws-amplify/ui-storybook@2.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/ui-storybook diff --git a/packages/amplify-ui-storybook/package.json b/packages/amplify-ui-storybook/package.json index 2c457426b46..0b2730bd538 100644 --- a/packages/amplify-ui-storybook/package.json +++ b/packages/amplify-ui-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/ui-storybook", - "version": "2.0.7", + "version": "2.0.15", "private": true, "dependencies": { "@aws-amplify/ui-react": "0.2.38", @@ -10,7 +10,7 @@ "@types/node": "^12.0.0", "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", - "aws-amplify": "4.2.1", + "aws-amplify": "4.2.9", "react": "^16.12.0", "react-app-polyfill": "^1.0.6", "react-dom": "^16.12.0", diff --git a/packages/amplify-ui-vue/CHANGELOG.md b/packages/amplify-ui-vue/CHANGELOG.md index 5c5f47aaace..91b2a961ddd 100644 --- a/packages/amplify-ui-vue/CHANGELOG.md +++ b/packages/amplify-ui-vue/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.1.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.8...@aws-amplify/ui-vue@1.1.9) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + +## [1.1.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.7...@aws-amplify/ui-vue@1.1.8) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + +## [1.1.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.6...@aws-amplify/ui-vue@1.1.7) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + +## [1.1.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.5...@aws-amplify/ui-vue@1.1.6) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + +## [1.1.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.4...@aws-amplify/ui-vue@1.1.5) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + +## [1.1.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.3...@aws-amplify/ui-vue@1.1.4) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + +## [1.1.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.2...@aws-amplify/ui-vue@1.1.3) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + +## [1.1.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.1...@aws-amplify/ui-vue@1.1.2) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/ui-vue + + + + + ## [1.1.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/ui-vue@1.1.0...@aws-amplify/ui-vue@1.1.1) (2021-07-22) **Note:** Version bump only for package @aws-amplify/ui-vue diff --git a/packages/amplify-ui-vue/package.json b/packages/amplify-ui-vue/package.json index 7e16c23bff7..25e6f832760 100644 --- a/packages/amplify-ui-vue/package.json +++ b/packages/amplify-ui-vue/package.json @@ -1,7 +1,7 @@ { "name": "@aws-amplify/ui-vue", "sideEffects": true, - "version": "1.1.1", + "version": "1.1.9", "description": "Vue specific wrapper for @aws-amplify/ui-components", "publishConfig": { "access": "public" @@ -17,7 +17,7 @@ "url": "https://github.com/aws-amplify/amplify-js.git" }, "dependencies": { - "@aws-amplify/ui-components": "1.7.0" + "@aws-amplify/ui-components": "1.7.8" }, "devDependencies": { "rimraf": "^3.0.2" diff --git a/packages/analytics/CHANGELOG.md b/packages/analytics/CHANGELOG.md index 93044365b50..c3c4e0e788e 100644 --- a/packages/analytics/CHANGELOG.md +++ b/packages/analytics/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.14...@aws-amplify/analytics@5.0.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + +## [5.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.13...@aws-amplify/analytics@5.0.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + +## [5.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.12...@aws-amplify/analytics@5.0.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + +## [5.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.11...@aws-amplify/analytics@5.0.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + +## [5.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.10...@aws-amplify/analytics@5.0.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + +## [5.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.9...@aws-amplify/analytics@5.0.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + +## [5.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.8...@aws-amplify/analytics@5.0.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + +## [5.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.7...@aws-amplify/analytics@5.0.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/analytics + + + + + ## [5.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@5.0.6...@aws-amplify/analytics@5.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/analytics diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 0a02baa4a7d..30ca791facc 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/analytics", - "version": "5.0.7", + "version": "5.0.15", "description": "Analytics category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -43,8 +43,8 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/cache": "4.0.9", - "@aws-amplify/core": "4.2.1", + "@aws-amplify/cache": "4.0.17", + "@aws-amplify/core": "4.2.9", "@aws-sdk/client-firehose": "3.6.1", "@aws-sdk/client-kinesis": "3.6.1", "@aws-sdk/client-personalize-events": "3.6.1", diff --git a/packages/api-graphql/CHANGELOG.md b/packages/api-graphql/CHANGELOG.md index ecf9fb1e407..5de0a7feffc 100644 --- a/packages/api-graphql/CHANGELOG.md +++ b/packages/api-graphql/CHANGELOG.md @@ -3,6 +3,77 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.2.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.2.3...@aws-amplify/api-graphql@2.2.4) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/api-graphql + + + + + +## [2.2.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.2.2...@aws-amplify/api-graphql@2.2.3) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/api-graphql + + + + + +## [2.2.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.2.1...@aws-amplify/api-graphql@2.2.2) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/api-graphql + + + + + +## [2.2.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.2.0...@aws-amplify/api-graphql@2.2.1) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/api-graphql + + + + + +# [2.2.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.1.2...@aws-amplify/api-graphql@2.2.0) (2021-08-26) + + +### Features + +* **@aws-amplify/api-graphql:** Add support for string 'authmode' values in TypeScript based apps ([#8799](https://github.com/aws-amplify/amplify-js/issues/8799)) ([f1dc4a2](https://github.com/aws-amplify/amplify-js/commit/f1dc4a24330bb41295621aaf47f6c4e26828fea5)) + + + + + +## [2.1.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.1.1...@aws-amplify/api-graphql@2.1.2) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/api-graphql + + + + + +## [2.1.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.1.0...@aws-amplify/api-graphql@2.1.1) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/api-graphql + + + + + +# [2.1.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.0.7...@aws-amplify/api-graphql@2.1.0) (2021-07-28) + + +### Features + +* **@aws-amplify/api:** support lambda authorizers ([aba3d2a](https://github.com/aws-amplify/amplify-js/commit/aba3d2aec7e7c9ad8701b345ab94d796b2bdb897)) +* **@aws-amplify/datastore:** support lambda authorizers ([52d43cc](https://github.com/aws-amplify/amplify-js/commit/52d43cc73b459148f1ae81ab81d3a5365a4457e3)) + + + + + ## [2.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@2.0.6...@aws-amplify/api-graphql@2.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/api-graphql diff --git a/packages/api-graphql/package.json b/packages/api-graphql/package.json index 3a5e58785de..d83eddf3bad 100644 --- a/packages/api-graphql/package.json +++ b/packages/api-graphql/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/api-graphql", - "version": "2.0.7", + "version": "2.2.4", "description": "Api-graphql category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -44,11 +44,11 @@ "@types/zen-observable": "^0.8.0" }, "dependencies": { - "@aws-amplify/api-rest": "2.0.7", - "@aws-amplify/auth": "4.1.3", - "@aws-amplify/cache": "4.0.9", - "@aws-amplify/core": "4.2.1", - "@aws-amplify/pubsub": "4.0.7", + "@aws-amplify/api-rest": "2.0.15", + "@aws-amplify/auth": "4.3.5", + "@aws-amplify/cache": "4.0.17", + "@aws-amplify/core": "4.2.9", + "@aws-amplify/pubsub": "4.1.7", "graphql": "14.0.0", "uuid": "^3.2.1", "zen-observable-ts": "0.8.19" diff --git a/packages/api-graphql/src/types/index.ts b/packages/api-graphql/src/types/index.ts index a4b42b97cdf..c52bab34948 100644 --- a/packages/api-graphql/src/types/index.ts +++ b/packages/api-graphql/src/types/index.ts @@ -17,7 +17,7 @@ import { DocumentNode } from 'graphql/language/ast'; export interface GraphQLOptions { query: string | DocumentNode; variables?: object; - authMode?: GRAPHQL_AUTH_MODE; + authMode?: keyof typeof GRAPHQL_AUTH_MODE; authToken?: string; } diff --git a/packages/api-rest/CHANGELOG.md b/packages/api-rest/CHANGELOG.md index 29f66735537..6febc355799 100644 --- a/packages/api-rest/CHANGELOG.md +++ b/packages/api-rest/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.14...@aws-amplify/api-rest@2.0.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + +## [2.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.13...@aws-amplify/api-rest@2.0.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + +## [2.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.12...@aws-amplify/api-rest@2.0.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + +## [2.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.11...@aws-amplify/api-rest@2.0.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + +## [2.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.10...@aws-amplify/api-rest@2.0.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + +## [2.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.9...@aws-amplify/api-rest@2.0.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + +## [2.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.8...@aws-amplify/api-rest@2.0.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + +## [2.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.7...@aws-amplify/api-rest@2.0.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/api-rest + + + + + ## [2.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@2.0.6...@aws-amplify/api-rest@2.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/api-rest diff --git a/packages/api-rest/package.json b/packages/api-rest/package.json index e9d0ac5973d..35f96ac7613 100644 --- a/packages/api-rest/package.json +++ b/packages/api-rest/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/api-rest", - "version": "2.0.7", + "version": "2.0.15", "description": "Api-rest category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -41,8 +41,8 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/core": "4.2.1", - "axios": "0.21.1" + "@aws-amplify/core": "4.2.9", + "axios": "0.21.4" }, "jest": { "globals": { diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 99571b28711..699723326db 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.14...@aws-amplify/api@4.0.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/api + + + + + +## [4.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.13...@aws-amplify/api@4.0.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/api + + + + + +## [4.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.12...@aws-amplify/api@4.0.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/api + + + + + +## [4.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.11...@aws-amplify/api@4.0.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/api + + + + + +## [4.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.10...@aws-amplify/api@4.0.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/api + + + + + +## [4.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.9...@aws-amplify/api@4.0.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/api + + + + + +## [4.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.8...@aws-amplify/api@4.0.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/api + + + + + +## [4.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.7...@aws-amplify/api@4.0.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/api + + + + + ## [4.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@4.0.6...@aws-amplify/api@4.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/api diff --git a/packages/api/package.json b/packages/api/package.json index 0bc3787443f..5070ea40fa5 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/api", - "version": "4.0.7", + "version": "4.0.15", "description": "Api category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -44,8 +44,8 @@ "@types/zen-observable": "^0.8.0" }, "dependencies": { - "@aws-amplify/api-graphql": "2.0.7", - "@aws-amplify/api-rest": "2.0.7" + "@aws-amplify/api-graphql": "2.2.4", + "@aws-amplify/api-rest": "2.0.15" }, "jest": { "globals": { diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index bb3f1e88ab0..8c2ee2bed53 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -3,6 +3,79 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.3.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.3.4...@aws-amplify/auth@4.3.5) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/auth + + + + + +## [4.3.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.3.3...@aws-amplify/auth@4.3.4) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/auth + + + + + +## [4.3.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.3.2...@aws-amplify/auth@4.3.3) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/auth + + + + + +## [4.3.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.3.1...@aws-amplify/auth@4.3.2) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/auth + + + + + +## [4.3.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.3.0...@aws-amplify/auth@4.3.1) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/auth + + + + + +# [4.3.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.2.1...@aws-amplify/auth@4.3.0) (2021-08-19) + + +### Features + +* **@aws-amplify/auth:** Add a 'SUCCESS' response on successful call to forgotPasswordSubmit and verifyUserAttributes([#8744](https://github.com/aws-amplify/amplify-js/issues/8744)) ([1bd6c35](https://github.com/aws-amplify/amplify-js/commit/1bd6c35c115321d77f48a3954942dd57d7cf9056)) + + + + + +## [4.2.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.2.0...@aws-amplify/auth@4.2.1) (2021-08-12) + + +### Bug Fixes + +* function parameters partiy with signIn ([#8713](https://github.com/aws-amplify/amplify-js/issues/8713)) ([b5d4243](https://github.com/aws-amplify/amplify-js/commit/b5d424372d382e638bd58844ec34c512026cae02)) + + + + + +# [4.2.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.1.3...@aws-amplify/auth@4.2.0) (2021-07-28) + + +### Features + +* **@aws-amplify/auth:** delete user attributes ([#7342](https://github.com/aws-amplify/amplify-js/issues/7342)) ([1b1df67](https://github.com/aws-amplify/amplify-js/commit/1b1df679d874e824bc89f95054008b2f46ae76cf)) + + + + + ## [4.1.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@4.1.2...@aws-amplify/auth@4.1.3) (2021-07-22) diff --git a/packages/auth/package.json b/packages/auth/package.json index 49659b6e288..47f4adde9cf 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/auth", - "version": "4.1.3", + "version": "4.3.5", "description": "Auth category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -41,9 +41,9 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/cache": "4.0.9", - "@aws-amplify/core": "4.2.1", - "amazon-cognito-identity-js": "5.0.6", + "@aws-amplify/cache": "4.0.17", + "@aws-amplify/core": "4.2.9", + "amazon-cognito-identity-js": "5.1.0", "crypto-js": "^4.1.1" }, "devDependencies": { diff --git a/packages/auth/src/Auth.ts b/packages/auth/src/Auth.ts index e4bbb6fd786..b02bfc08c18 100644 --- a/packages/auth/src/Auth.ts +++ b/packages/auth/src/Auth.ts @@ -1540,8 +1540,8 @@ export class AuthClass { user.getAttributeVerificationCode( attr, { - onSuccess() { - return resolve(); + onSuccess(success) { + return resolve(success); }, onFailure(err) { return reject(err); @@ -1819,7 +1819,7 @@ export class AuthClass { code: string, password: string, clientMetadata: ClientMetaData = this._config.clientMetadata - ): Promise { + ): Promise { if (!this.userPool) { return this.rejectNoUserPool(); } @@ -1839,13 +1839,13 @@ export class AuthClass { code, password, { - onSuccess: () => { + onSuccess: (success) => { dispatchAuthEvent( 'forgotPasswordSubmit', user, `${username} forgotPasswordSubmit successful` ); - resolve(); + resolve(success); return; }, onFailure: err => { @@ -1873,7 +1873,7 @@ export class AuthClass { if (!source || source === 'aws' || source === 'userPool') { const user = await this.currentUserPoolUser().catch(err => - logger.debug(err) + logger.error(err) ); if (!user) { return null; @@ -1899,7 +1899,7 @@ export class AuthClass { }; return info; } catch (err) { - logger.debug('currentUserInfo error', err); + logger.error('currentUserInfo error', err); return {}; } } @@ -2129,6 +2129,17 @@ export class AuthClass { return credentials; } catch (err) { logger.debug('Error in cognito hosted auth response', err); + + // Just like a successful handling of `?code`, replace the window history to "dispose" of the `code`. + // Otherwise, reloading the page will throw errors as the `code` has already been spent. + if (window && typeof window.history !== 'undefined') { + window.history.replaceState( + {}, + null, + (this._config.oauth as AwsCognitoOAuthOpts).redirectSignIn + ); + } + dispatchAuthEvent( 'signIn_failure', err, diff --git a/packages/auth/src/OAuth/OAuth.ts b/packages/auth/src/OAuth/OAuth.ts index 2ac97e29da2..275c931e94d 100644 --- a/packages/auth/src/OAuth/OAuth.ts +++ b/packages/auth/src/OAuth/OAuth.ts @@ -291,7 +291,7 @@ export default class OAuth { ); logger.debug(`Signing out from ${oAuthLogoutEndpoint}`); - return this._urlOpener(oAuthLogoutEndpoint); + return this._urlOpener(oAuthLogoutEndpoint, signout_uri); } private _generateState(length: number) { diff --git a/packages/aws-amplify-angular/CHANGELOG.md b/packages/aws-amplify-angular/CHANGELOG.md index fd458c7f8ec..7b965c60eed 100644 --- a/packages/aws-amplify-angular/CHANGELOG.md +++ b/packages/aws-amplify-angular/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.0.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.14...aws-amplify-angular@6.0.15) (2021-09-09) + +**Note:** Version bump only for package aws-amplify-angular + + + + + +## [6.0.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.13...aws-amplify-angular@6.0.14) (2021-09-07) + +**Note:** Version bump only for package aws-amplify-angular + + + + + +## [6.0.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.12...aws-amplify-angular@6.0.13) (2021-09-04) + +**Note:** Version bump only for package aws-amplify-angular + + + + + +## [6.0.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.11...aws-amplify-angular@6.0.12) (2021-09-02) + +**Note:** Version bump only for package aws-amplify-angular + + + + + +## [6.0.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.10...aws-amplify-angular@6.0.11) (2021-08-26) + +**Note:** Version bump only for package aws-amplify-angular + + + + + +## [6.0.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.9...aws-amplify-angular@6.0.10) (2021-08-19) + +**Note:** Version bump only for package aws-amplify-angular + + + + + +## [6.0.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.8...aws-amplify-angular@6.0.9) (2021-08-12) + +**Note:** Version bump only for package aws-amplify-angular + + + + + +## [6.0.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.7...aws-amplify-angular@6.0.8) (2021-07-28) + +**Note:** Version bump only for package aws-amplify-angular + + + + + ## [6.0.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-angular@6.0.6...aws-amplify-angular@6.0.7) (2021-07-22) **Note:** Version bump only for package aws-amplify-angular diff --git a/packages/aws-amplify-angular/package.json b/packages/aws-amplify-angular/package.json index ec6359856f8..243096d2b68 100644 --- a/packages/aws-amplify-angular/package.json +++ b/packages/aws-amplify-angular/package.json @@ -1,6 +1,6 @@ { "name": "aws-amplify-angular", - "version": "6.0.7", + "version": "6.0.15", "description": "AWS Amplify Angular Components", "main": "bundles/aws-amplify-angular.umd.js", "module": "dist/index.js", @@ -39,7 +39,7 @@ "@types/zen-observable": "^0.5.3", "angular2-template-loader": "^0.6.2", "awesome-typescript-loader": "^4.0.1", - "aws-amplify": "4.2.1", + "aws-amplify": "4.2.9", "babel-core": "^6.26.3", "babel-plugin-lodash": "^3.3.4", "babel-preset-env": "^1.7.0", diff --git a/packages/aws-amplify-react/CHANGELOG.md b/packages/aws-amplify-react/CHANGELOG.md index b760ae978a4..d2c609cbbaa 100644 --- a/packages/aws-amplify-react/CHANGELOG.md +++ b/packages/aws-amplify-react/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.15](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.14...aws-amplify-react@5.0.15) (2021-09-09) + +**Note:** Version bump only for package aws-amplify-react + + + + + +## [5.0.14](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.13...aws-amplify-react@5.0.14) (2021-09-07) + +**Note:** Version bump only for package aws-amplify-react + + + + + +## [5.0.13](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.12...aws-amplify-react@5.0.13) (2021-09-04) + +**Note:** Version bump only for package aws-amplify-react + + + + + +## [5.0.12](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.11...aws-amplify-react@5.0.12) (2021-09-02) + +**Note:** Version bump only for package aws-amplify-react + + + + + +## [5.0.11](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.10...aws-amplify-react@5.0.11) (2021-08-26) + +**Note:** Version bump only for package aws-amplify-react + + + + + +## [5.0.10](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.9...aws-amplify-react@5.0.10) (2021-08-19) + +**Note:** Version bump only for package aws-amplify-react + + + + + +## [5.0.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.8...aws-amplify-react@5.0.9) (2021-08-12) + +**Note:** Version bump only for package aws-amplify-react + + + + + +## [5.0.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.7...aws-amplify-react@5.0.8) (2021-07-28) + +**Note:** Version bump only for package aws-amplify-react + + + + + ## [5.0.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify-react@5.0.6...aws-amplify-react@5.0.7) (2021-07-22) **Note:** Version bump only for package aws-amplify-react diff --git a/packages/aws-amplify-react/package.json b/packages/aws-amplify-react/package.json index 94ed183b611..5dcbd72873e 100644 --- a/packages/aws-amplify-react/package.json +++ b/packages/aws-amplify-react/package.json @@ -1,6 +1,6 @@ { "name": "aws-amplify-react", - "version": "5.0.7", + "version": "5.0.15", "description": "AWS Amplify is a JavaScript library for Frontend and mobile developers building cloud-enabled applications.", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -38,7 +38,7 @@ "@types/enzyme-adapter-react-16": "^1.0.3", "@types/react": "^16.0.41", "@types/react-dom": "^16.0.11", - "aws-amplify": "4.2.1", + "aws-amplify": "4.2.9", "enzyme": "^3.1.0", "enzyme-adapter-react-16": "^1.0.3", "enzyme-to-json": "^3.2.1", diff --git a/packages/aws-amplify/CHANGELOG.md b/packages/aws-amplify/CHANGELOG.md index 88dc92c2814..99f8123a75a 100644 --- a/packages/aws-amplify/CHANGELOG.md +++ b/packages/aws-amplify/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.2.9](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.8...aws-amplify@4.2.9) (2021-09-09) + +**Note:** Version bump only for package aws-amplify + + + + + +## [4.2.8](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.7...aws-amplify@4.2.8) (2021-09-07) + +**Note:** Version bump only for package aws-amplify + + + + + +## [4.2.7](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.6...aws-amplify@4.2.7) (2021-09-04) + +**Note:** Version bump only for package aws-amplify + + + + + +## [4.2.6](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.5...aws-amplify@4.2.6) (2021-09-02) + +**Note:** Version bump only for package aws-amplify + + + + + +## [4.2.5](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.4...aws-amplify@4.2.5) (2021-08-26) + +**Note:** Version bump only for package aws-amplify + + + + + +## [4.2.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.3...aws-amplify@4.2.4) (2021-08-19) + +**Note:** Version bump only for package aws-amplify + + + + + +## [4.2.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.2...aws-amplify@4.2.3) (2021-08-12) + +**Note:** Version bump only for package aws-amplify + + + + + +## [4.2.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.1...aws-amplify@4.2.2) (2021-07-28) + +**Note:** Version bump only for package aws-amplify + + + + + ## [4.2.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@4.2.0...aws-amplify@4.2.1) (2021-07-22) **Note:** Version bump only for package aws-amplify diff --git a/packages/aws-amplify/package.json b/packages/aws-amplify/package.json index eea7adbf6e4..76b60c7186a 100644 --- a/packages/aws-amplify/package.json +++ b/packages/aws-amplify/package.json @@ -1,6 +1,6 @@ { "name": "aws-amplify", - "version": "4.2.1", + "version": "4.2.9", "description": "AWS Amplify is a JavaScript library for Frontend and mobile developers building cloud-enabled applications.", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -34,19 +34,19 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/analytics": "5.0.7", - "@aws-amplify/api": "4.0.7", - "@aws-amplify/auth": "4.1.3", - "@aws-amplify/cache": "4.0.9", - "@aws-amplify/core": "4.2.1", - "@aws-amplify/datastore": "3.2.2", - "@aws-amplify/geo": "0.0.1", - "@aws-amplify/interactions": "4.0.7", - "@aws-amplify/predictions": "4.0.7", - "@aws-amplify/pubsub": "4.0.7", - "@aws-amplify/storage": "4.3.2", + "@aws-amplify/analytics": "5.0.15", + "@aws-amplify/api": "4.0.15", + "@aws-amplify/auth": "4.3.5", + "@aws-amplify/cache": "4.0.17", + "@aws-amplify/core": "4.2.9", + "@aws-amplify/datastore": "3.4.3", + "@aws-amplify/geo": "0.0.1", + "@aws-amplify/interactions": "4.0.15", + "@aws-amplify/predictions": "4.0.15", + "@aws-amplify/pubsub": "4.1.7", + "@aws-amplify/storage": "4.3.10", "@aws-amplify/ui": "2.0.3", - "@aws-amplify/xr": "3.0.7" + "@aws-amplify/xr": "3.0.15" }, "jest": { "globals": { diff --git a/packages/cache/CHANGELOG.md b/packages/cache/CHANGELOG.md index f18ec11256f..9d5c9f881b3 100644 --- a/packages/cache/CHANGELOG.md +++ b/packages/cache/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.0.17](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.16...@aws-amplify/cache@4.0.17) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + +## [4.0.16](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.15...@aws-amplify/cache@4.0.16) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + +## [4.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.14...@aws-amplify/cache@4.0.15) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + +## [4.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.13...@aws-amplify/cache@4.0.14) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + +## [4.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.12...@aws-amplify/cache@4.0.13) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + +## [4.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.11...@aws-amplify/cache@4.0.12) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + +## [4.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.10...@aws-amplify/cache@4.0.11) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + +## [4.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.9...@aws-amplify/cache@4.0.10) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/cache + + + + + ## [4.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/cache@4.0.8...@aws-amplify/cache@4.0.9) (2021-07-22) **Note:** Version bump only for package @aws-amplify/cache diff --git a/packages/cache/package.json b/packages/cache/package.json index 37d3c35e27c..12ed0fea1d2 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/cache", - "version": "4.0.9", + "version": "4.0.17", "description": "Cache category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -44,7 +44,7 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/core": "4.2.1" + "@aws-amplify/core": "4.2.9" }, "jest": { "globals": { diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 2f90a8a3608..3c426299009 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -3,6 +3,73 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.2.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.8...@aws-amplify/core@4.2.9) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/core + + + + + +## [4.2.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.7...@aws-amplify/core@4.2.8) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/core + + + + + +## [4.2.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.6...@aws-amplify/core@4.2.7) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/core + + + + + +## [4.2.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.5...@aws-amplify/core@4.2.6) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/core + + + + + +## [4.2.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.4...@aws-amplify/core@4.2.5) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/core + + + + + +## [4.2.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.3...@aws-amplify/core@4.2.4) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/core + + + + + +## [4.2.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.2...@aws-amplify/core@4.2.3) (2021-08-12) + + +### Bug Fixes + +* **@aws-amplify/core:** Include refreshToken in UniversalStorage for SSR ([#7374](https://github.com/aws-amplify/amplify-js/issues/7374)) ([1e0887b](https://github.com/aws-amplify/amplify-js/commit/1e0887bdc45e178f04229c888051ecf10d2bfabc)) + + + + + +## [4.2.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.1...@aws-amplify/core@4.2.2) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/core + + + + + ## [4.2.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@4.2.0...@aws-amplify/core@4.2.1) (2021-07-22) **Note:** Version bump only for package @aws-amplify/core diff --git a/packages/core/package.json b/packages/core/package.json index af520e4e1a7..2554df79f91 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/core", - "version": "4.2.1", + "version": "4.2.9", "description": "Core category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", diff --git a/packages/core/src/Platform/version.ts b/packages/core/src/Platform/version.ts index d5afe4d1647..194686dfb5d 100644 --- a/packages/core/src/Platform/version.ts +++ b/packages/core/src/Platform/version.ts @@ -1,2 +1,2 @@ // generated by genversion -export const version = '4.2.1'; +export const version = '4.2.9'; diff --git a/packages/core/src/UniversalStorage/index.ts b/packages/core/src/UniversalStorage/index.ts index 2a9edaf8ad4..caf190d8bbc 100644 --- a/packages/core/src/UniversalStorage/index.ts +++ b/packages/core/src/UniversalStorage/index.ts @@ -78,17 +78,20 @@ export class UniversalStorage implements Storage { // accessToken is required for CognitoUserSession case 'accessToken': + // refreshToken originates on the client, but SSR pages won't fail when this expires + // Note: the new `accessToken` will also be refreshed on the client (since Amplify doesn't set server-side cookies) + case 'refreshToken': + // Required for CognitoUserSession case 'idToken': - this.setUniversalItem(key, value); + isBrowser + ? this.setUniversalItem(key, value) + : this.setLocalItem(key, value); // userData is used when `Auth.currentAuthenticatedUser({ bypassCache: false })`. // Can be persisted to speed up calls to `Auth.currentAuthenticatedUser()` // case 'userData': - // refreshToken isn't shared with the server so that the client handles refreshing - // case 'refreshToken': - // Ignoring clockDrift on the server for now, but needs testing // case 'clockDrift': } diff --git a/packages/datastore-storage-adapter/.npmignore b/packages/datastore-storage-adapter/.npmignore new file mode 100644 index 00000000000..7843ccd1b80 --- /dev/null +++ b/packages/datastore-storage-adapter/.npmignore @@ -0,0 +1,15 @@ +__mocks__/** +__tests__/** +coverage/** +docs/** +node_modules/** +.vscode/** +.DS_Store +*.log +prepend-license.js +prettier.config.json +tsconfig.json +tsfmt.json +tslint.json +typeDoc.js +webpack.config.js \ No newline at end of file diff --git a/packages/datastore-storage-adapter/CHANGELOG.md b/packages/datastore-storage-adapter/CHANGELOG.md new file mode 100644 index 00000000000..925b6f2dd5d --- /dev/null +++ b/packages/datastore-storage-adapter/CHANGELOG.md @@ -0,0 +1,35 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.1.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@1.1.2...@aws-amplify/datastore-storage-adapter@1.1.3) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + + + + + +## [1.1.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@1.1.1...@aws-amplify/datastore-storage-adapter@1.1.2) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + + + + + +## [1.1.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@1.1.0...@aws-amplify/datastore-storage-adapter@1.1.1) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + + + + + +# 1.1.0 (2021-09-02) + + +### Features + +* **@aws-amplify/datastore:** add SQLite storage adapter option for RN apps ([#8809](https://github.com/aws-amplify/amplify-js/issues/8809)) ([46ee5dd](https://github.com/aws-amplify/amplify-js/commit/46ee5dd91c61f49bad4da8286b2f97c737d96631)) diff --git a/packages/datastore-storage-adapter/__tests__/SQLiteUtils.test.ts b/packages/datastore-storage-adapter/__tests__/SQLiteUtils.test.ts new file mode 100644 index 00000000000..09d5ce17b93 --- /dev/null +++ b/packages/datastore-storage-adapter/__tests__/SQLiteUtils.test.ts @@ -0,0 +1,658 @@ +import { + generateSchemaStatements, + queryByIdStatement, + queryAllStatement, + queryOneStatement, + modelInsertStatement, + modelUpdateStatement, + whereClauseFromPredicate, + limitClauseFromPagination, + orderByClauseFromSort, + deleteByIdStatement, + deleteByPredicateStatement, + modelCreateTableStatement, + implicitAuthFieldsForModel, +} from '../src/SQLiteAdapter/SQLiteUtils'; +import { + InternalSchema, + PersistentModelConstructor, + QueryOne, + SchemaModel, + initSchema as initSchemaType, +} from '@aws-amplify/datastore'; +import { Model, testSchema, internalTestSchema } from './helpers'; + +let initSchema: typeof initSchemaType; + +const INTERNAL_TEST_SCHEMA_STATEMENTS = [ + 'CREATE TABLE IF NOT EXISTS "Setting" ("id" PRIMARY KEY NOT NULL, "key" TEXT NOT NULL, "value" TEXT NOT NULL);', + 'CREATE TABLE IF NOT EXISTS "Model" ("id" PRIMARY KEY NOT NULL, "field1" TEXT NOT NULL, "optionalField1" TEXT, "dateCreated" TEXT NOT NULL, "emails" TEXT NOT NULL, "ips" TEXT, "metadata" TEXT, "_version" INTEGER, "_lastChangedAt" INTEGER, "_deleted" INTEGER);', + 'CREATE TABLE IF NOT EXISTS "LocalModel" ("id" PRIMARY KEY NOT NULL, "field1" TEXT NOT NULL, "_version" INTEGER, "_lastChangedAt" INTEGER, "_deleted" INTEGER);', + 'CREATE TABLE IF NOT EXISTS "MutationEvent" ("id" PRIMARY KEY NOT NULL, "model" TEXT NOT NULL, "data" TEXT NOT NULL, "modelId" TEXT NOT NULL, "operation" TEXT NOT NULL, "condition" TEXT NOT NULL);', + 'CREATE TABLE IF NOT EXISTS "ModelMetadata" ("id" PRIMARY KEY NOT NULL, "namespace" TEXT NOT NULL, "model" TEXT NOT NULL, "lastSync" INTEGER, "lastFullSync" INTEGER, "fullSyncInterval" INTEGER NOT NULL);', +]; + +const INTERNAL_TEST_SCHEMA_MANY_TO_MANY_STATEMENT = + 'CREATE TABLE IF NOT EXISTS "PostEditor" ("id" PRIMARY KEY NOT NULL, "post" TEXT, "postID" TEXT NOT NULL, "editor" TEXT, "editorID" TEXT NOT NULL, "createdAt" TEXT, "updatedAt" TEXT, "_version" INTEGER, "_lastChangedAt" INTEGER, "_deleted" INTEGER);'; + +describe('SQLiteUtils tests', () => { + let Model: PersistentModelConstructor; + + beforeAll(async () => { + ({ initSchema } = require('@aws-amplify/datastore')); + + const classes = initSchema(testSchema()); + + ({ Model } = classes as { + Model: PersistentModelConstructor; + }); + }); + + describe('createSchemaStatements', () => { + it('should generate valid CREATE TABLE statements from internal schema', () => { + const schema: InternalSchema = internalTestSchema(); + + expect(generateSchemaStatements(schema)).toEqual( + INTERNAL_TEST_SCHEMA_STATEMENTS + ); + }); + }); + + describe('modelCreateTableStatement', () => { + it('should generate valid CREATE TABLE statement from a M:N join table model with implicit FKs', () => { + expect(modelCreateTableStatement(postEditorImplicit, true)).toEqual( + INTERNAL_TEST_SCHEMA_MANY_TO_MANY_STATEMENT + ); + }); + + it('should generate valid CREATE TABLE statement from a M:N join table model with explicit FKs', () => { + expect(modelCreateTableStatement(postEditorExplicit, true)).toEqual( + INTERNAL_TEST_SCHEMA_MANY_TO_MANY_STATEMENT + ); + }); + }); + + describe('implicitAuthFieldsForModel', () => { + it('should extract implicitly defined owner field from model attributes', () => { + expect(implicitAuthFieldsForModel(ownerAuthImplicit)).toEqual(['owner']); + }); + + it('should skip explicitly defined owner field', () => { + expect(implicitAuthFieldsForModel(ownerAuthExplicit)).toEqual([]); + }); + + it('should extract implicitly defined groups field from model attributes', () => { + expect(implicitAuthFieldsForModel(groupsAuthImplicit)).toEqual([ + 'allowedGroups', + ]); + }); + + it('should skip explicitly defined groups field', () => { + expect(implicitAuthFieldsForModel(groupsAuthExplicit)).toEqual([]); + }); + }); + + describe('queryByIdStatement', () => { + it('should generate valid SELECT by id statement', () => { + const model = new Model({ + field1: 'test', + dateCreated: new Date().toISOString(), + }); + + const expected = [`SELECT * FROM "Model" WHERE "id" = ?`, [model.id]]; + + expect(queryByIdStatement(model.id, 'Model')).toEqual(expected); + }); + }); + + describe('queryAllStatement', () => { + it('should generate valid SELECT all statement', () => { + const expected = [`SELECT * FROM "Model" ORDER BY _rowid_ ASC`, []]; + + expect(queryAllStatement('Model')).toEqual(expected); + }); + + it('should generate valid SELECT all statement - with predicates, sort, & pagination', () => { + const tableName = 'Model'; + + const predicateGroup = { + type: 'and', + predicates: [ + { + field: 'firstName', + operator: 'eq', + operand: 'Bob', + }, + { + field: 'lastName', + operator: 'beginsWith', + operand: 'Sm', + }, + { + field: 'sortOrder', + operator: 'gt', + operand: 5, + }, + ], + }; + + const sortPredicateGroup = [ + { + field: 'sortOrder', + sortDirection: 'ASCENDING', + }, + { + field: 'lastName', + sortDirection: 'DESCENDING', + }, + ]; + + const limit = 10; + const page = 3; + + const expected = [ + `SELECT * FROM "Model" WHERE ("firstName" = ? AND "lastName" LIKE ? AND "sortOrder" > ?) ORDER BY "sortOrder" ASC, "lastName" DESC, _rowid_ ASC LIMIT ? OFFSET ?`, + ['Bob', 'Sm%', 5, 10, 30], + ]; + + expect( + queryAllStatement( + tableName, + predicateGroup as any, + sortPredicateGroup as any, + limit, + page + ) + ).toEqual(expected); + }); + }); + + describe('queryOneStatement', () => { + it('should generate valid SELECT statement for query first', () => { + const expected = [`SELECT * FROM Model ORDER BY _rowid_ LIMIT 1`, []]; + + expect(queryOneStatement(QueryOne.FIRST, 'Model')).toEqual(expected); + }); + + it('should generate valid SELECT statement for query last', () => { + const expected = [ + `SELECT * FROM Model ORDER BY _rowid_ DESC LIMIT 1`, + [], + ]; + + expect(queryOneStatement(QueryOne.LAST, 'Model')).toEqual(expected); + }); + }); + + describe('modelInsertStatement', () => { + it('should generate valid SELECT by id statement', () => { + const model = new Model({ + field1: 'test', + dateCreated: new Date().toISOString(), + }); + + const expected = [ + 'INSERT INTO "Model" ("field1", "dateCreated", "id", "_version", "_lastChangedAt", "_deleted") VALUES (?, ?, ?, ?, ?, ?)', + [ + model.field1, + model.dateCreated, + model.id, + undefined, + undefined, + undefined, + ], + ]; + + expect(modelInsertStatement(model, 'Model')).toEqual(expected); + }); + }); + + describe('modelUpdateStatement', () => { + it('should generate valid UPDATE by id statement', () => { + const model = new Model({ + field1: 'test', + dateCreated: new Date().toISOString(), + }); + + const expected = [ + `UPDATE "Model" SET "field1"=?, "dateCreated"=?, "_version"=?, "_lastChangedAt"=?, "_deleted"=? WHERE id=?`, + [ + model.field1, + model.dateCreated, + undefined, + undefined, + undefined, + model.id, + ], + ]; + + expect(modelUpdateStatement(model, 'Model')).toEqual(expected); + }); + }); + + describe('whereClauseFromPredicate', () => { + it('should generate valid WHERE clause from predicate', () => { + const predicateGroup = { + type: 'and', + predicates: [ + { + field: 'firstName', + operator: 'eq', + operand: 'Bob', + }, + { + field: 'lastName', + operator: 'beginsWith', + operand: 'Sm', + }, + { + field: 'sortOrder', + operator: 'gt', + operand: 5, + }, + ], + }; + + const expected = [ + `WHERE ("firstName" = ? AND "lastName" LIKE ? AND "sortOrder" > ?)`, + ['Bob', 'Sm%', 5], + ]; + + expect(whereClauseFromPredicate(predicateGroup as any)).toEqual(expected); + }); + }); + + describe('limitClauseFromPagination', () => { + it('should generate valid LIMIT clause from pagination limit', () => { + const limit = 10; + + const expected = ['LIMIT ?', [10]]; + + expect(limitClauseFromPagination(limit)).toEqual(expected); + }); + + it('should generate valid LIMIT clause from pagination limit and page', () => { + const limit = 10; + const page = 3; + + const expected = ['LIMIT ? OFFSET ?', [10, 30]]; + + expect(limitClauseFromPagination(limit, page)).toEqual(expected); + }); + }); + + describe('orderByClauseFromSort', () => { + it('should generate valid ORDER BY clause from pagination sort', () => { + const sortPredicateGroup = [ + { + field: 'sortOrder', + sortDirection: 'ASCENDING', + }, + ]; + + const expected = 'ORDER BY "sortOrder" ASC, _rowid_ ASC'; + + expect(orderByClauseFromSort(sortPredicateGroup as any)).toEqual( + expected + ); + }); + + it('should generate valid ORDER BY clause from pagination sort - multi field', () => { + const sortPredicateGroup = [ + { + field: 'sortOrder', + sortDirection: 'ASCENDING', + }, + { + field: 'lastName', + sortDirection: 'DESCENDING', + }, + ]; + + const expected = 'ORDER BY "sortOrder" ASC, "lastName" DESC, _rowid_ ASC'; + + expect(orderByClauseFromSort(sortPredicateGroup as any)).toEqual( + expected + ); + }); + }); + + describe('deleteByIdStatement', () => { + it('should generate valid DELETE statement', () => { + const model = new Model({ + field1: 'test', + dateCreated: new Date().toISOString(), + }); + + const expected = ['DELETE FROM "Model" WHERE "id"=?', [model.id]]; + + expect(deleteByIdStatement(model.id, 'Model')).toEqual(expected); + }); + }); + + describe('deleteByPredicateStatement', () => { + it('should generate valid DELETE statement', () => { + const model = new Model({ + field1: 'test', + dateCreated: new Date().toISOString(), + }); + + const predicateGroup = { + type: 'and', + predicates: [ + { + field: 'createdAt', + operator: 'gt', + operand: '2021-06-20', + }, + ], + }; + + const expected = [ + 'DELETE FROM "Model" WHERE ("createdAt" > ?)', + ['2021-06-20'], + ]; + + expect( + deleteByPredicateStatement('Model', predicateGroup as any) + ).toEqual(expected); + }); + }); +}); + +const postEditorImplicit: SchemaModel = { + name: 'PostEditor', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + post: { + name: 'post', + isArray: false, + type: { model: 'Post' }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'postID', + }, + }, + editor: { + name: 'editor', + isArray: false, + type: { model: 'User' }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'editorID', + }, + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PostEditors', + attributes: [ + { type: 'model', properties: { queries: null } }, + { + type: 'key', + properties: { + name: 'byPost', + fields: ['postID', 'editorID'], + }, + }, + { + type: 'key', + properties: { + name: 'byEditor', + fields: ['editorID', 'postID'], + }, + }, + ], +}; + +const postEditorExplicit: SchemaModel = { + name: 'PostEditor', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + post: { + name: 'post', + isArray: false, + type: { model: 'Post' }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'postID', + }, + }, + postID: { + name: 'postID', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + editor: { + name: 'editor', + isArray: false, + type: { model: 'User' }, + isRequired: true, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'editorID', + }, + }, + editorID: { + name: 'editorID', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PostEditors', + attributes: [ + { type: 'model', properties: { queries: null } }, + { + type: 'key', + properties: { name: 'byPost', fields: ['postID', 'editorID'] }, + }, + { + type: 'key', + properties: { + name: 'byEditor', + fields: ['editorID', 'postID'], + }, + }, + ], +}; + +const ownerAuthImplicit: SchemaModel = { + name: 'OwnerAuthImplicit', + pluralName: 'OwnerAuthImplicit', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + }, + attributes: [ + { + type: 'auth', + properties: { + rules: [ + { + provider: 'userPools', + ownerField: 'owner', + allow: 'owner', + identityClaim: 'cognito:username', + operations: ['create', 'update', 'delete', 'read'], + }, + { + allow: 'public', + operations: ['read'], + }, + ], + }, + }, + ], +}; + +const ownerAuthExplicit: SchemaModel = { + name: 'OwnerAuthImplicit', + pluralName: 'OwnerAuthImplicit', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + owner: { + name: 'owner', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + attributes: [ + { + type: 'auth', + properties: { + rules: [ + { + provider: 'userPools', + ownerField: 'owner', + allow: 'owner', + identityClaim: 'cognito:username', + operations: ['create', 'update', 'delete', 'read'], + }, + { + allow: 'public', + operations: ['read'], + }, + ], + }, + }, + ], +}; + +const groupsAuthImplicit: SchemaModel = { + name: 'OwnerAuthImplicit', + pluralName: 'OwnerAuthImplicit', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + }, + attributes: [ + { + type: 'auth', + properties: { + rules: [ + { + groupClaim: 'cognito:groups', + provider: 'userPools', + allow: 'groups', + groupsField: 'allowedGroups', + operations: ['create', 'update', 'delete', 'read'], + }, + { + allow: 'public', + operations: ['read'], + }, + ], + }, + }, + ], +}; + +const groupsAuthExplicit: SchemaModel = { + name: 'OwnerAuthImplicit', + pluralName: 'OwnerAuthImplicit', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + allowedGroups: { + name: 'allowedGroups', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + attributes: [ + { + type: 'auth', + properties: { + rules: [ + { + groupClaim: 'cognito:groups', + provider: 'userPools', + allow: 'groups', + groupsField: 'allowedGroups', + operations: ['create', 'update', 'delete', 'read'], + }, + { + allow: 'public', + operations: ['read'], + }, + ], + }, + }, + ], +}; diff --git a/packages/datastore-storage-adapter/__tests__/helpers.ts b/packages/datastore-storage-adapter/__tests__/helpers.ts new file mode 100644 index 00000000000..8e2b00a1feb --- /dev/null +++ b/packages/datastore-storage-adapter/__tests__/helpers.ts @@ -0,0 +1,912 @@ +import { + ModelInit, + MutableModel, + Schema, + InternalSchema, + SchemaModel, +} from '@aws-amplify/datastore'; + +export declare class Model { + public readonly id: string; + public readonly field1: string; + public readonly optionalField1?: string; + public readonly dateCreated: string; + public readonly emails?: string[]; + public readonly ips?: (string | null)[]; + public readonly metadata?: Metadata; + public readonly createdAt?: string; + public readonly updatedAt?: string; + + constructor(init: ModelInit); + + static copyOf( + src: Model, + mutator: (draft: MutableModel) => void | Model + ): Model; +} +export declare class Metadata { + readonly author: string; + readonly tags?: string[]; + readonly rewards: string[]; + readonly penNames: string[]; + readonly nominations?: string[]; + readonly misc?: (string | null)[]; + constructor(init: Metadata); +} + +export declare class Post { + public readonly id: string; + public readonly title: string; +} + +export declare class Comment { + public readonly id: string; + public readonly content: string; + public readonly post: Post; +} + +export declare class User { + public readonly id: string; + public readonly name: string; + public readonly profileID: string; +} +export declare class Profile { + public readonly id: string; + public readonly firstName: string; + public readonly lastName: string; +} + +export declare class PostComposite { + public readonly id: string; + public readonly title: string; + public readonly description: string; + public readonly created: string; + public readonly sort: number; +} + +export declare class PostCustomPK { + public readonly id: string; + public readonly postId: number; + public readonly title: string; + public readonly description?: string; +} + +export declare class PostCustomPKSort { + public readonly id: string; + public readonly postId: number; + public readonly title: string; + public readonly description?: string; +} +export declare class PostCustomPKComposite { + public readonly id: string; + public readonly postId: number; + public readonly title: string; + public readonly description?: string; + public readonly sort: number; +} + +export function testSchema(): Schema { + return { + enums: {}, + models: { + Model: { + name: 'Model', + pluralName: 'Models', + syncable: true, + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + }, + field1: { + name: 'field1', + isArray: false, + type: 'String', + isRequired: true, + }, + optionalField1: { + name: 'optionalField1', + isArray: false, + type: 'String', + isRequired: false, + }, + dateCreated: { + name: 'dateCreated', + isArray: false, + type: 'AWSDateTime', + isRequired: true, + attributes: [], + }, + emails: { + name: 'emails', + isArray: true, + type: 'AWSEmail', + isRequired: true, + attributes: [], + isArrayNullable: true, + }, + ips: { + name: 'ips', + isArray: true, + type: 'AWSIPAddress', + isRequired: false, + attributes: [], + isArrayNullable: true, + }, + metadata: { + name: 'metadata', + isArray: false, + type: { + nonModel: 'Metadata', + }, + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + }, + Post: { + name: 'Post', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + title: { + name: 'title', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + comments: { + name: 'comments', + isArray: true, + type: { + model: 'Comment', + }, + isRequired: true, + attributes: [], + isArrayNullable: true, + association: { + connectionType: 'HAS_MANY', + associatedWith: 'postId', + }, + }, + }, + syncable: true, + pluralName: 'Posts', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + Comment: { + name: 'Comment', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + content: { + name: 'content', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + post: { + name: 'post', + isArray: false, + type: { + model: 'Post', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'BELONGS_TO', + targetName: 'postId', + }, + }, + }, + syncable: true, + pluralName: 'Comments', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'byPost', + fields: ['postId'], + }, + }, + ], + }, + LocalModel: { + name: 'LocalModel', + pluralName: 'LocalModels', + syncable: false, + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + }, + field1: { + name: 'field1', + isArray: false, + type: 'String', + isRequired: true, + }, + }, + }, + User: { + name: 'User', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + name: { + name: 'name', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + profileID: { + name: 'profileID', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + profile: { + name: 'profile', + isArray: false, + type: { + model: 'Profile', + }, + isRequired: false, + attributes: [], + association: { + connectionType: 'HAS_ONE', + associatedWith: 'id', + targetName: 'profileID', + }, + }, + }, + syncable: true, + pluralName: 'Users', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + Profile: { + name: 'Profile', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + firstName: { + name: 'firstName', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + lastName: { + name: 'lastName', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + }, + syncable: true, + pluralName: 'Profiles', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + PostComposite: { + name: 'PostComposite', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + title: { + name: 'title', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + description: { + name: 'description', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + created: { + name: 'created', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + sort: { + name: 'sort', + isArray: false, + type: 'Int', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PostComposites', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + name: 'titleCreatedSort', + fields: ['title', 'created', 'sort'], + }, + }, + ], + }, + PostCustomPK: { + name: 'PostCustomPK', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + postId: { + name: 'postId', + isArray: false, + type: 'Int', + isRequired: true, + attributes: [], + }, + title: { + name: 'title', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + description: { + name: 'description', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PostCustomPKS', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['postId'], + }, + }, + ], + }, + PostCustomPKSort: { + name: 'PostCustomPKSort', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + postId: { + name: 'postId', + isArray: false, + type: 'Int', + isRequired: true, + attributes: [], + }, + title: { + name: 'title', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + description: { + name: 'description', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PostCustomPKSorts', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['id', 'postId'], + }, + }, + ], + }, + PostCustomPKComposite: { + name: 'PostCustomPKComposite', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + postId: { + name: 'postId', + isArray: false, + type: 'Int', + isRequired: true, + attributes: [], + }, + title: { + name: 'title', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + description: { + name: 'description', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + sort: { + name: 'sort', + isArray: false, + type: 'Int', + isRequired: true, + attributes: [], + }, + }, + syncable: true, + pluralName: 'PostCustomPKComposites', + attributes: [ + { + type: 'model', + properties: {}, + }, + { + type: 'key', + properties: { + fields: ['id', 'postId', 'sort'], + }, + }, + ], + }, + }, + nonModels: { + Metadata: { + name: 'Metadata', + fields: { + author: { + name: 'author', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + tags: { + name: 'tags', + isArray: true, + type: 'String', + isRequired: false, + isArrayNullable: true, + attributes: [], + }, + rewards: { + name: 'rewards', + isArray: true, + type: 'String', + isRequired: true, + attributes: [], + }, + penNames: { + name: 'penNames', + isArray: true, + type: 'String', + isRequired: true, + isArrayNullable: true, + attributes: [], + }, + nominations: { + name: 'nominations', + isArray: true, + type: 'String', + isRequired: false, + attributes: [], + }, + misc: { + name: 'misc', + isArray: true, + type: 'String', + isRequired: false, + isArrayNullable: true, + attributes: [], + }, + }, + }, + }, + version: '1', + }; +} + +export function internalTestSchema(): InternalSchema { + return { + namespaces: { + datastore: { + name: 'datastore', + relationships: { + Setting: { + indexes: [], + relationTypes: [], + }, + }, + enums: {}, + nonModels: {}, + models: { + Setting: { + name: 'Setting', + pluralName: 'Settings', + syncable: false, + fields: { + id: { + name: 'id', + type: 'ID', + isRequired: true, + isArray: false, + }, + key: { + name: 'key', + type: 'String', + isRequired: true, + isArray: false, + }, + value: { + name: 'value', + type: 'String', + isRequired: true, + isArray: false, + }, + }, + }, + }, + }, + user: { + name: 'user', + enums: {}, + models: { + Model: { + name: 'Model', + pluralName: 'Models', + syncable: true, + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + }, + field1: { + name: 'field1', + isArray: false, + type: 'String', + isRequired: true, + }, + optionalField1: { + name: 'optionalField1', + isArray: false, + type: 'String', + isRequired: false, + }, + dateCreated: { + name: 'dateCreated', + isArray: false, + type: 'AWSDateTime', + isRequired: true, + attributes: [], + }, + emails: { + name: 'emails', + isArray: true, + type: 'AWSEmail', + isRequired: true, + attributes: [], + isArrayNullable: true, + }, + ips: { + name: 'ips', + isArray: true, + type: 'AWSIPAddress', + isRequired: false, + attributes: [], + isArrayNullable: true, + }, + metadata: { + name: 'metadata', + isArray: false, + type: { + nonModel: 'Metadata', + }, + isRequired: false, + attributes: [], + }, + }, + }, + LocalModel: { + name: 'LocalModel', + pluralName: 'LocalModels', + syncable: false, + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + }, + field1: { + name: 'field1', + isArray: false, + type: 'String', + isRequired: true, + }, + }, + }, + }, + nonModels: { + Metadata: { + name: 'Metadata', + fields: { + author: { + name: 'author', + isArray: false, + type: 'String', + isRequired: true, + attributes: [], + }, + tags: { + name: 'tags', + isArray: true, + type: 'String', + isRequired: false, + isArrayNullable: true, + attributes: [], + }, + rewards: { + name: 'rewards', + isArray: true, + type: 'String', + isRequired: true, + attributes: [], + }, + penNames: { + name: 'penNames', + isArray: true, + type: 'String', + isRequired: true, + isArrayNullable: true, + attributes: [], + }, + nominations: { + name: 'nominations', + isArray: true, + type: 'String', + isRequired: false, + attributes: [], + }, + misc: { + name: 'misc', + isArray: true, + type: 'String', + isRequired: false, + isArrayNullable: true, + attributes: [], + }, + }, + }, + }, + relationships: { + Model: { + indexes: [], + relationTypes: [], + }, + LocalModel: { + indexes: [], + relationTypes: [], + }, + }, + }, + sync: { + name: 'sync', + relationships: { + MutationEvent: { + indexes: [], + relationTypes: [], + }, + ModelMetadata: { + indexes: [], + relationTypes: [], + }, + }, + enums: { + OperationType: { + name: 'OperationType', + values: ['CREATE', 'UPDATE', 'DELETE'], + }, + }, + nonModels: {}, + models: { + MutationEvent: { + name: 'MutationEvent', + pluralName: 'MutationEvents', + syncable: false, + fields: { + id: { + name: 'id', + type: 'ID', + isRequired: true, + isArray: false, + }, + model: { + name: 'model', + type: 'String', + isRequired: true, + isArray: false, + }, + data: { + name: 'data', + type: 'String', + isRequired: true, + isArray: false, + }, + modelId: { + name: 'modelId', + type: 'String', + isRequired: true, + isArray: false, + }, + operation: { + name: 'operation', + type: { + enum: 'Operationtype', + }, + isArray: false, + isRequired: true, + }, + condition: { + name: 'condition', + type: 'String', + isArray: false, + isRequired: true, + }, + }, + }, + ModelMetadata: { + name: 'ModelMetadata', + pluralName: 'ModelsMetadata', + syncable: false, + fields: { + id: { + name: 'id', + type: 'ID', + isRequired: true, + isArray: false, + }, + namespace: { + name: 'namespace', + type: 'String', + isRequired: true, + isArray: false, + }, + model: { + name: 'model', + type: 'String', + isRequired: true, + isArray: false, + }, + lastSync: { + name: 'lastSync', + type: 'Int', + isRequired: false, + isArray: false, + }, + lastFullSync: { + name: 'lastFullSync', + type: 'Int', + isRequired: false, + isArray: false, + }, + fullSyncInterval: { + name: 'fullSyncInterval', + type: 'Int', + isRequired: true, + isArray: false, + }, + }, + }, + }, + }, + }, + version: '1', + }; +} diff --git a/packages/datastore-storage-adapter/build.js b/packages/datastore-storage-adapter/build.js new file mode 100644 index 00000000000..35e84b281a1 --- /dev/null +++ b/packages/datastore-storage-adapter/build.js @@ -0,0 +1,5 @@ +'use strict'; + +const build = require('../../scripts/build'); + +build(process.argv[2], process.argv[3]); diff --git a/packages/datastore-storage-adapter/index.js b/packages/datastore-storage-adapter/index.js new file mode 100644 index 00000000000..b47ac4febbd --- /dev/null +++ b/packages/datastore-storage-adapter/index.js @@ -0,0 +1,7 @@ +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./dist/aws-amplify-datastore-storage-adapter.min.js'); +} else { + module.exports = require('./dist/aws-amplify-datastore-storage-adapter.js'); +} diff --git a/packages/datastore-storage-adapter/package.json b/packages/datastore-storage-adapter/package.json new file mode 100644 index 00000000000..f157c8d40c0 --- /dev/null +++ b/packages/datastore-storage-adapter/package.json @@ -0,0 +1,93 @@ +{ + "name": "@aws-amplify/datastore-storage-adapter", + "version": "1.1.3", + "description": "SQLite storage adapter for Amplify DataStore ", + "main": "./lib/index.js", + "module": "./lib-esm/index.js", + "typings": "./lib-esm/index.d.ts", + "react-native": { + "./lib/index": "./lib-esm/index.js" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "test": "npm run lint && jest -w 1 --coverage", + "build-with-test": "npm test && npm run build", + "build:cjs": "node ./build es5 && webpack && webpack --config ./webpack.config.dev.js", + "build:esm": "node ./build es6", + "build:cjs:watch": "node ./build es5 --watch", + "build:esm:watch": "rimraf lib-esm && node ./build es6 --watch", + "build": "yarn clean && yarn build:esm && npm run build:cjs", + "clean": "rimraf lib-esm lib dist", + "format": "echo \"Not implemented\"", + "lint": "tslint '{__tests__,src}/**/*.ts'" + }, + "repository": { + "type": "git", + "url": "https://github.com/aws-amplify/amplify-js.git" + }, + "author": "Amazon Web Services", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/aws/aws-amplify/issues" + }, + "homepage": "https://aws-amplify.github.io/", + "dependencies": { + "@aws-amplify/core": "4.2.9", + "@aws-amplify/datastore": "3.4.3" + }, + "devDependencies": { + "react-native-sqlite-storage": "5.0.0" + }, + "jest": { + "globals": { + "ts-jest": { + "diagnostics": true, + "tsConfig": { + "lib": [ + "es5", + "es2015", + "esnext.asynciterable", + "es2019" + ], + "allowJs": true, + "esModuleInterop": true, + "downlevelIteration": true + } + } + }, + "transform": { + "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" + }, + "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", + "testPathIgnorePatterns": [ + "__tests__/model.ts", + "__tests__/schema.ts", + "__tests__/helpers.ts" + ], + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "json", + "jsx" + ], + "testEnvironment": "jsdom", + "testURL": "http://localhost/", + "coverageThreshold": { + "global": { + "branches": 0, + "functions": 0, + "lines": 0, + "statements": 0 + } + }, + "coveragePathIgnorePatterns": [ + "/node_modules/", + "dist", + "lib", + "lib-esm" + ] + } +} diff --git a/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteAdapter.ts b/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteAdapter.ts new file mode 100644 index 00000000000..1ec312e4c10 --- /dev/null +++ b/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteAdapter.ts @@ -0,0 +1,480 @@ +import { ConsoleLogger as Logger } from '@aws-amplify/core'; +import SQLiteDatabase from './SQLiteDatabase'; +import { + generateSchemaStatements, + queryByIdStatement, + modelUpdateStatement, + modelInsertStatement, + queryAllStatement, + queryOneStatement, + deleteByIdStatement, + deleteByPredicateStatement, + ParameterizedStatement, +} from './SQLiteUtils'; + +import { + StorageAdapter, + ModelInstanceCreator, + ModelPredicateCreator, + ModelSortPredicateCreator, + InternalSchema, + isPredicateObj, + ModelInstanceMetadata, + ModelPredicate, + NamespaceResolver, + OpType, + PaginationInput, + PersistentModel, + PersistentModelConstructor, + PredicateObject, + PredicatesGroup, + QueryOne, + utils, +} from '@aws-amplify/datastore'; + +const { traverseModel, validatePredicate, isModelConstructor } = utils; + +const logger = new Logger('DataStore'); +export class SQLiteAdapter implements StorageAdapter { + private schema: InternalSchema; + private namespaceResolver: NamespaceResolver; + private modelInstanceCreator: ModelInstanceCreator; + private getModelConstructorByModelName: ( + namsespaceName: string, + modelName: string + ) => PersistentModelConstructor; + private db: SQLiteDatabase; + private initPromise: Promise; + private resolve: (value?: any) => void; + private reject: (value?: any) => void; + + public async setUp( + theSchema: InternalSchema, + namespaceResolver: NamespaceResolver, + modelInstanceCreator: ModelInstanceCreator, + getModelConstructorByModelName: ( + namsespaceName: string, + modelName: string + ) => PersistentModelConstructor + ) { + if (!this.initPromise) { + this.initPromise = new Promise((res, rej) => { + this.resolve = res; + this.reject = rej; + }); + } else { + await this.initPromise; + return; + } + this.schema = theSchema; + this.namespaceResolver = namespaceResolver; + this.modelInstanceCreator = modelInstanceCreator; + this.getModelConstructorByModelName = getModelConstructorByModelName; + + try { + if (!this.db) { + this.db = new SQLiteDatabase(); + await this.db.init(); + + const statements = generateSchemaStatements(this.schema); + await this.db.createSchema(statements); + this.resolve(); + } + } catch (error) { + this.reject(error); + } + } + + async clear(): Promise { + await this.db.clear(); + + this.db = undefined; + this.initPromise = undefined; + } + + async save( + model: T, + condition?: ModelPredicate + ): Promise<[T, OpType.INSERT | OpType.UPDATE][]> { + const modelConstructor = Object.getPrototypeOf(model) + .constructor as PersistentModelConstructor; + const { name: tableName } = modelConstructor; + const connectedModels = traverseModel( + modelConstructor.name, + model, + this.schema.namespaces[this.namespaceResolver(modelConstructor)], + this.modelInstanceCreator, + this.getModelConstructorByModelName + ); + const connectionStoreNames = Object.values(connectedModels).map( + ({ modelName, item, instance }) => { + return { modelName, item, instance }; + } + ); + + const [queryStatement, params] = queryByIdStatement(model.id, tableName); + + const fromDB = await this.db.get(queryStatement, params); + + if (condition && fromDB) { + const predicates = ModelPredicateCreator.getPredicates(condition); + const { predicates: predicateObjs, type } = predicates; + + const isValid = validatePredicate(fromDB, type, predicateObjs); + + if (!isValid) { + const msg = 'Conditional update failed'; + logger.error(msg, { model: fromDB, condition: predicateObjs }); + + throw new Error(msg); + } + } + + const result: [T, OpType.INSERT | OpType.UPDATE][] = []; + const saveStatements = new Set(); + + for await (const resItem of connectionStoreNames) { + const { modelName, item, instance } = resItem; + const { id } = item; + + const [queryStatement, params] = queryByIdStatement(id, modelName); + const fromDB = await this.db.get(queryStatement, params); + + const opType: OpType = + fromDB === undefined ? OpType.INSERT : OpType.UPDATE; + + const saveStatement = fromDB + ? modelUpdateStatement(instance, modelName) + : modelInsertStatement(instance, modelName); + + saveStatements.add(saveStatement); + + result.push([instance, opType]); + } + + await this.db.batchSave(saveStatements); + + return result; + } + + private async load( + namespaceName: string, + srcModelName: string, + records: T[] + ): Promise { + const namespace = this.schema.namespaces[namespaceName]; + const relations = namespace.relationships[srcModelName].relationTypes; + const connectionTableNames = relations.map(({ modelName }) => modelName); + + const modelConstructor = this.getModelConstructorByModelName( + namespaceName, + srcModelName + ); + + if (connectionTableNames.length === 0) { + return records.map(record => + this.modelInstanceCreator(modelConstructor, record) + ); + } + + for await (const relation of relations) { + const { + fieldName, + modelName: tableName, + targetName, + relationType, + } = relation; + + const modelConstructor = this.getModelConstructorByModelName( + namespaceName, + tableName + ); + + // TODO: use SQL JOIN instead + switch (relationType) { + case 'HAS_ONE': + for await (const recordItem of records) { + if (recordItem[fieldName]) { + const [queryStatement, params] = queryByIdStatement( + recordItem[fieldName], + tableName + ); + + const connectionRecord = await this.db.get( + queryStatement, + params + ); + + recordItem[fieldName] = + connectionRecord && + this.modelInstanceCreator(modelConstructor, connectionRecord); + } + } + + break; + case 'BELONGS_TO': + for await (const recordItem of records) { + if (recordItem[targetName]) { + const [queryStatement, params] = queryByIdStatement( + recordItem[targetName], + tableName + ); + const connectionRecord = await this.db.get( + queryStatement, + params + ); + + recordItem[fieldName] = + connectionRecord && + this.modelInstanceCreator(modelConstructor, connectionRecord); + delete recordItem[targetName]; + } + } + + break; + case 'HAS_MANY': + // TODO: Lazy loading + break; + default: + const _: never = relationType; + throw new Error(`invalid relation type ${relationType}`); + break; + } + } + + return records.map(record => + this.modelInstanceCreator(modelConstructor, record) + ); + } + + async query( + modelConstructor: PersistentModelConstructor, + predicate?: ModelPredicate, + pagination?: PaginationInput + ): Promise { + const { name: tableName } = modelConstructor; + const namespaceName = this.namespaceResolver(modelConstructor); + + const predicates = + predicate && ModelPredicateCreator.getPredicates(predicate); + const sortPredicates = + pagination && + pagination.sort && + ModelSortPredicateCreator.getPredicates(pagination.sort); + const limit = pagination && pagination.limit; + const page = limit && pagination.page; + + const queryById = predicates && this.idFromPredicate(predicates); + + const records: T[] = await (async () => { + if (queryById) { + const record = await this.getById(tableName, queryById); + return record ? [record] : []; + } + + const [queryStatement, params] = queryAllStatement( + tableName, + predicates, + sortPredicates, + limit, + page + ); + + return await this.db.getAll(queryStatement, params); + })(); + + return await this.load(namespaceName, modelConstructor.name, records); + } + + private async getById( + tableName: string, + id: string + ): Promise { + const [queryStatement, params] = queryByIdStatement(id, tableName); + const record = await this.db.get(queryStatement, params); + return record; + } + + private idFromPredicate( + predicates: PredicatesGroup + ) { + const { predicates: predicateObjs } = predicates; + const idPredicate = + predicateObjs.length === 1 && + (predicateObjs.find( + p => isPredicateObj(p) && p.field === 'id' && p.operator === 'eq' + ) as PredicateObject); + + return idPredicate && idPredicate.operand; + } + + async queryOne( + modelConstructor: PersistentModelConstructor, + firstOrLast: QueryOne = QueryOne.FIRST + ): Promise { + const { name: tableName } = modelConstructor; + const [queryStatement, params] = queryOneStatement(firstOrLast, tableName); + + const result = await this.db.get(queryStatement, params); + + const modelInstance = + result && this.modelInstanceCreator(modelConstructor, result); + + return modelInstance; + } + + // Currently does not cascade + // TODO: use FKs in relations and have `ON DELETE CASCADE` set + // For Has Many and Has One relations to have SQL handle cascades automatically + async delete( + modelOrModelConstructor: T | PersistentModelConstructor, + condition?: ModelPredicate + ): Promise<[T[], T[]]> { + if (isModelConstructor(modelOrModelConstructor)) { + const modelConstructor = modelOrModelConstructor; + const namespaceName = this.namespaceResolver(modelConstructor); + const { name: tableName } = modelConstructor; + + const predicates = + condition && ModelPredicateCreator.getPredicates(condition); + + const queryStatement = queryAllStatement(tableName, predicates); + const deleteStatement = deleteByPredicateStatement(tableName, predicates); + + const models = await this.db.selectAndDelete( + queryStatement, + deleteStatement + ); + + const modelInstances = await this.load( + namespaceName, + modelConstructor.name, + models + ); + + return [modelInstances, modelInstances]; + } else { + const model = modelOrModelConstructor as T; + const modelConstructor = Object.getPrototypeOf(model) + .constructor as PersistentModelConstructor; + const { name: tableName } = modelConstructor; + + if (condition) { + const [queryStatement, params] = queryByIdStatement( + model.id, + tableName + ); + + const fromDB = await this.db.get(queryStatement, params); + + if (fromDB === undefined) { + const msg = 'Model instance not found in storage'; + logger.warn(msg, { model }); + + return [[model], []]; + } + + const predicates = ModelPredicateCreator.getPredicates(condition); + const { predicates: predicateObjs, type } = predicates; + + const isValid = validatePredicate(fromDB, type, predicateObjs); + + if (!isValid) { + const msg = 'Conditional update failed'; + logger.error(msg, { model: fromDB, condition: predicateObjs }); + + throw new Error(msg); + } + + const [deleteStatement, deleteParams] = deleteByIdStatement( + model.id, + tableName + ); + await this.db.save(deleteStatement, deleteParams); + return [[model], [model]]; + } else { + const [deleteStatement, params] = deleteByIdStatement( + model.id, + tableName + ); + await this.db.save(deleteStatement, params); + return [[model], [model]]; + } + } + } + + async batchSave( + modelConstructor: PersistentModelConstructor, + items: ModelInstanceMetadata[] + ): Promise<[T, OpType][]> { + const { name: tableName } = modelConstructor; + + const result: [T, OpType][] = []; + + const itemsToSave: T[] = []; + // To determine whether an item should result in an insert or update operation + // We first need to query the local DB on the item id + const queryStatements = new Set(); + // Deletes don't need to be queried first, because if the item doesn't exist, + // the delete operation will be a no-op + const deleteStatements = new Set(); + const saveStatements = new Set(); + + for (const item of items) { + const connectedModels = traverseModel( + modelConstructor.name, + this.modelInstanceCreator(modelConstructor, item), + this.schema.namespaces[this.namespaceResolver(modelConstructor)], + this.modelInstanceCreator, + this.getModelConstructorByModelName + ); + + const { id, _deleted } = item; + + const { instance } = connectedModels.find( + ({ instance }) => instance.id === id + ); + + if (_deleted) { + // create the delete statements right away + const deleteStatement = deleteByIdStatement(instance.id, tableName); + deleteStatements.add(deleteStatement); + result.push([(item), OpType.DELETE]); + } else { + // query statements for the saves at first + const queryStatement = queryByIdStatement(id, tableName); + queryStatements.add(queryStatement); + // combination of insert and update items + itemsToSave.push(instance); + } + } + + // returns the query results for each of the save items + const queryResponses = await this.db.batchQuery(queryStatements); + + queryResponses.forEach((response, idx) => { + if (response === undefined) { + const insertStatement = modelInsertStatement( + itemsToSave[idx], + tableName + ); + saveStatements.add(insertStatement); + result.push([(itemsToSave[idx]), OpType.INSERT]); + } else { + const updateStatement = modelUpdateStatement( + itemsToSave[idx], + tableName + ); + saveStatements.add(updateStatement); + result.push([(itemsToSave[idx]), OpType.UPDATE]); + } + }); + + // perform all of the insert/update/delete operations in a single transaction + await this.db.batchSave(saveStatements, deleteStatements); + + return result; + } +} + +export default new SQLiteAdapter(); diff --git a/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteDatabase.ts b/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteDatabase.ts new file mode 100644 index 00000000000..782bab10745 --- /dev/null +++ b/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteDatabase.ts @@ -0,0 +1,167 @@ +import SQLite from 'react-native-sqlite-storage'; +import { ConsoleLogger as Logger } from '@aws-amplify/core'; +import { PersistentModel } from '@aws-amplify/datastore'; +import { ParameterizedStatement } from './SQLiteUtils'; + +const logger = new Logger('SQLiteDatabase'); + +SQLite.enablePromise(true); + +if (Logger.LOG_LEVEL === 'DEBUG') { + SQLite.DEBUG(true); +} + +const DB_NAME = 'AmplifyDatastore'; +const DB_DISPLAYNAME = 'AWS Amplify DataStore SQLite Database'; + +// TODO: make these configurable +const DB_SIZE = 200000; +const DB_VERSION = '1.0'; + +/* + +Note: +I purposely avoided using arrow functions () => {} in this class, +Because I ran into issues with them in some of the SQLite method callbacks + +Also, even though the SQLite library is promisified, certain operations +only work correctly with callbacks. Specifically, any time you need to +get the result of an `executeSql` command inside of a transaction +(see the batchQuery method below) + +*/ + +class SQLiteDatabase { + private db: SQLite.SQLiteDatabase; + + public async init(): Promise { + this.db = await SQLite.openDatabase( + DB_NAME, + DB_VERSION, + DB_DISPLAYNAME, + DB_SIZE + ); + } + + public async createSchema(statements: string[]) { + return await this.executeStatements(statements); + } + + public async clear() { + await this.closeDB(); + logger.debug('Deleting database'); + await SQLite.deleteDatabase(DB_NAME); + logger.debug('Database deleted'); + } + + public async get( + statement: string, + params: any[] + ): Promise { + const [resultSet] = await this.db.executeSql(statement, params); + const result = + resultSet && + resultSet.rows && + resultSet.rows.length && + resultSet.rows.raw && + resultSet.rows.raw(); + + return result[0] || undefined; + } + + public async getAll( + statement: string, + params: any[] + ): Promise { + const [resultSet] = await this.db.executeSql(statement, params); + const result = + resultSet && + resultSet.rows && + resultSet.rows.length && + resultSet.rows.raw && + resultSet.rows.raw(); + + return result || []; + } + + public async save(statement: string, params: any[]): Promise { + await this.db.executeSql(statement, params); + } + + public async batchQuery(queryStatements: Set) { + const results = []; + + await this.db.readTransaction(function(tx) { + for (const [statement, params] of queryStatements) { + tx.executeSql( + statement, + params, + function(_tx, res) { + results.push(res.rows.raw()[0]); + }, + logger.warn + ); + } + }); + + return results; + } + + public async batchSave( + saveStatements: Set, + deleteStatements?: Set + ) { + await this.db.transaction(function(tx) { + for (const [statement, params] of saveStatements) { + tx.executeSql(statement, params); + } + if (deleteStatements) { + for (const [statement, params] of deleteStatements) { + tx.executeSql(statement, params); + } + } + }); + } + + public async selectAndDelete( + query: ParameterizedStatement, + _delete: ParameterizedStatement + ) { + let results = []; + + const [queryStatement, queryParams] = query; + const [deleteStatement, deleteParams] = _delete; + + await this.db.transaction(function(tx) { + tx.executeSql( + queryStatement, + queryParams, + function(_tx, res) { + results = res.rows.raw(); + }, + logger.warn + ); + tx.executeSql(deleteStatement, deleteParams, () => {}, logger.warn); + }); + + return results; + } + + private async executeStatements(statements: string[]): Promise { + return await this.db.transaction(function(tx) { + for (const statement of statements) { + tx.executeSql(statement); + } + }); + } + + private async closeDB() { + if (this.db) { + logger.debug('Closing Database'); + await this.db.close(); + logger.debug('Database closed'); + } + } +} + +export default SQLiteDatabase; diff --git a/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteUtils.ts b/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteUtils.ts new file mode 100644 index 00000000000..8f33cbf5696 --- /dev/null +++ b/packages/datastore-storage-adapter/src/SQLiteAdapter/SQLiteUtils.ts @@ -0,0 +1,427 @@ +import { + InternalSchema, + SchemaModel, + ModelField, + PersistentModel, + isGraphQLScalarType, + QueryOne, + PredicatesGroup, + isPredicateObj, + SortPredicatesGroup, + PredicateObject, + isPredicateGroup, + isModelFieldType, + isTargetNameAssociation, + isModelAttributeAuth, + ModelAttributeAuth, + ModelAuthRule, + utils, +} from '@aws-amplify/datastore'; + +import { getSQLiteType } from './types'; + +const { USER, isNonModelConstructor, isModelConstructor } = utils; + +export type ParameterizedStatement = [string, any[]]; + +const keysFromModel = model => + Object.keys(model) + .map(k => `"${k}"`) + .join(', '); + +const valuesFromModel = (model): [string, any[]] => { + const values = Object.values(model).map(prepareValueForDML); + const paramaterized = values.map(() => '?').join(', '); + + return [paramaterized, values]; +}; + +const updateSet: (model: any) => [any, any] = model => { + const values = []; + const paramaterized = Object.entries(model) + .filter(([k]) => k !== 'id') + .map(([k, v]) => { + values.push(prepareValueForDML(v)); + return `"${k}"=?`; + }) + .join(', '); + + return [paramaterized, values]; +}; + +function prepareValueForDML(value: unknown): any { + const scalarTypes = ['string', 'number', 'boolean']; + + const isScalarType = + value === null || value === undefined || scalarTypes.includes(typeof value); + + if (isScalarType) { + return value; + } + + const isObjectType = + typeof value === 'object' && + (Object.getPrototypeOf(value).constructor === Object || + isNonModelConstructor(Object.getPrototypeOf(value).constructor) || + isModelConstructor(Object.getPrototypeOf(value).constructor)); + + if (Array.isArray(value) || isObjectType) { + return JSON.stringify(value); + } + + return `${value}`; +} + +export function generateSchemaStatements(schema: InternalSchema): string[] { + return Object.keys(schema.namespaces).flatMap(namespaceName => { + const namespace = schema.namespaces[namespaceName]; + const isUserModel = namespaceName === USER; + + return Object.values(namespace.models).map(model => + modelCreateTableStatement(model, isUserModel) + ); + }); +} + +export const implicitAuthFieldsForModel: (model: SchemaModel) => string[] = ( + model: SchemaModel +) => { + if (!model.attributes || !model.attributes.length) { + return []; + } + + const authRules: ModelAttributeAuth = model.attributes.find( + isModelAttributeAuth + ); + + if (!authRules) { + return []; + } + + const authFieldsForModel = authRules.properties.rules + .filter((rule: ModelAuthRule) => rule.ownerField || rule.groupsField) + .map((rule: ModelAuthRule) => rule.ownerField || rule.groupsField); + + return authFieldsForModel.filter((authField: string) => { + const authFieldExplicitlyDefined = Object.values(model.fields).find( + (f: ModelField) => f.name === authField + ); + return !authFieldExplicitlyDefined; + }); +}; + +export function modelCreateTableStatement( + model: SchemaModel, + userModel: boolean = false +): string { + // implicitly defined auth fields, e.g., `owner`, `groupsField`, etc. + const implicitAuthFields = implicitAuthFieldsForModel(model); + + let fields = Object.values(model.fields).reduce((acc, field: ModelField) => { + if (isGraphQLScalarType(field.type)) { + if (field.name === 'id') { + return acc + '"id" PRIMARY KEY NOT NULL'; + } + + let columnParam = `"${field.name}" ${getSQLiteType(field.type)}`; + + if (field.isRequired) { + columnParam += ' NOT NULL'; + } + + return acc + `, ${columnParam}`; + } + + if (isModelFieldType(field.type)) { + // add targetName as well as field name for BELONGS_TO relations + if (isTargetNameAssociation(field.association)) { + const required = field.isRequired ? ' NOT NULL' : ''; + + let columnParam = `"${field.name}" TEXT`; + // check if this field has been explicitly defined in the model + const fkDefinedInModel = Object.values(model.fields).find( + (f: ModelField) => f.name === field.association.targetName + ); + + // only add auto-generate it if not + if (!fkDefinedInModel) { + columnParam += `, "${field.association.targetName}" TEXT${required}`; + } + + return acc + `, ${columnParam}`; + } + } + + // default to TEXT + let columnParam = `"${field.name}" TEXT`; + + if (field.isRequired) { + columnParam += ' NOT NULL'; + } + + return acc + `, ${columnParam}`; + }, ''); + + implicitAuthFields.forEach((authField: string) => { + fields += `, ${authField} TEXT`; + }); + + if (userModel) { + fields += + ', "_version" INTEGER, "_lastChangedAt" INTEGER, "_deleted" INTEGER'; + } + + const createTableStatement = `CREATE TABLE IF NOT EXISTS "${model.name}" (${fields});`; + return createTableStatement; +} + +export function modelInsertStatement( + model: PersistentModel, + tableName: string +): ParameterizedStatement { + const keys = keysFromModel(model); + const [paramaterized, values] = valuesFromModel(model); + + const insertStatement = `INSERT INTO "${tableName}" (${keys}) VALUES (${paramaterized})`; + + return [insertStatement, values]; +} + +export function modelUpdateStatement( + model: PersistentModel, + tableName: string +): ParameterizedStatement { + const [paramaterized, values] = updateSet(model); + + const updateStatement = `UPDATE "${tableName}" SET ${paramaterized} WHERE id=?`; + + return [updateStatement, [...values, model.id]]; +} + +export function queryByIdStatement( + id: string, + tableName: string +): ParameterizedStatement { + return [`SELECT * FROM "${tableName}" WHERE "id" = ?`, [id]]; +} + +/* + Predicates supported by DataStore: + + Strings: eq | ne | le | lt | ge | gt | contains | notContains | beginsWith | between + Numbers: eq | ne | le | lt | ge | gt | between + Lists: contains | notContains +*/ + +const comparisonOperatorMap = { + eq: '=', + ne: '!=', + le: '<=', + lt: '<', + ge: '>=', + gt: '>', +}; + +const logicalOperatorMap = { + beginsWith: 'LIKE', + contains: 'LIKE', + notContains: 'NOT LIKE', + between: 'BETWEEN', +}; + +const whereConditionFromPredicateObject = ({ + field, + operator, + operand, +}: { + field: string; + operator: + | keyof typeof logicalOperatorMap + | keyof typeof comparisonOperatorMap; + operand: any; +}): ParameterizedStatement => { + const comparisonOperator = comparisonOperatorMap[operator]; + + if (comparisonOperator) { + return [`"${field}" ${comparisonOperator} ?`, [operand]]; + } + + const logicalOperatorKey = operator; + const logicalOperator = logicalOperatorMap[logicalOperatorKey]; + + if (logicalOperator) { + let rightExp = []; + switch (logicalOperatorKey) { + case 'between': + rightExp = operand; // operand is a 2-tuple + break; + case 'beginsWith': + rightExp = [`${operand}%`]; + break; + case 'contains': + case 'notContains': + rightExp = [`%${operand}%`]; + break; + default: + const _: never = logicalOperatorKey; + // Incorrect WHERE clause can result in data loss + throw new Error('Cannot map predicate to a valid WHERE clause'); + } + return [ + `"${field}" ${logicalOperator} ${rightExp.map(_ => '?').join(' AND ')}`, + rightExp, + ]; + } +}; + +export function whereClauseFromPredicate( + predicate: PredicatesGroup +): ParameterizedStatement { + const result = []; + const params = []; + + recurse(predicate, result, params); + const whereClause = `WHERE ${result.join(' ')}`; + + return [whereClause, params]; + + function recurse( + predicate: PredicatesGroup | PredicateObject, + result = [], + params = [] + ): void { + if (isPredicateGroup(predicate)) { + const { type: groupType, predicates: groupPredicates } = predicate; + let filterType: string = ''; + let isNegation = false; + switch (groupType) { + case 'not': + isNegation = true; + break; + case 'and': + filterType = 'AND'; + break; + case 'or': + filterType = 'OR'; + break; + default: + const _: never = groupType; + throw new Error(`Invalid ${groupType}`); + } + + const groupResult = []; + for (const p of groupPredicates) { + recurse(p, groupResult, params); + } + result.push( + `${isNegation ? 'NOT' : ''}(${groupResult.join(` ${filterType} `)})` + ); + } else if (isPredicateObj(predicate)) { + const [condition, conditionParams] = whereConditionFromPredicateObject( + predicate + ); + + result.push(condition); + params.push(...conditionParams); + } + } +} + +const sortDirectionMap = { + ASCENDING: 'ASC', + DESCENDING: 'DESC', +}; + +export function orderByClauseFromSort( + sortPredicate: SortPredicatesGroup = [] +): string { + const orderByParts = sortPredicate.map( + ({ field, sortDirection }) => + `"${field}" ${sortDirectionMap[sortDirection]}` + ); + + // We always sort by _rowid_ last + orderByParts.push(`_rowid_ ${sortDirectionMap.ASCENDING}`); + + return `ORDER BY ${orderByParts.join(', ')}`; +} + +export function limitClauseFromPagination( + limit: number, + page: number = 0 +): ParameterizedStatement { + const params = [limit]; + let clause = 'LIMIT ?'; + if (page) { + const offset = limit * page; + params.push(offset); + clause += ' OFFSET ?'; + } + + return [clause, params]; +} + +export function queryAllStatement( + tableName: string, + predicate?: PredicatesGroup, + sort?: SortPredicatesGroup, + limit?: number, + page?: number +): ParameterizedStatement { + let statement = `SELECT * FROM "${tableName}"`; + const params = []; + + if (predicate && predicate.predicates.length) { + const [whereClause, whereParams] = whereClauseFromPredicate(predicate); + statement += ` ${whereClause}`; + params.push(...whereParams); + } + + const orderByClause = orderByClauseFromSort(sort); + statement += ` ${orderByClause}`; + + if (limit) { + const [limitClause, limitParams] = limitClauseFromPagination(limit, page); + statement += ` ${limitClause}`; + params.push(...limitParams); + } + + return [statement, params]; +} + +export function queryOneStatement( + firstOrLast, + tableName: string +): ParameterizedStatement { + if (firstOrLast === QueryOne.FIRST) { + // ORDER BY rowid will no longer work as expected if a customer has + // a field by that name in their schema. We may want to enforce it + // as a reserved keyword in Codegen + return [`SELECT * FROM ${tableName} ORDER BY _rowid_ LIMIT 1`, []]; + } else { + return [`SELECT * FROM ${tableName} ORDER BY _rowid_ DESC LIMIT 1`, []]; + } +} + +export function deleteByIdStatement( + id: string, + tableName: string +): ParameterizedStatement { + const deleteStatement = `DELETE FROM "${tableName}" WHERE "id"=?`; + return [deleteStatement, [id]]; +} + +export function deleteByPredicateStatement( + tableName: string, + predicate?: PredicatesGroup +): ParameterizedStatement { + let statement = `DELETE FROM "${tableName}"`; + const params = []; + + if (predicate && predicate.predicates.length) { + const [whereClause, whereParams] = whereClauseFromPredicate(predicate); + statement += ` ${whereClause}`; + params.push(...whereParams); + } + return [statement, params]; +} diff --git a/packages/datastore-storage-adapter/src/SQLiteAdapter/types.ts b/packages/datastore-storage-adapter/src/SQLiteAdapter/types.ts new file mode 100644 index 00000000000..dd781657c57 --- /dev/null +++ b/packages/datastore-storage-adapter/src/SQLiteAdapter/types.ts @@ -0,0 +1,31 @@ +import { GraphQLScalarType } from '@aws-amplify/datastore'; + +export function getSQLiteType( + scalar: keyof Omit< + typeof GraphQLScalarType, + 'getJSType' | 'getValidationFunction' | 'getSQLiteType' + > +): 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' { + switch (scalar) { + case 'Boolean': + case 'Int': + case 'AWSTimestamp': + return 'INTEGER'; + case 'ID': + case 'String': + case 'AWSDate': + case 'AWSTime': + case 'AWSDateTime': + case 'AWSEmail': + case 'AWSJSON': + case 'AWSURL': + case 'AWSPhone': + case 'AWSIPAddress': + return 'TEXT'; + case 'Float': + return 'REAL'; + default: + const _: never = scalar; + throw new Error(`unknown type ${scalar}`); + } +} diff --git a/packages/datastore-storage-adapter/src/index.ts b/packages/datastore-storage-adapter/src/index.ts new file mode 100644 index 00000000000..b771fd5286d --- /dev/null +++ b/packages/datastore-storage-adapter/src/index.ts @@ -0,0 +1,2 @@ +import SQLiteAdapter from './SQLiteAdapter/SQLiteAdapter'; +export { SQLiteAdapter }; diff --git a/packages/datastore-storage-adapter/tslint.json b/packages/datastore-storage-adapter/tslint.json new file mode 100644 index 00000000000..8eafab1d2b4 --- /dev/null +++ b/packages/datastore-storage-adapter/tslint.json @@ -0,0 +1,50 @@ +{ + "defaultSeverity": "error", + "plugins": ["prettier"], + "extends": [], + "jsRules": {}, + "rules": { + "prefer-const": true, + "max-line-length": [true, 120], + "no-empty-interface": true, + "no-var-keyword": true, + "object-literal-shorthand": true, + "no-eval": true, + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never" + } + ], + "no-parameter-reassignment": true, + "align": [true, "parameters"], + "no-duplicate-imports": true, + "one-variable-per-declaration": [false, "ignore-for-loop"], + "triple-equals": [true, "allow-null-check"], + "comment-format": [true, "check-space"], + "indent": [false], + "whitespace": [ + false, + "check-branch", + "check-decl", + "check-operator", + "check-preblock" + ], + "eofline": true, + "variable-name": [ + true, + "check-format", + "allow-pascal-case", + "allow-snake-case", + "allow-leading-underscore" + ], + "semicolon": [ + true, + "always", + "ignore-interfaces", + "ignore-bound-class-methods" + ] + }, + "rulesDirectory": [] +} diff --git a/packages/datastore-storage-adapter/webpack.config.dev.js b/packages/datastore-storage-adapter/webpack.config.dev.js new file mode 100644 index 00000000000..31512a1245b --- /dev/null +++ b/packages/datastore-storage-adapter/webpack.config.dev.js @@ -0,0 +1,6 @@ +var config = require('./webpack.config.js'); + +var entry = { + 'aws-amplify-datastore-storage-adapter': './lib-esm/index.js', +}; +module.exports = Object.assign(config, { entry, mode: 'development' }); diff --git a/packages/datastore-storage-adapter/webpack.config.js b/packages/datastore-storage-adapter/webpack.config.js new file mode 100644 index 00000000000..ecc1d2fcb18 --- /dev/null +++ b/packages/datastore-storage-adapter/webpack.config.js @@ -0,0 +1,44 @@ +module.exports = { + entry: { + 'aws-amplify-datastore-storage-adapter.min': './lib-esm/index.js', + }, + externals: [ + '@aws-amplify/datastore', + '@aws-amplify/core', + 'react-native-sqlite-storage', + ], + output: { + filename: '[name].js', + path: __dirname + '/dist', + library: 'aws-amplify-datastore-storage-adapter', + libraryTarget: 'umd', + umdNamedDefine: true, + devtoolModuleFilenameTemplate: require('../aws-amplify/webpack-utils') + .devtoolModuleFilenameTemplate, + }, + // Enable sourcemaps for debugging webpack's output. + devtool: 'source-map', + resolve: { + extensions: ['.mjs', '.js', '.json'], + }, + mode: 'production', + module: { + rules: [ + // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. + //{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }, + { + test: /\.js?$/, + exclude: /node_modules/, + use: [ + 'babel-loader', + { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'], + }, + }, + ], + }, + ], + }, +}; diff --git a/packages/datastore/CHANGELOG.md b/packages/datastore/CHANGELOG.md index e7ecf755ee0..1525927d6b1 100644 --- a/packages/datastore/CHANGELOG.md +++ b/packages/datastore/CHANGELOG.md @@ -3,6 +3,88 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.4.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.4.2...@aws-amplify/datastore@3.4.3) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/datastore + + + + + +## [3.4.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.4.1...@aws-amplify/datastore@3.4.2) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/datastore + + + + + +## [3.4.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.4.0...@aws-amplify/datastore@3.4.1) (2021-09-04) + + +### Bug Fixes + +* **@aws-amplify/datastore:** only stringify nested AWSJSON in mutation event ([#8844](https://github.com/aws-amplify/amplify-js/issues/8844)) ([0febaac](https://github.com/aws-amplify/amplify-js/commit/0febaac79af1b9fd0621dce1e63a139bebdb46f5)) + + + + + +# [3.4.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.3.3...@aws-amplify/datastore@3.4.0) (2021-09-02) + + +### Bug Fixes + +* **@aws-amplify/datastore:** patch immer vuln ([#8841](https://github.com/aws-amplify/amplify-js/issues/8841)) ([6521a57](https://github.com/aws-amplify/amplify-js/commit/6521a576572f21a91738e2bdc37ffb21350392d0)) +* **@aws-amplify/datastore:** remove conditional require ([#8828](https://github.com/aws-amplify/amplify-js/issues/8828)) ([48b76e1](https://github.com/aws-amplify/amplify-js/commit/48b76e10602b0b5cc9bc43b9b3abd653e27e1817)) + + +### Features + +* **@aws-amplify/datastore:** add SQLite storage adapter option for RN apps ([#8809](https://github.com/aws-amplify/amplify-js/issues/8809)) ([46ee5dd](https://github.com/aws-amplify/amplify-js/commit/46ee5dd91c61f49bad4da8286b2f97c737d96631)) + + + + + +## [3.3.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.3.2...@aws-amplify/datastore@3.3.3) (2021-08-26) + + +### Bug Fixes + +* **@aws-amplify/datastore:** check read-only at instance level ([#8794](https://github.com/aws-amplify/amplify-js/issues/8794)) ([b278875](https://github.com/aws-amplify/amplify-js/commit/b278875491bf6959591d5aea6fbdddfc78f3fe9b)) + + + + + +## [3.3.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.3.1...@aws-amplify/datastore@3.3.2) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/datastore + + + + + +## [3.3.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.3.0...@aws-amplify/datastore@3.3.1) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/datastore + + + + + +# [3.3.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.2.2...@aws-amplify/datastore@3.3.0) (2021-07-28) + + +### Features + +* **@aws-amplify/datastore:** support lambda authorizers ([52d43cc](https://github.com/aws-amplify/amplify-js/commit/52d43cc73b459148f1ae81ab81d3a5365a4457e3)) + + + + + ## [3.2.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@3.2.1...@aws-amplify/datastore@3.2.2) (2021-07-22) diff --git a/packages/datastore/__tests__/DataStore.ts b/packages/datastore/__tests__/DataStore.ts index 3339d7709e7..5a6d5f36f34 100644 --- a/packages/datastore/__tests__/DataStore.ts +++ b/packages/datastore/__tests__/DataStore.ts @@ -557,36 +557,30 @@ describe('DataStore tests', () => { const { Model } = classes as { Model: PersistentModelConstructor }; - model = new Model({ - field1: 'something', - dateCreated: new Date().toISOString(), - createdAt: '2021-06-03T20:56:23.201Z', - } as any); - - await expect(DataStore.save(model)).rejects.toThrowError( - 'createdAt is read-only.' - ); + expect(() => { + new Model({ + field1: 'something', + dateCreated: new Date().toISOString(), + createdAt: '2021-06-03T20:56:23.201Z', + } as any); + }).toThrow('createdAt is read-only.'); model = new Model({ field1: 'something', dateCreated: new Date().toISOString(), }); - model = Model.copyOf(model, draft => { - (draft as any).createdAt = '2021-06-03T20:56:23.201Z'; - }); - - await expect(DataStore.save(model)).rejects.toThrowError( - 'createdAt is read-only.' - ); - - model = Model.copyOf(model, draft => { - (draft as any).updatedAt = '2021-06-03T20:56:23.201Z'; - }); + expect(() => { + Model.copyOf(model, draft => { + (draft as any).createdAt = '2021-06-03T20:56:23.201Z'; + }); + }).toThrow('createdAt is read-only.'); - await expect(DataStore.save(model)).rejects.toThrowError( - 'updatedAt is read-only.' - ); + expect(() => { + Model.copyOf(model, draft => { + (draft as any).updatedAt = '2021-06-03T20:56:23.201Z'; + }); + }).toThrow('updatedAt is read-only.'); }); test('Instantiation validations', async () => { diff --git a/packages/datastore/package.json b/packages/datastore/package.json index f07f9d544b1..40ade3c18cc 100644 --- a/packages/datastore/package.json +++ b/packages/datastore/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/datastore", - "version": "3.2.2", + "version": "3.4.3", "description": "AppSyncLocal support for aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -48,13 +48,13 @@ "fake-indexeddb": "3.0.0" }, "dependencies": { - "@aws-amplify/api": "4.0.7", - "@aws-amplify/auth": "4.1.3", - "@aws-amplify/core": "4.2.1", - "@aws-amplify/pubsub": "4.0.7", - "amazon-cognito-identity-js": "5.0.6", + "@aws-amplify/api": "4.0.15", + "@aws-amplify/auth": "4.3.5", + "@aws-amplify/core": "4.2.9", + "@aws-amplify/pubsub": "4.1.7", + "amazon-cognito-identity-js": "5.1.0", "idb": "5.0.6", - "immer": "8.0.1", + "immer": "9.0.6", "ulid": "2.3.0", "uuid": "3.3.2", "zen-observable-ts": "0.8.19", @@ -70,7 +70,7 @@ "es2015", "dom", "esnext.asynciterable", - "es2019.object" + "es2019" ], "allowJs": true, "esModuleInterop": true, diff --git a/packages/datastore/src/datastore/datastore.ts b/packages/datastore/src/datastore/datastore.ts index 94e21b58205..cf61efaaebd 100644 --- a/packages/datastore/src/datastore/datastore.ts +++ b/packages/datastore/src/datastore/datastore.ts @@ -16,6 +16,7 @@ import { ModelSortPredicateCreator, PredicateAll, } from '../predicates'; +import { Adapter } from '../storage/adapter'; import { ExclusiveStorage as Storage } from '../storage/storage'; import { ControlMessage, SyncEngine } from '../sync'; import { @@ -49,7 +50,8 @@ import { ErrorHandler, SyncExpression, AuthModeStrategyType, - ModelFields, + isNonModelFieldType, + isModelFieldType, } from '../types'; import { DATASTORE, @@ -62,6 +64,7 @@ import { SYNC, USER, isNullOrUndefined, + registerNonModelClass, } from '../util'; setAutoFreeze(true); @@ -277,6 +280,20 @@ const validateModelFields = (modelDefinition: SchemaModel | SchemaNonModel) => ( const jsType = GraphQLScalarType.getJSType(type); const validateScalar = GraphQLScalarType.getValidationFunction(type); + if (type === 'AWSJSON') { + if (typeof v === jsType) { + return; + } + if (typeof v === 'string') { + try { + JSON.parse(v); + return; + } catch (error) { + throw new Error(`Field ${name} is an invalid JSON object. ${v}`); + } + } + } + if (isArray) { let errorTypeText: string = jsType; if (!isRequired) { @@ -340,6 +357,35 @@ const validateModelFields = (modelDefinition: SchemaModel | SchemaNonModel) => ( } }; +const castInstanceType = ( + modelDefinition: SchemaModel | SchemaNonModel, + k: string, + v: any +) => { + const { isArray, type } = modelDefinition.fields[k] || {}; + // attempt to parse stringified JSON + if ( + typeof v === 'string' && + (isArray || + type === 'AWSJSON' || + isNonModelFieldType(type) || + isModelFieldType(type)) + ) { + try { + return JSON.parse(v); + } catch { + // if JSON is invalid, don't throw and let modelValidator handle it + } + } + + // cast from numeric representation of boolean to JS boolean + if (typeof v === 'number' && type === 'Boolean') { + return Boolean(v); + } + + return v; +}; + const initializeInstance = ( init: ModelInit, modelDefinition: SchemaModel | SchemaNonModel, @@ -347,8 +393,10 @@ const initializeInstance = ( ) => { const modelValidator = validateModelFields(modelDefinition); Object.entries(init).forEach(([k, v]) => { - modelValidator(k, v); - (draft)[k] = v; + const parsedValue = castInstanceType(modelDefinition, k, v); + + modelValidator(k, parsedValue); + (draft)[k] = parsedValue; }); }; @@ -374,13 +422,18 @@ const createModelClass = ( _deleted, } = modelInstanceMetadata; - const id = - // instancesIds is set by modelInstanceCreator, it is accessible only internally - _id !== null && _id !== undefined - ? _id - : modelDefinition.syncable - ? uuid4() - : ulid(); + // instancesIds are set by modelInstanceCreator, it is accessible only internally + const isInternal = _id !== null && _id !== undefined; + + const id = isInternal + ? _id + : modelDefinition.syncable + ? uuid4() + : ulid(); + + if (!isInternal) { + checkReadOnlyPropertyOnCreate(draft, modelDefinition); + } draft.id = id; @@ -411,7 +464,9 @@ const createModelClass = ( draft.id = source.id; const modelValidator = validateModelFields(modelDefinition); Object.entries(draft).forEach(([k, v]) => { - modelValidator(k, v); + const parsedValue = castInstanceType(modelDefinition, k, v); + + modelValidator(k, parsedValue); }); }, p => (patches = p) @@ -419,6 +474,7 @@ const createModelClass = ( if (patches.length) { modelPatchesMap.set(model, [patches, source]); + checkReadOnlyPropertyOnUpdate(patches, modelDefinition); } return model; @@ -449,6 +505,36 @@ const createModelClass = ( return clazz; }; +const checkReadOnlyPropertyOnCreate = ( + draft: T, + modelDefinition: SchemaModel +) => { + const modelKeys = Object.keys(draft); + const { fields } = modelDefinition; + + modelKeys.forEach(key => { + if (fields[key] && fields[key].isReadOnly) { + throw new Error(`${key} is read-only.`); + } + }); +}; + +const checkReadOnlyPropertyOnUpdate = ( + patches: Patch[], + modelDefinition: SchemaModel +) => { + const patchArray = patches.map(p => [p.path[0], p.value]); + const { fields } = modelDefinition; + + patchArray.forEach(([key, val]) => { + if (!val || !fields[key]) return; + + if (fields[key].isReadOnly) { + throw new Error(`${key} is read-only.`); + } + }); +}; + const createNonModelClass = (typeDefinition: SchemaNonModel) => { const clazz = >(class Model { constructor(init: ModelInit) { @@ -467,6 +553,8 @@ const createNonModelClass = (typeDefinition: SchemaNonModel) => { Object.defineProperty(clazz, 'name', { value: typeDefinition.name }); + registerNonModelClass(clazz); + return clazz; }; @@ -617,7 +705,7 @@ class DataStore { ModelPredicate > = new WeakMap>(); private sessionId: string; - private getAuthToken: Promise; + private storageAdapter: Adapter; getModuleName() { return 'DataStore'; @@ -641,7 +729,7 @@ class DataStore { namespaceResolver, getModelConstructorByModelName, modelInstanceCreator, - undefined, + this.storageAdapter, this.sessionId ); @@ -815,9 +903,6 @@ class DataStore { const modelDefinition = getModelDefinition(modelConstructor); - // ensuring "read-only" data isn't being overwritten - this.checkReadOnlyProperty(modelDefinition.fields, model, patchesTuple); - const producedCondition = ModelPredicateCreator.createFromExisting( modelDefinition, condition @@ -835,46 +920,6 @@ class DataStore { return savedModel; }; - private checkReadOnlyProperty( - fields: ModelFields, - model: Record, - patchesTuple: [ - Patch[], - Readonly< - { - id: string; - } & Record - > - ] - ) { - if (!patchesTuple) { - // saving a new model instance - const modelKeys = Object.keys(model); - modelKeys.forEach(key => { - if (fields[key] && fields[key].isReadOnly) { - throw new Error(`${key} is read-only.`); - } - }); - } else { - // * Updating an existing instance via 'patchesTuple' - // patchesTuple[0] is an object that contains the info we need - // like the 'path' (mapped to the model's key) and the 'value' of the patch - const patchArray = patchesTuple[0].map(p => [p.path[0], p.value]); - patchArray.forEach(patch => { - const [key, val] = [...patch]; - - // the value of a read-only field should be undefined - if so, no need to do the following check - if (!val || !fields[key]) return; - - // if the value is NOT undefined, we have to check the 'isReadOnly' property - // and throw an error to avoid persisting a mutation - if (fields[key].isReadOnly) { - throw new Error(`${key} is read-only.`); - } - }); - } - } - setConflictHandler = (config: DataStoreConfig): ConflictHandler => { const { DataStore: configDataStore } = config; @@ -1112,6 +1157,7 @@ class DataStore { fullSyncInterval: configFullSyncInterval, syncExpressions: configSyncExpressions, authProviders: configAuthProviders, + storageAdapter: configStorageAdapter, ...configFromAmplify } = config; @@ -1162,6 +1208,12 @@ class DataStore { configFullSyncInterval || 24 * 60; // 1 day + this.storageAdapter = + (configDataStore && configDataStore.storageAdapter) || + this.storageAdapter || + configStorageAdapter || + undefined; + this.sessionId = this.retrieveSessionId(); }; diff --git a/packages/datastore/src/index.ts b/packages/datastore/src/index.ts index 7689c7c7a5c..cd86f64ba03 100644 --- a/packages/datastore/src/index.ts +++ b/packages/datastore/src/index.ts @@ -1,3 +1,31 @@ -export { DataStore, DataStoreClass, initSchema } from './datastore/datastore'; -export { Predicates } from './predicates'; +export { + DataStore, + DataStoreClass, + initSchema, + ModelInstanceCreator, +} from './datastore/datastore'; + +export { + Predicates, + ModelPredicateCreator, + ModelSortPredicateCreator, +} from './predicates'; +export { Adapter as StorageAdapter } from './storage/adapter'; + +import { + traverseModel, + validatePredicate, + USER, + isNonModelConstructor, + isModelConstructor, +} from './util'; + +export const utils = { + USER, + traverseModel, + validatePredicate, + isNonModelConstructor, + isModelConstructor, +}; + export * from './types'; diff --git a/packages/datastore/src/storage/adapter/getDefaultAdapter/index.ts b/packages/datastore/src/storage/adapter/getDefaultAdapter/index.ts index c80c1619a0a..47006acfaac 100644 --- a/packages/datastore/src/storage/adapter/getDefaultAdapter/index.ts +++ b/packages/datastore/src/storage/adapter/getDefaultAdapter/index.ts @@ -1,16 +1,16 @@ import { browserOrNode, isWebWorker } from '@aws-amplify/core'; import { Adapter } from '..'; +import IndexedDBAdapter from '../IndexedDBAdapter'; +import AsyncStorageAdapter from '../AsyncStorageAdapter'; const getDefaultAdapter: () => Adapter = () => { const { isBrowser } = browserOrNode(); if ((isBrowser && window.indexedDB) || (isWebWorker() && self.indexedDB)) { - return require('../IndexedDBAdapter').default; + return IndexedDBAdapter; } - const { AsyncStorageAdapter } = require('../AsyncStorageAdapter'); - - return new AsyncStorageAdapter(); + return AsyncStorageAdapter; }; export default getDefaultAdapter; diff --git a/packages/datastore/src/storage/storage.ts b/packages/datastore/src/storage/storage.ts index c6f9a76228b..7dbb767fe39 100644 --- a/packages/datastore/src/storage/storage.ts +++ b/packages/datastore/src/storage/storage.ts @@ -57,7 +57,7 @@ class StorageClass implements StorageFacade { private readonly adapter?: Adapter, private readonly sessionId?: string ) { - this.adapter = getDefaultAdapter(); + this.adapter = this.adapter || getDefaultAdapter(); this.pushStream = new PushStream(); } diff --git a/packages/datastore/src/sync/index.ts b/packages/datastore/src/sync/index.ts index 29086bbe6c4..a0e7d31a91a 100644 --- a/packages/datastore/src/sync/index.ts +++ b/packages/datastore/src/sync/index.ts @@ -908,6 +908,12 @@ export class SyncEngine { isRequired: true, isArray: false, }, + lastSyncPredicate: { + name: 'lastSyncPredicate', + type: 'String', + isRequired: false, + isArray: false, + }, }, }, }, diff --git a/packages/datastore/src/sync/utils.ts b/packages/datastore/src/sync/utils.ts index 36c45722905..ad06de6cdfb 100644 --- a/packages/datastore/src/sync/utils.ts +++ b/packages/datastore/src/sync/utils.ts @@ -395,9 +395,26 @@ export function createMutationInstanceFromModelOperation< exhaustiveCheck(opType); } + // stringify nested objects of type AWSJSON + // this allows us to return parsed JSON to users (see `castInstanceType()` in datastore.ts), + // but still send the object correctly over the wire + const replacer = (k, v) => { + const isAWSJSON = + k && + v !== null && + typeof v === 'object' && + modelDefinition.fields[k] && + modelDefinition.fields[k].type === 'AWSJSON'; + + if (isAWSJSON) { + return JSON.stringify(v); + } + return v; + }; + const mutationEvent = modelInstanceCreator(MutationEventConstructor, { ...(id ? { id } : {}), - data: JSON.stringify(element), + data: JSON.stringify(element, replacer), modelId: element.id, model: model.name, operation, diff --git a/packages/datastore/src/types.ts b/packages/datastore/src/types.ts index 9feb1a265be..21ec62e2656 100644 --- a/packages/datastore/src/types.ts +++ b/packages/datastore/src/types.ts @@ -13,6 +13,7 @@ import { } from './util'; import { PredicateAll } from './predicates'; import { GRAPHQL_AUTH_MODE } from '@aws-amplify/api-graphql'; +import { Adapter } from './storage/adapter'; //#region Schema types export type Schema = UserSchema & { @@ -79,6 +80,35 @@ export function isTargetNameAssociation( export type ModelAttributes = ModelAttribute[]; type ModelAttribute = { type: string; properties?: Record }; +export type ModelAuthRule = { + allow: string; + provider?: string; + operations?: string[]; + ownerField?: string; + identityClaim?: string; + groups?: string[]; + groupClaim?: string; + groupsField?: string; +}; + +export type ModelAttributeAuth = { + type: 'auth'; + properties: { + rules: ModelAuthRule[]; + }; +}; + +export function isModelAttributeAuth( + attr: ModelAttribute +): attr is ModelAttributeAuth { + return ( + attr.type === 'auth' && + attr.properties && + attr.properties.rules && + attr.properties.rules.length > 0 + ); +} + type ModelAttributeKey = { type: 'key'; properties: { @@ -179,7 +209,7 @@ export namespace GraphQLScalarType { typeof GraphQLScalarType, 'getJSType' | 'getValidationFunction' > - ): 'string' | 'number' | 'boolean' { + ): 'string' | 'number' | 'boolean' | 'object' { switch (scalar) { case 'Boolean': return 'boolean'; @@ -189,7 +219,6 @@ export namespace GraphQLScalarType { case 'AWSTime': case 'AWSDateTime': case 'AWSEmail': - case 'AWSJSON': case 'AWSURL': case 'AWSPhone': case 'AWSIPAddress': @@ -198,8 +227,10 @@ export namespace GraphQLScalarType { case 'Float': case 'AWSTimestamp': return 'number'; + case 'AWSJSON': + return 'object'; default: - exhaustiveCheck(scalar); + exhaustiveCheck(scalar as never); } } @@ -277,7 +308,7 @@ export function isEnumFieldType(obj: any): obj is EnumFieldType { return false; } -type ModelField = { +export type ModelField = { name: string; type: | keyof Omit< @@ -619,6 +650,7 @@ export type DataStoreConfig = { fullSyncInterval?: number; syncExpressions?: SyncExpression[]; authProviders?: AuthProviders; + storageAdapter?: Adapter; }; authModeStrategyType?: AuthModeStrategyType; conflictHandler?: ConflictHandler; // default : retry until client wins up to x times @@ -628,10 +660,11 @@ export type DataStoreConfig = { fullSyncInterval?: number; syncExpressions?: SyncExpression[]; authProviders?: AuthProviders; + storageAdapter?: Adapter; }; export type AuthProviders = { - functionAuthProvider: Promise; + functionAuthProvider: () => { token: string } | Promise<{ token: string }>; }; export enum AuthModeStrategyType { diff --git a/packages/datastore/src/util.ts b/packages/datastore/src/util.ts index 161faceb70a..7bf3b9e2c80 100644 --- a/packages/datastore/src/util.ts +++ b/packages/datastore/src/util.ts @@ -22,6 +22,7 @@ import { isModelAttributeKey, isModelAttributePrimaryKey, isModelAttributeCompositeKey, + NonModelTypeConstructor, } from './types'; import { WordArray } from 'amazon-cognito-identity-js'; @@ -131,6 +132,18 @@ export const isModelConstructor = ( ); }; +const nonModelClasses = new WeakSet>(); + +export function registerNonModelClass(clazz: NonModelTypeConstructor) { + nonModelClasses.add(clazz); +} + +export const isNonModelConstructor = ( + obj: any +): obj is NonModelTypeConstructor => { + return nonModelClasses.has(obj); +}; + /* When we have GSI(s) with composite sort keys defined on a model There are some very particular rules regarding which fields must be included in the update mutation input diff --git a/packages/geo/package.json b/packages/geo/package.json index 7cd49cf7cc7..3d0d02956f3 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -41,7 +41,7 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/core": "4.2.1", + "@aws-amplify/core": "4.2.9", "@aws-sdk/client-location": "3.22.0", "camelcase-keys": "6.2.2" }, diff --git a/packages/interactions/CHANGELOG.md b/packages/interactions/CHANGELOG.md index deda615887c..9d62aa8c045 100644 --- a/packages/interactions/CHANGELOG.md +++ b/packages/interactions/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.14...@aws-amplify/interactions@4.0.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + +## [4.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.13...@aws-amplify/interactions@4.0.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + +## [4.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.12...@aws-amplify/interactions@4.0.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + +## [4.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.11...@aws-amplify/interactions@4.0.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + +## [4.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.10...@aws-amplify/interactions@4.0.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + +## [4.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.9...@aws-amplify/interactions@4.0.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + +## [4.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.8...@aws-amplify/interactions@4.0.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + +## [4.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.7...@aws-amplify/interactions@4.0.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/interactions + + + + + ## [4.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@4.0.6...@aws-amplify/interactions@4.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/interactions diff --git a/packages/interactions/package.json b/packages/interactions/package.json index 16bd624d264..5143369565a 100644 --- a/packages/interactions/package.json +++ b/packages/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/interactions", - "version": "4.0.7", + "version": "4.0.15", "description": "Interactions category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -41,7 +41,7 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/core": "4.2.1", + "@aws-amplify/core": "4.2.9", "@aws-sdk/client-lex-runtime-service": "3.6.1" }, "jest": { diff --git a/packages/predictions/CHANGELOG.md b/packages/predictions/CHANGELOG.md index cef17c07b63..d1d26ea4e7f 100644 --- a/packages/predictions/CHANGELOG.md +++ b/packages/predictions/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.14...@aws-amplify/predictions@4.0.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + +## [4.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.13...@aws-amplify/predictions@4.0.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + +## [4.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.12...@aws-amplify/predictions@4.0.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + +## [4.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.11...@aws-amplify/predictions@4.0.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + +## [4.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.10...@aws-amplify/predictions@4.0.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + +## [4.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.9...@aws-amplify/predictions@4.0.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + +## [4.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.8...@aws-amplify/predictions@4.0.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + +## [4.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.7...@aws-amplify/predictions@4.0.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/predictions + + + + + ## [4.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@4.0.6...@aws-amplify/predictions@4.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/predictions diff --git a/packages/predictions/package.json b/packages/predictions/package.json index db090f271f2..637d0d686ed 100644 --- a/packages/predictions/package.json +++ b/packages/predictions/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/predictions", - "version": "4.0.7", + "version": "4.0.15", "description": "Machine learning category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -40,8 +40,8 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/core": "4.2.1", - "@aws-amplify/storage": "4.3.2", + "@aws-amplify/core": "4.2.9", + "@aws-amplify/storage": "4.3.10", "@aws-sdk/client-comprehend": "3.6.1", "@aws-sdk/client-polly": "3.6.1", "@aws-sdk/client-rekognition": "3.6.1", diff --git a/packages/pubsub/CHANGELOG.md b/packages/pubsub/CHANGELOG.md index 432984a666a..9380b20367e 100644 --- a/packages/pubsub/CHANGELOG.md +++ b/packages/pubsub/CHANGELOG.md @@ -3,6 +3,74 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.1.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.1.6...@aws-amplify/pubsub@4.1.7) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/pubsub + + + + + +## [4.1.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.1.5...@aws-amplify/pubsub@4.1.6) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/pubsub + + + + + +## [4.1.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.1.4...@aws-amplify/pubsub@4.1.5) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/pubsub + + + + + +## [4.1.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.1.3...@aws-amplify/pubsub@4.1.4) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/pubsub + + + + + +## [4.1.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.1.2...@aws-amplify/pubsub@4.1.3) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/pubsub + + + + + +## [4.1.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.1.1...@aws-amplify/pubsub@4.1.2) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/pubsub + + + + + +## [4.1.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.1.0...@aws-amplify/pubsub@4.1.1) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/pubsub + + + + + +# [4.1.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.0.7...@aws-amplify/pubsub@4.1.0) (2021-07-28) + + +### Features + +* **@aws-amplify/datastore:** support lambda authorizers ([52d43cc](https://github.com/aws-amplify/amplify-js/commit/52d43cc73b459148f1ae81ab81d3a5365a4457e3)) +* **@aws-amplify/pubsub:** support lambda authorizers ([85879ac](https://github.com/aws-amplify/amplify-js/commit/85879ac94952cbfe033a63370c48e89f00b7265d)) + + + + + ## [4.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@4.0.6...@aws-amplify/pubsub@4.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/pubsub diff --git a/packages/pubsub/__tests__/PubSub-unit-test.ts b/packages/pubsub/__tests__/PubSub-unit-test.ts index 60285569306..969e42d520b 100644 --- a/packages/pubsub/__tests__/PubSub-unit-test.ts +++ b/packages/pubsub/__tests__/PubSub-unit-test.ts @@ -196,6 +196,41 @@ describe('PubSub', () => { expect(mqttTopicMatch('topic/A/+/#', publishTopic)).toBe(true); expect(mqttTopicMatch('topic/A/B/C/#', publishTopic)).toBe(false); }); + + test('should remove AWSIoTProvider', () => { + const pubsub = new PubSub({}); + const originalProvider = new AWSIoTProvider({ + aws_pubsub_region: 'region', + aws_pubsub_endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', + }); + jest.spyOn(originalProvider, 'publish'); + const newProvider = new AWSIoTProvider({ + aws_pubsub_region: 'new-region', + aws_pubsub_endpoint: 'wss://iot.newEndPoint.org:443/newEndPoint', + }); + jest.spyOn(newProvider, 'publish'); + + pubsub.addPluggable(originalProvider); + pubsub.removePluggable('AWSIoTProvider'); + pubsub.addPluggable(newProvider); + pubsub.publish('someTopic', { msg: 'published Message' }); + + expect(originalProvider.publish).not.toHaveBeenCalled(); + expect(newProvider.publish).toHaveBeenCalled(); + }); + + test('should exit gracefully when trying to remove provider when no providers have been added', () => { + const config = { + PubSub: { + aws_pubsub_region: 'region', + aws_pubsub_endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', + }, + }; + const pubsub = new PubSub({}); + pubsub.configure(config); + + expect(() => pubsub.removePluggable('AWSIoTProvider')).not.toThrow(); + }); }); describe('MqttOverWSProvider', () => { @@ -238,6 +273,28 @@ describe('PubSub', () => { awsIotProvider.onDisconnect({ errorCode: 1, clientId: '123' }); }); + + test('should remove MqttOverWSProvider', () => { + const pubsub = new PubSub({}); + const originalProvider = new MqttOverWSProvider({ + aws_pubsub_region: 'region', + aws_appsync_dangerously_connect_to_http_endpoint_for_testing: true, + }); + jest.spyOn(originalProvider, 'publish'); + const newProvider = new MqttOverWSProvider({ + aws_pubsub_region: 'region', + aws_appsync_dangerously_connect_to_http_endpoint_for_testing: true, + }); + jest.spyOn(newProvider, 'publish'); + + pubsub.addPluggable(originalProvider); + pubsub.removePluggable('MqttOverWSProvider'); + pubsub.addPluggable(newProvider); + pubsub.publish('someTopic', { msg: 'published Message' }); + + expect(originalProvider.publish).not.toHaveBeenCalled(); + expect(newProvider.publish).toHaveBeenCalled(); + }); }); describe('MqttOverWSProvider local testing config', () => { diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index 6ccd3bfcab2..85ca94eb426 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/pubsub", - "version": "4.0.7", + "version": "4.1.7", "description": "Pubsub category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -45,9 +45,9 @@ "cpx": "^1.5.0" }, "dependencies": { - "@aws-amplify/auth": "4.1.3", - "@aws-amplify/cache": "4.0.9", - "@aws-amplify/core": "4.2.1", + "@aws-amplify/auth": "4.3.5", + "@aws-amplify/cache": "4.0.17", + "@aws-amplify/core": "4.2.9", "graphql": "14.0.0", "paho-mqtt": "^1.1.0", "uuid": "^3.2.1", diff --git a/packages/pubsub/src/PubSub.ts b/packages/pubsub/src/PubSub.ts index bee1ab0376f..d4d6b632e1f 100644 --- a/packages/pubsub/src/PubSub.ts +++ b/packages/pubsub/src/PubSub.ts @@ -110,6 +110,16 @@ export class PubSubClass { } } + /** + * remove plugin from PubSub category + * @param providerName - the name of the plugin + */ + removePluggable(providerName: string): void { + this._pluggables = this._pluggables.filter( + pluggable => pluggable.getProviderName() !== providerName + ); + } + private getProviderByName(providerName) { if (providerName === INTERNAL_AWS_APPSYNC_PUBSUB_PROVIDER) { return this.awsAppSyncProvider; diff --git a/packages/pushnotification/CHANGELOG.md b/packages/pushnotification/CHANGELOG.md index a2fd5f20bbf..20d8dc52261 100644 --- a/packages/pushnotification/CHANGELOG.md +++ b/packages/pushnotification/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.2.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.8...@aws-amplify/pushnotification@4.2.9) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + +## [4.2.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.7...@aws-amplify/pushnotification@4.2.8) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + +## [4.2.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.6...@aws-amplify/pushnotification@4.2.7) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + +## [4.2.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.5...@aws-amplify/pushnotification@4.2.6) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + +## [4.2.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.4...@aws-amplify/pushnotification@4.2.5) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + +## [4.2.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.3...@aws-amplify/pushnotification@4.2.4) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + +## [4.2.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.2...@aws-amplify/pushnotification@4.2.3) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + +## [4.2.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.1...@aws-amplify/pushnotification@4.2.2) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/pushnotification + + + + + ## [4.2.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pushnotification@4.2.0...@aws-amplify/pushnotification@4.2.1) (2021-07-22) **Note:** Version bump only for package @aws-amplify/pushnotification diff --git a/packages/pushnotification/package.json b/packages/pushnotification/package.json index 91b81cf5dd2..144e98981c4 100644 --- a/packages/pushnotification/package.json +++ b/packages/pushnotification/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/pushnotification", - "version": "4.2.1", + "version": "4.2.9", "description": "Push notifications category of aws-amplify", "main": "./lib/index.js", "module": "./lib/index.js", @@ -44,7 +44,7 @@ "webpack": "^3.5.5" }, "dependencies": { - "@aws-amplify/core": "4.2.1", + "@aws-amplify/core": "4.2.9", "@react-native-community/push-notification-ios": "1.0.3" }, "peerdependencies": { diff --git a/packages/storage/CHANGELOG.md b/packages/storage/CHANGELOG.md index ecb47abed2e..c6827b8d12e 100644 --- a/packages/storage/CHANGELOG.md +++ b/packages/storage/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.3.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.9...@aws-amplify/storage@4.3.10) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + +## [4.3.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.8...@aws-amplify/storage@4.3.9) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + +## [4.3.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.7...@aws-amplify/storage@4.3.8) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + +## [4.3.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.6...@aws-amplify/storage@4.3.7) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + +## [4.3.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.5...@aws-amplify/storage@4.3.6) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + +## [4.3.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.4...@aws-amplify/storage@4.3.5) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + +## [4.3.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.3...@aws-amplify/storage@4.3.4) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + +## [4.3.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.2...@aws-amplify/storage@4.3.3) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/storage + + + + + ## [4.3.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@4.3.1...@aws-amplify/storage@4.3.2) (2021-07-22) **Note:** Version bump only for package @aws-amplify/storage diff --git a/packages/storage/__tests__/providers/AWSS3ProviderManagedUpload-unit-test.ts b/packages/storage/__tests__/providers/AWSS3ProviderManagedUpload-unit-test.ts index 26a0ae9f9f7..c74f909db5d 100644 --- a/packages/storage/__tests__/providers/AWSS3ProviderManagedUpload-unit-test.ts +++ b/packages/storage/__tests__/providers/AWSS3ProviderManagedUpload-unit-test.ts @@ -33,6 +33,8 @@ const testParams: any = { Key: 'testKey', Body: 'testDataBody', ContentType: 'testContentType', + SSECustomerAlgorithm: 'AES256', + SSECustomerKey: '1234567890', }; const credentials = { @@ -151,6 +153,8 @@ describe('multi part upload tests', () => { Key: testParams.Key, PartNumber: 1, UploadId: testUploadId, + SSECustomerAlgorithm: testParams.SSECustomerAlgorithm, + SSECustomerKey: testParams.SSECustomerKey, }); expect(s3ServiceCallSpy.mock.calls[2][0].input).toStrictEqual({ Body: testParams.Body.slice(testMinPartSize, testParams.Body.length), @@ -158,6 +162,8 @@ describe('multi part upload tests', () => { Key: testParams.Key, PartNumber: 2, UploadId: testUploadId, + SSECustomerAlgorithm: testParams.SSECustomerAlgorithm, + SSECustomerKey: testParams.SSECustomerKey, }); // Lastly complete multi part upload call @@ -252,6 +258,8 @@ describe('multi part upload tests', () => { Key: testParams.Key, PartNumber: 1, UploadId: testUploadId, + SSECustomerAlgorithm: testParams.SSECustomerAlgorithm, + SSECustomerKey: testParams.SSECustomerKey, }); // Second call fails @@ -261,6 +269,8 @@ describe('multi part upload tests', () => { Key: testParams.Key, PartNumber: 2, UploadId: testUploadId, + SSECustomerAlgorithm: testParams.SSECustomerAlgorithm, + SSECustomerKey: testParams.SSECustomerKey, }); // so we abort the multipart upload diff --git a/packages/storage/package.json b/packages/storage/package.json index c998f456efa..d2919c76150 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/storage", - "version": "4.3.2", + "version": "4.3.10", "description": "Storage category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -41,12 +41,12 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/core": "4.2.1", + "@aws-amplify/core": "4.2.9", "@aws-sdk/client-s3": "3.6.1", "@aws-sdk/s3-request-presigner": "3.6.1", "@aws-sdk/util-create-request": "3.6.1", "@aws-sdk/util-format-url": "3.6.1", - "axios": "0.21.1", + "axios": "0.21.4", "events": "^3.1.0", "sinon": "^7.5.0" }, diff --git a/packages/storage/src/providers/AWSS3Provider.ts b/packages/storage/src/providers/AWSS3Provider.ts index 13481ed5ce4..901230c9888 100644 --- a/packages/storage/src/providers/AWSS3Provider.ts +++ b/packages/storage/src/providers/AWSS3Provider.ts @@ -278,6 +278,9 @@ export class AWSS3Provider implements StorageProvider { contentType, expires, track, + SSECustomerAlgorithm, + SSECustomerKey, + SSECustomerKeyMD5, progressCallback, } = opt; const prefix = this._prefix(opt); @@ -297,6 +300,15 @@ export class AWSS3Provider implements StorageProvider { if (contentEncoding) params.ResponseContentEncoding = contentEncoding; if (contentLanguage) params.ResponseContentLanguage = contentLanguage; if (contentType) params.ResponseContentType = contentType; + if (SSECustomerAlgorithm) { + params.SSECustomerAlgorithm = SSECustomerAlgorithm; + } + if (SSECustomerKey) { + params.SSECustomerKey = SSECustomerKey; + } + if (SSECustomerKeyMD5) { + params.SSECustomerKeyMD5 = SSECustomerKeyMD5; + } if (download === true) { const getObjectCommand = new GetObjectCommand(params); diff --git a/packages/storage/src/providers/AWSS3ProviderManagedUpload.ts b/packages/storage/src/providers/AWSS3ProviderManagedUpload.ts index fa229144f9b..c1ec3f466a7 100644 --- a/packages/storage/src/providers/AWSS3ProviderManagedUpload.ts +++ b/packages/storage/src/providers/AWSS3ProviderManagedUpload.ts @@ -176,13 +176,18 @@ export class AWSS3ProviderManagedUpload { parts.map(async part => { this.setupEventListener(part); const s3 = await this._createNewS3Client(this.opts, part.emitter); + const { Key, Bucket, SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5 } = this.params; return s3.send( new UploadPartCommand({ PartNumber: part.partNumber, Body: part.bodyPart, UploadId: uploadId, - Key: this.params.Key, - Bucket: this.params.Bucket, + Key, + Bucket, + ...(SSECustomerAlgorithm && { SSECustomerAlgorithm }), + ...(SSECustomerKey && { SSECustomerKey }), + ...(SSECustomerKeyMD5 && { SSECustomerKeyMD5 }) + }) ); }) @@ -348,6 +353,7 @@ export class AWSS3ProviderManagedUpload { region, dangerouslyConnectToHttpEndpointForTesting, cancelTokenSource, + useAccelerateEndpoint } = config; let localTestingConfig = {}; @@ -363,6 +369,7 @@ export class AWSS3ProviderManagedUpload { const client = new S3Client({ region, credentials, + useAccelerateEndpoint, ...localTestingConfig, requestHandler: new AxiosHttpHandler({}, emitter, cancelTokenSource), customUserAgent: getAmplifyUserAgent(), diff --git a/packages/storage/src/types/AWSS3Provider.ts b/packages/storage/src/types/AWSS3Provider.ts index b5480684989..b3079517839 100644 --- a/packages/storage/src/types/AWSS3Provider.ts +++ b/packages/storage/src/types/AWSS3Provider.ts @@ -49,6 +49,7 @@ export interface S3ProviderPutConfig extends StorageOptions { expires?: PutObjectRequest['Expires']; metadata?: PutObjectRequest['Metadata']; tagging?: PutObjectRequest['Tagging']; + useAccelerateEndpoint?: boolean; } export interface S3ProviderPutOutput { diff --git a/packages/xr/CHANGELOG.md b/packages/xr/CHANGELOG.md index 0d03fd5b5cc..d0c7dbe36d4 100644 --- a/packages/xr/CHANGELOG.md +++ b/packages/xr/CHANGELOG.md @@ -3,6 +3,70 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.0.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.14...@aws-amplify/xr@3.0.15) (2021-09-09) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + +## [3.0.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.13...@aws-amplify/xr@3.0.14) (2021-09-07) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + +## [3.0.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.12...@aws-amplify/xr@3.0.13) (2021-09-04) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + +## [3.0.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.11...@aws-amplify/xr@3.0.12) (2021-09-02) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + +## [3.0.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.10...@aws-amplify/xr@3.0.11) (2021-08-26) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + +## [3.0.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.9...@aws-amplify/xr@3.0.10) (2021-08-19) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + +## [3.0.9](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.8...@aws-amplify/xr@3.0.9) (2021-08-12) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + +## [3.0.8](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.7...@aws-amplify/xr@3.0.8) (2021-07-28) + +**Note:** Version bump only for package @aws-amplify/xr + + + + + ## [3.0.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/xr@3.0.6...@aws-amplify/xr@3.0.7) (2021-07-22) **Note:** Version bump only for package @aws-amplify/xr diff --git a/packages/xr/package.json b/packages/xr/package.json index ac448a2fb2b..0d09032e80e 100644 --- a/packages/xr/package.json +++ b/packages/xr/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/xr", - "version": "3.0.7", + "version": "3.0.15", "description": "XR category of aws-amplify", "main": "./lib/index.js", "module": "./lib-esm/index.js", @@ -41,7 +41,7 @@ }, "homepage": "https://aws-amplify.github.io/", "dependencies": { - "@aws-amplify/core": "4.2.1" + "@aws-amplify/core": "4.2.9" }, "jest": { "globals": { diff --git a/scripts/build.js b/scripts/build.js index 04913358d80..511c49e1d20 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -162,7 +162,7 @@ async function buildES5(typeScriptCompiler, watchMode) { 'es2017', 'esnext.asynciterable', 'es2018.asyncgenerator', - 'es2019.object', + 'es2019', ], downlevelIteration: true, jsx: jsx, @@ -219,7 +219,7 @@ function buildES6(typeScriptCompiler, watchMode) { 'es2017', 'esnext.asynciterable', 'es2018.asyncgenerator', - 'es2019.object', + 'es2019', ], downlevelIteration: true, jsx: jsx,