diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 78ed19747ec..3af1b2c1bd9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,6 +8,8 @@ /packages/geo @aws-amplify/amplify-js @aws-amplify/amplify-ui /packages/pubsub @aws-amplify/amplify-js @aws-amplify/amplify-data /packages/aws-amplify/package.json @aws-amplify/amplify-js-admins +packages/storage/src/storageBrowser @aws-amplify/amplify-js @aws-amplify/amplify-ui +packages/storage/storage-browser @aws-amplify/amplify-js @aws-amplify/amplify-ui /.circleci/ @aws-amplify/amplify-js @aws-amplify/amplify-devops /.github/ @aws-amplify/amplify-js-admins diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yaml b/.github/ISSUE_TEMPLATE/1.bug_report.yaml index ed10dbad86d..9d73aee3760 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yaml @@ -1,6 +1,5 @@ name: Bug report description: Create a report to help us improve Amplify JS -labels: pending-triage body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/2.feature_request.yaml b/.github/ISSUE_TEMPLATE/2.feature_request.yaml index 13eb5e1522d..c50290cbd22 100644 --- a/.github/ISSUE_TEMPLATE/2.feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/2.feature_request.yaml @@ -1,6 +1,5 @@ name: Feature request description: Suggest an idea for Amplify JS -labels: pending-triage body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/3.usage-question.md b/.github/ISSUE_TEMPLATE/3.usage-question.md deleted file mode 100644 index 82d079fe7be..00000000000 --- a/.github/ISSUE_TEMPLATE/3.usage-question.md +++ /dev/null @@ -1,23 +0,0 @@ - - ---- - -name: Usage Question -about: Ask a question about AWS Amplify usage -title: '' -labels: question,pending-triage -assignees: '' - ---- - -** Which Category is your question related to? ** -E.g. Auth, Predictions, Storage, etc. -** What AWS Services are you utilizing? ** -E.g. Cognito, AWS AppSync, etc. -** Provide additional details e.g. code snippets ** -E.g. Sample code, versions of Amplify you are using diff --git a/.github/ISSUE_TEMPLATE/4.rfc.md b/.github/ISSUE_TEMPLATE/4.rfc.md deleted file mode 100644 index 464d9aee63f..00000000000 --- a/.github/ISSUE_TEMPLATE/4.rfc.md +++ /dev/null @@ -1,46 +0,0 @@ ---- - -name: Request For Comments (RFC) -about: Gather community feedback regarding a proposed change to the library -title: 'RFC: PROPOSAL HEADLINE' -labels: feature-request -assignees: '' ----_This issue is a Request For Comments (RFC). It is intended to elicit community feedback regarding a proposed change to the library. Please feel free to post comments or questions here._ - -## Summary - -In one or two sentences, why should this change exist? - -## Motivation - -Why is this RFC needed? What will happen if accepted? And what would happen if it _isn't_ accepted? - -## Basic Example - -If the RFC involves a new or changed API, include a basic code example. (Omit if not applicable) - -## Detailed Design - -Provide enough detail on _how_ this should be implemented such that someone other than yourself could build it. -Include examples of how the implementation is used - -## Drawbacks - -- Is this a breaking change? Days/Weeks/Months to implement? Will it require extensive documentation & examples? - -## Adoption Strategy - -- What supporting efforts will be needed (e.g. documentation, tests, tutorials, public outreach, etc.)? - -## Related Issues - -Add GitHub issue numbers/URLs that informed or would be impacted by this proposal. - -- #1234 -- https://github.com/aws-amplify/amplify-js/issues/1234 - -## References - -List articles, resources, prior art, and inspiration for this proposal. - -- http://stackoverflow.com/ diff --git a/.github/dependency-review/dependecy-review-config.yml b/.github/dependency-review/dependecy-review-config.yml index 173aefd36ef..6f66da66007 100644 --- a/.github/dependency-review/dependecy-review-config.yml +++ b/.github/dependency-review/dependecy-review-config.yml @@ -1,14 +1,16 @@ allow-licenses: - - 'Apache-2.0' - '0BSD' - - 'BSL-1.0' + - 'Apache-2.0' + - 'BlueOak-1.0.0' - 'BSD-1-Clause' - 'BSD-2-Clause-FreeBSD' - 'BSD-2-Clause' - 'BSD-3-Clause-Attribution' - 'BSD-3-Clause' + - 'BSL-1.0' - 'CC-BY-3.0' - 'CC-BY-4.0' + - 'CC0-1.0' - 'curl' - 'ISC' - 'JSON' @@ -20,4 +22,3 @@ allow-licenses: - 'Unlicense' - 'WTFPL' - 'Zlib' - - 'CC0-1.0' \ No newline at end of file diff --git a/.github/integ-config/detox-integ-all.yml b/.github/integ-config/detox-integ-all.yml index b58aefdda5c..3debdf83482 100644 --- a/.github/integ-config/detox-integ-all.yml +++ b/.github/integ-config/detox-integ-all.yml @@ -16,3 +16,7 @@ - test_name: 'integ_rn_ios_api_v6_rn_72_detox_cli' working_directory: amplify-js-samples-staging/samples/react-native/api/v6/ApiGRAPHQL timeout_minutes: 120 +- test_name: 'integ_rn_ios_oidc_signout' + working_directory: amplify-js-samples-staging/samples/react-native/auth/HosteduiApp + timeout_minutes: 120 + host_signout_page: true diff --git a/.github/integ-config/integ-all.yml b/.github/integ-config/integ-all.yml index f99b0dac6aa..211ebc76db1 100644 --- a/.github/integ-config/integ-all.yml +++ b/.github/integ-config/integ-all.yml @@ -514,6 +514,13 @@ tests: sample_name: [sign-in-with-oauth] spec: sign-in-with-oauth browser: [chrome] + - test_name: integ_vue_sign_out_of_oidc_provider + desc: 'Sign-out of OIDC provider' + framework: vue + category: auth + sample_name: [sign-in-with-oauth] + spec: sign-out-oidc-provider + browser: [chrome] # AUTH GEN2 - test_name: integ_react_javascript_authentication_gen2 @@ -595,6 +602,13 @@ tests: sample_name: [sign-in-with-oauth] spec: sign-in-with-oauth browser: [chrome] + - test_name: subdomain_authentication + desc: 'Sign-in with the OAuth flow and subdomains' + framework: next + category: auth + sample_name: [subdomains] + spec: subdomains + browser: [chrome] # DISABLED Angular/Vue tests: # TODO: delete tests or add custom ui logic to support them. diff --git a/.github/workflows/callable-e2e-test-detox.yml b/.github/workflows/callable-e2e-test-detox.yml index e9efa09f336..ffea13efb6a 100644 --- a/.github/workflows/callable-e2e-test-detox.yml +++ b/.github/workflows/callable-e2e-test-detox.yml @@ -13,11 +13,15 @@ on: timeout_minutes: required: true type: number + host_signout_page: + required: false + type: boolean + default: false jobs: e2e-test: name: E2E-Detox ${{ inputs.test_name }} - runs-on: macos-latest + runs-on: macos-latest-large timeout-minutes: ${{ inputs.timeout_minutes }} steps: @@ -70,6 +74,11 @@ jobs: JEST_JUNIT_OUTPUT_NAME: detox-test-results.xml working-directory: ${{ inputs.working_directory }} shell: bash + - name: Start the http-server and host the oidc signout page locally (background). + if: ${{ inputs.host_signout_page }} + run: yarn host:signout + working-directory: ${{ inputs.working_directory }} + shell: bash - name: Detox run run: | $GITHUB_WORKSPACE/amplify-js/scripts/retry-yarn-script.sh -s 'detox test -c ios.sim.debug -u' -n 3 diff --git a/.github/workflows/callable-e2e-tests.yml b/.github/workflows/callable-e2e-tests.yml index c27c51ce57f..4ae74a69c88 100644 --- a/.github/workflows/callable-e2e-tests.yml +++ b/.github/workflows/callable-e2e-tests.yml @@ -74,3 +74,4 @@ jobs: test_name: ${{ matrix.integ-config.test_name }} working_directory: ${{ matrix.integ-config.working_directory }} timeout_minutes: ${{ matrix.integ-config.timeout_minutes || 45 }} + host_signout_page: ${{ matrix.integ-config.host_signout_page || false }} diff --git a/.github/workflows/issue-closed.yml b/.github/workflows/issue-closed.yml new file mode 100644 index 00000000000..fed460e0181 --- /dev/null +++ b/.github/workflows/issue-closed.yml @@ -0,0 +1,22 @@ +name: Issue Closed + +on: + issues: + types: [closed] + +permissions: + issues: write + +jobs: + cleanup-labels: + runs-on: ubuntu-latest + if: ${{ (contains(github.event.issue.labels.*.name, 'pending-community-response') || contains(github.event.issue.labels.*.name, 'pending-maintainer-response') || contains(github.event.issue.labels.*.name, 'pending-triage')) }} + steps: + - name: Remove unnecessary labels after closing + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + REPOSITORY_NAME: ${{ github.event.repository.full_name }} + run: | + gh issue edit $ISSUE_NUMBER --repo $REPOSITORY_NAME --remove-label "pending-community-response" --remove-label "pending-maintainer-response" --remove-label "pending-triage" diff --git a/.github/workflows/issue-comment.yml b/.github/workflows/issue-comment.yml new file mode 100644 index 00000000000..cfde2f7d331 --- /dev/null +++ b/.github/workflows/issue-comment.yml @@ -0,0 +1,31 @@ +name: Issue Comment + +on: + issue_comment: + types: [created] + +jobs: + adjust-labels: + runs-on: ubuntu-latest + permissions: + issues: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + REPOSITORY_NAME: ${{ github.event.repository.full_name }} + steps: + - name: Remove pending-community-response when new comment received + if: ${{ !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) && !github.event.issue.pull_request }} + shell: bash + run: | + gh issue edit $ISSUE_NUMBER --repo $REPOSITORY_NAME --remove-label "pending-community-response" + - name: Add pending-maintainer-response when new community comment received + if: ${{ !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) }} + shell: bash + run: | + gh issue edit $ISSUE_NUMBER --repo $REPOSITORY_NAME --add-label "pending-maintainer-response" + - name: Remove pending-maintainer-response when new owner/member comment received + if: ${{ contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) }} + shell: bash + run: | + gh issue edit $ISSUE_NUMBER --repo $REPOSITORY_NAME --remove-label "pending-maintainer-response" diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml new file mode 100644 index 00000000000..022fc996a3a --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,21 @@ +name: Issue Labeled + +on: + issues: + types: [labeled] + +jobs: + remove-pending-triage-label: + runs-on: ubuntu-latest + if: ${{ contains(fromJSON('["question", "bug", "feature-request"]'), github.event.label.name) }} + permissions: + issues: write + steps: + - name: Remove the pending-triage label + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + REPOSITORY_NAME: ${{ github.event.repository.full_name }} + run: | + gh issue edit $ISSUE_NUMBER --repo $REPOSITORY_NAME --remove-label "pending-triage" diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml new file mode 100644 index 00000000000..6ac0a9ce124 --- /dev/null +++ b/.github/workflows/issue-opened.yml @@ -0,0 +1,25 @@ +name: Issue Opened + +on: + issues: + types: [opened] + +jobs: + add-issue-opened-labels: + runs-on: ubuntu-latest + permissions: + issues: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + REPOSITORY_NAME: ${{ github.event.repository.full_name }} + steps: + - name: Add the pending-triage label + shell: bash + run: | + gh issue edit $ISSUE_NUMBER --repo $REPOSITORY_NAME --add-label "pending-triage" + - name: Add the pending-maintainer-response label + if: ${{ !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.issue.author_association) }} + shell: bash + run: | + gh issue edit $ISSUE_NUMBER --repo $REPOSITORY_NAME --add-label "pending-maintainer-response" diff --git a/.github/workflows/issue-pending-response.yml b/.github/workflows/issue-pending-response.yml deleted file mode 100644 index 8dd8ac9584d..00000000000 --- a/.github/workflows/issue-pending-response.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: issue-pending-response -on: - issue_comment: - types: [created] -permissions: - issues: write -jobs: - issue_commented: - if: ${{ !github.event.issue.pull_request && contains(github.event.issue.labels.*.name, 'pending-response') }} - runs-on: ubuntu-latest - steps: - - uses: siegerts/pending-author-response@409a63bf27370ba9a0e98e8d5fbda7a12398d456 # v1 https://github.com/siegerts/pending-author-response/commit/409a63bf27370ba9a0e98e8d5fbda7a12398d456 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - pending-response-label: pending-response diff --git a/docs/api/assets/navigation.js b/docs/api/assets/navigation.js index 01e7c4a9ec9..2f434fcdca7 100644 --- a/docs/api/assets/navigation.js +++ b/docs/api/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "data:application/octet-stream;base64,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" \ No newline at end of file +window.navigationData = "data:application/octet-stream;base64,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" \ No newline at end of file diff --git a/docs/api/assets/search.js b/docs/api/assets/search.js index ed8859ddb5b..64d3774df34 100644 --- a/docs/api/assets/search.js +++ b/docs/api/assets/search.js @@ -1 +1 @@ -window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/docs/api/classes/_aws_amplify_adapter_nextjs.index._Reference_Types_.Blob.html b/docs/api/classes/_aws_amplify_adapter_nextjs.index._Reference_Types_.Blob.html index 5e8597b6d59..d7a6a1fb1bc 100644 --- a/docs/api/classes/_aws_amplify_adapter_nextjs.index._Reference_Types_.Blob.html +++ b/docs/api/classes/_aws_amplify_adapter_nextjs.index._Reference_Types_.Blob.html @@ -6,6 +6,7 @@

Properties

size type

Methods

arrayBuffer +bytes slice stream text @@ -20,6 +21,10 @@

Methods

\ No newline at end of file +
\ No newline at end of file diff --git a/docs/api/classes/aws_amplify.auth_cognito.DefaultTokenStore.html b/docs/api/classes/aws_amplify.auth_cognito.DefaultTokenStore.html index 7dfa9ea73ad..abc243c87d6 100644 --- a/docs/api/classes/aws_amplify.auth_cognito.DefaultTokenStore.html +++ b/docs/api/classes/aws_amplify.auth_cognito.DefaultTokenStore.html @@ -6,8 +6,10 @@ getDeviceMetadata getKeyValueStorage getLastAuthUser +getOAuthMetadata loadTokens setAuthConfig setKeyValueStorage +setOAuthMetadata storeTokens -

Constructors

Properties

keyValueStorage?: KeyValueStorageInterface

Methods

\ No newline at end of file +

Constructors

Properties

keyValueStorage?: KeyValueStorageInterface

Methods

\ No newline at end of file diff --git a/docs/api/classes/aws_amplify.auth_cognito.TokenOrchestrator.html b/docs/api/classes/aws_amplify.auth_cognito.TokenOrchestrator.html index 4c0b1229849..5e03954ff0e 100644 --- a/docs/api/classes/aws_amplify.auth_cognito.TokenOrchestrator.html +++ b/docs/api/classes/aws_amplify.auth_cognito.TokenOrchestrator.html @@ -7,11 +7,13 @@

Methods

clearDeviceMetadata clearTokens getDeviceMetadata +getOAuthMetadata getTokenRefresher getTokenStore getTokens setAuthConfig setAuthTokenStore +setOAuthMetadata setTokenRefresher setTokens -

Constructors

Properties

inflightPromise: undefined | Promise<void>
tokenRefresher?: TokenRefresher
tokenStore?: AuthTokenStore
waitForInflightOAuth: (() => Promise<void>)

Type declaration

    • (): Promise<void>
    • Returns Promise<void>

Methods

\ No newline at end of file +

Constructors

Properties

inflightPromise: undefined | Promise<void>
tokenRefresher?: TokenRefresher
tokenStore?: AuthTokenStore
waitForInflightOAuth: (() => Promise<void>)

Type declaration

    • (): Promise<void>
    • Returns Promise<void>

Methods

\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.api.generateClient.html b/docs/api/functions/aws_amplify.api.generateClient.html index 9d639439f5c..d90eac9cfd9 100644 --- a/docs/api/functions/aws_amplify.api.generateClient.html +++ b/docs/api/functions/aws_amplify.api.generateClient.html @@ -1,3 +1,5 @@ generateClient | Amplify JS API Documentation
\ No newline at end of file +

Type Parameters

Parameters

Returns V6Client<T>

V6Client

+

Throws

Error - Throws error when client cannot be generated due to configuration issues.

+
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.api.isCancelError.html b/docs/api/functions/aws_amplify.api.isCancelError.html index d008a72b3ec..5ee66a87c2e 100644 --- a/docs/api/functions/aws_amplify.api.isCancelError.html +++ b/docs/api/functions/aws_amplify.api.isCancelError.html @@ -1,5 +1,9 @@ isCancelError | Amplify JS API Documentation
  • Check if an error is caused by user calling cancel() in REST API.

    -

    Parameters

    • error: unknown

    Returns error is CanceledError

    Note

    This function works ONLY for errors thrown by REST API. For GraphQL APIs, use client.isCancelError(error) +

    Parameters

    • error: unknown

      The unknown exception to be checked.

      +

    Returns error is CanceledError

      +
    • A boolean indicating if the error was from an upload cancellation
    • +
    +

    Note

    This function works ONLY for errors thrown by REST API. For GraphQL APIs, use client.isCancelError(error) instead. client is generated from generateClient() API from aws-amplify/api.

\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.auth.decodeJWT.html b/docs/api/functions/aws_amplify.auth.decodeJWT.html index 92400134d0d..8ade6d36949 100644 --- a/docs/api/functions/aws_amplify.auth.decodeJWT.html +++ b/docs/api/functions/aws_amplify.auth.decodeJWT.html @@ -1,2 +1,5 @@ decodeJWT | Amplify JS API Documentation -
  • Parameters

    • token: string

    Returns JWT

\ No newline at end of file +
  • Decodes payload of JWT token

    +

    Parameters

    • token: string

      A string representing a token to be decoded

      +

    Returns JWT

    Throws

    Error - Throws error when token is invalid or payload malformed.

    +
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.auth.fetchAuthSession.html b/docs/api/functions/aws_amplify.auth.fetchAuthSession.html index 5a52daaee82..f62b7471aa8 100644 --- a/docs/api/functions/aws_amplify.auth.fetchAuthSession.html +++ b/docs/api/functions/aws_amplify.auth.fetchAuthSession.html @@ -1,2 +1,8 @@ fetchAuthSession | Amplify JS API Documentation -
\ No newline at end of file +
  • Fetch the auth session including the tokens and credentials if they are available. By default it +does not refresh the auth tokens or credentials if they are loaded in storage already. You can force a refresh +with { forceRefresh: true } input.

    +

    Parameters

    Returns Promise<AuthSession>

    Promise

    +

    Throws

    AuthError - Throws error when session information cannot be refreshed.

    +
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isAssociatedWith.html b/docs/api/functions/aws_amplify.datastore.isAssociatedWith.html deleted file mode 100644 index 78b1cbc2f5a..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isAssociatedWith.html +++ /dev/null @@ -1,2 +0,0 @@ -isAssociatedWith | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isEnumFieldType.html b/docs/api/functions/aws_amplify.datastore.isEnumFieldType.html deleted file mode 100644 index 3ec677ab00e..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isEnumFieldType.html +++ /dev/null @@ -1,2 +0,0 @@ -isEnumFieldType | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isFieldAssociation.html b/docs/api/functions/aws_amplify.datastore.isFieldAssociation.html deleted file mode 100644 index b3000735a65..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isFieldAssociation.html +++ /dev/null @@ -1,2 +0,0 @@ -isFieldAssociation | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isGraphQLScalarType.html b/docs/api/functions/aws_amplify.datastore.isGraphQLScalarType.html deleted file mode 100644 index 76005f74c73..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isGraphQLScalarType.html +++ /dev/null @@ -1,2 +0,0 @@ -isGraphQLScalarType | Amplify JS API Documentation -
  • Parameters

    • obj: any

    Returns obj is "ID" | "String" | "Int" | "Float" | "Boolean" | "AWSDate" | "AWSTime" | "AWSDateTime" | "AWSTimestamp" | "AWSEmail" | "AWSJSON" | "AWSURL" | "AWSPhone" | "AWSIPAddress"

\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isIdentifierObject.html b/docs/api/functions/aws_amplify.datastore.isIdentifierObject.html deleted file mode 100644 index 39718403439..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isIdentifierObject.html +++ /dev/null @@ -1,2 +0,0 @@ -isIdentifierObject | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isModelAttributeAuth.html b/docs/api/functions/aws_amplify.datastore.isModelAttributeAuth.html deleted file mode 100644 index b2701a225a3..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isModelAttributeAuth.html +++ /dev/null @@ -1,2 +0,0 @@ -isModelAttributeAuth | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isModelAttributePrimaryKey.html b/docs/api/functions/aws_amplify.datastore.isModelAttributePrimaryKey.html deleted file mode 100644 index 0338b654768..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isModelAttributePrimaryKey.html +++ /dev/null @@ -1,2 +0,0 @@ -isModelAttributePrimaryKey | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isModelFieldType.html b/docs/api/functions/aws_amplify.datastore.isModelFieldType.html deleted file mode 100644 index 14d84abadf1..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isModelFieldType.html +++ /dev/null @@ -1,2 +0,0 @@ -isModelFieldType | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isPredicateObj.html b/docs/api/functions/aws_amplify.datastore.isPredicateObj.html deleted file mode 100644 index f81031267d9..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isPredicateObj.html +++ /dev/null @@ -1,2 +0,0 @@ -isPredicateObj | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isSchemaModel.html b/docs/api/functions/aws_amplify.datastore.isSchemaModel.html deleted file mode 100644 index ad0505edb5a..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isSchemaModel.html +++ /dev/null @@ -1,2 +0,0 @@ -isSchemaModel | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isTargetNameAssociation.html b/docs/api/functions/aws_amplify.datastore.isTargetNameAssociation.html deleted file mode 100644 index 6811a40d273..00000000000 --- a/docs/api/functions/aws_amplify.datastore.isTargetNameAssociation.html +++ /dev/null @@ -1,2 +0,0 @@ -isTargetNameAssociation | Amplify JS API Documentation -
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.syncExpression-1.html b/docs/api/functions/aws_amplify.datastore.syncExpression-1.html index 1f48bcffdaa..e717af451a0 100644 --- a/docs/api/functions/aws_amplify.datastore.syncExpression-1.html +++ b/docs/api/functions/aws_amplify.datastore.syncExpression-1.html @@ -1,2 +1,11 @@ syncExpression | Amplify JS API Documentation -
\ No newline at end of file +
  • Build an expression that can be used to filter which items of a given Model +are synchronized down from the GraphQL service. E.g.,

    +
    import { DataStore, syncExpression } from 'aws-amplify/datastore';
    import { Post, Comment } from './models';


    DataStore.configure({
    syncExpressions: [
    syncExpression(Post, () => {
    return (post) => post.rating.gt(5);
    }),
    syncExpression(Comment, () => {
    return (comment) => comment.status.eq('active');
    })
    ]
    }); +
    +

    When DataStore starts syncing, only Posts with rating > 5 and Comments with +status === 'active' will be synced down to the user's local store.

    +

    Type Parameters

    Parameters

    Returns Promise<{
        conditionProducer: ConditionProducer<T, A>;
        modelConstructor: PersistentModelConstructor<T>;
    }>

    An sync expression object that can be attached to the DataStore syncExpressions configuration property.

    +
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.storage.isCancelError.html b/docs/api/functions/aws_amplify.storage.isCancelError.html index f3a0b9c293b..d24421a88ab 100644 --- a/docs/api/functions/aws_amplify.storage.isCancelError.html +++ b/docs/api/functions/aws_amplify.storage.isCancelError.html @@ -1,4 +1,8 @@ isCancelError | Amplify JS API Documentation
  • Check if an error is caused by user calling cancel() on a upload/download task. If an overwriting error is supplied to task.cancel(errorOverwrite), this function will return false.

    -

    Parameters

    • error: unknown

    Returns error is CanceledError

\ No newline at end of file +

Parameters

Returns error is CanceledError

+
\ No newline at end of file diff --git a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.CustomOperationArgument.html b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.CustomOperationArgument.html index 6cbe35e3722..d8d06354057 100644 --- a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.CustomOperationArgument.html +++ b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.CustomOperationArgument.html @@ -1,7 +1,7 @@ CustomOperationArgument | Amplify JS API Documentation -
interface CustomOperationArgument {
    isArray: boolean;
    isArrayNullable?: boolean;
    isRequired: boolean;
    name: string;
    type: FieldType;
}

Properties

isArray +
interface CustomOperationArgument {
    isArray: boolean;
    isArrayNullable?: boolean;
    isRequired: boolean;
    name: string;
    type: InputFieldType;
}

Properties

isArray: boolean
isArrayNullable?: boolean
isRequired: boolean
name: string
type: FieldType
\ No newline at end of file +

Properties

isArray: boolean
isArrayNullable?: boolean
isRequired: boolean
name: string
\ No newline at end of file diff --git a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.EnumType.html b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.EnumType.html new file mode 100644 index 00000000000..a5ebf6562e1 --- /dev/null +++ b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.EnumType.html @@ -0,0 +1,3 @@ +EnumType | Amplify JS API Documentation +
interface EnumType {
    enum: string;
}

Properties

Properties

enum: string
\ No newline at end of file diff --git a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.InputType.html b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.InputType.html new file mode 100644 index 00000000000..99f56ed01c5 --- /dev/null +++ b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.InputType.html @@ -0,0 +1,3 @@ +InputType | Amplify JS API Documentation +
interface InputType {
    input: string;
}

Properties

Properties

input: string
\ No newline at end of file diff --git a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.ModelIntrospectionSchema.html b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.ModelIntrospectionSchema.html index 75983470829..bd71784e221 100644 --- a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.ModelIntrospectionSchema.html +++ b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.ModelIntrospectionSchema.html @@ -1,11 +1,13 @@ ModelIntrospectionSchema | Amplify JS API Documentation
interface ModelIntrospectionSchema {
    enums: SchemaEnums;
    models: SchemaModels;
    mutations?: CustomOperations;
    nonModels: SchemaNonModels;
    queries?: CustomOperations;
    subscriptions?: CustomOperations;
    version: 1;
}

Properties

interface ModelIntrospectionSchema {
    conversations?: SchemaConversationRoutes;
    enums: SchemaEnums;
    generations?: SchemaGenerationRoutes;
    models: SchemaModels;
    mutations?: CustomOperations;
    nonModels: SchemaNonModels;
    queries?: CustomOperations;
    subscriptions?: CustomOperations;
    version: 1;
}

Properties

models: SchemaModels
mutations?: CustomOperations
nonModels: SchemaNonModels
subscriptions?: CustomOperations
version: 1
\ No newline at end of file +

Properties

conversations?: SchemaConversationRoutes
models: SchemaModels
mutations?: CustomOperations
nonModels: SchemaNonModels
subscriptions?: CustomOperations
version: 1
\ No newline at end of file diff --git a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversation.html b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversation.html new file mode 100644 index 00000000000..d6370f1a59c --- /dev/null +++ b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversation.html @@ -0,0 +1,3 @@ +SchemaConversation | Amplify JS API Documentation +
interface SchemaConversation {
    modelName: string;
}

Properties

Properties

modelName: string
\ No newline at end of file diff --git a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationMessage.html b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationMessage.html new file mode 100644 index 00000000000..875e81123cb --- /dev/null +++ b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationMessage.html @@ -0,0 +1,5 @@ +SchemaConversationMessage | Amplify JS API Documentation +
interface SchemaConversationMessage {
    modelName: string;
    send: CustomOperation;
    subscribe: CustomOperation;
}

Properties

Properties

modelName: string
subscribe: CustomOperation
\ No newline at end of file diff --git a/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationRoute.html b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationRoute.html new file mode 100644 index 00000000000..0a04c622ced --- /dev/null +++ b/docs/api/interfaces/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationRoute.html @@ -0,0 +1,8 @@ +SchemaConversationRoute | Amplify JS API Documentation +
interface SchemaConversationRoute {
    conversation: SchemaConversation;
    enums: SchemaEnums;
    message: SchemaConversationMessage;
    models: SchemaModels;
    name: string;
    nonModels: SchemaNonModels;
}

Properties

conversation: SchemaConversation
models: SchemaModels
name: string
nonModels: SchemaNonModels
\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.auth._Reference_Types_.AuthSignOutInput.html b/docs/api/interfaces/aws_amplify.auth._Reference_Types_.AuthSignOutInput.html index 31c54915f61..ff7c2a06a74 100644 --- a/docs/api/interfaces/aws_amplify.auth._Reference_Types_.AuthSignOutInput.html +++ b/docs/api/interfaces/aws_amplify.auth._Reference_Types_.AuthSignOutInput.html @@ -1,3 +1,4 @@ AuthSignOutInput | Amplify JS API Documentation -
interface AuthSignOutInput {
    global: boolean;
}

Properties

Properties

global: boolean
\ No newline at end of file +
interface AuthSignOutInput {
    global: boolean;
    oauth?: {
        redirectUrl?: string;
    };
}

Properties

Properties

global: boolean
oauth?: {
    redirectUrl?: string;
}

Type declaration

  • Optional redirectUrl?: string
\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenOrchestrator.html b/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenOrchestrator.html index 565c8461936..d5ef1408e1a 100644 --- a/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenOrchestrator.html +++ b/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenOrchestrator.html @@ -1,9 +1,11 @@ AuthTokenOrchestrator | Amplify JS API Documentation -
interface AuthTokenOrchestrator {
    clearDeviceMetadata(username?): Promise<void>;
    clearTokens(): Promise<void>;
    getDeviceMetadata(username?): Promise<null | DeviceMetadata>;
    getTokens(options?): Promise<null | AuthTokens & {
        signInDetails?: CognitoAuthSignInDetails;
    }>;
    setAuthTokenStore(tokenStore): void;
    setTokenRefresher(tokenRefresher): void;
    setTokens(__namedParameters): Promise<void>;
}

Implemented by

Methods

clearDeviceMetadata +
interface AuthTokenOrchestrator {
    clearDeviceMetadata(username?): Promise<void>;
    clearTokens(): Promise<void>;
    getDeviceMetadata(username?): Promise<null | DeviceMetadata>;
    getOAuthMetadata(): Promise<null | OAuthMetadata>;
    getTokens(options?): Promise<null | AuthTokens & {
        signInDetails?: CognitoAuthSignInDetails;
    }>;
    setAuthTokenStore(tokenStore): void;
    setOAuthMetadata(metadata): Promise<void>;
    setTokenRefresher(tokenRefresher): void;
    setTokens(__namedParameters): Promise<void>;
}

Implemented by

Methods

  • Parameters

    • Optional username: string

    Returns Promise<void>

  • Returns Promise<void>

  • Parameters

    Returns void

  • Parameters

    Returns void

\ No newline at end of file +

Methods

  • Parameters

    • Optional username: string

    Returns Promise<void>

  • Returns Promise<void>

  • Parameters

    Returns void

  • Parameters

    Returns Promise<void>

  • Parameters

    Returns void

\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenStore.html b/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenStore.html index fab9c1cd630..cd4a38d5034 100644 --- a/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenStore.html +++ b/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.AuthTokenStore.html @@ -1,9 +1,11 @@ AuthTokenStore | Amplify JS API Documentation -
interface AuthTokenStore {
    clearDeviceMetadata(username?): Promise<void>;
    clearTokens(): Promise<void>;
    getDeviceMetadata(username?): Promise<null | DeviceMetadata>;
    getLastAuthUser(): Promise<string>;
    loadTokens(): Promise<null | CognitoAuthTokens>;
    setKeyValueStorage(keyValueStorage): void;
    storeTokens(tokens): Promise<void>;
}

Implemented by

Methods

clearDeviceMetadata +
interface AuthTokenStore {
    clearDeviceMetadata(username?): Promise<void>;
    clearTokens(): Promise<void>;
    getDeviceMetadata(username?): Promise<null | DeviceMetadata>;
    getLastAuthUser(): Promise<string>;
    getOAuthMetadata(): Promise<null | OAuthMetadata>;
    loadTokens(): Promise<null | CognitoAuthTokens>;
    setKeyValueStorage(keyValueStorage): void;
    setOAuthMetadata(metadata): Promise<void>;
    storeTokens(tokens): Promise<void>;
}

Implemented by

Methods

  • Parameters

    • Optional username: string

    Returns Promise<void>

  • Returns Promise<void>

  • Returns Promise<string>

  • Parameters

    Returns Promise<void>

\ No newline at end of file +

Methods

  • Parameters

    • Optional username: string

    Returns Promise<void>

  • Returns Promise<void>

  • Returns Promise<string>

  • Parameters

    Returns Promise<void>

  • Parameters

    Returns Promise<void>

\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.OAuthMetadata.html b/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.OAuthMetadata.html new file mode 100644 index 00000000000..5c3d5d0b322 --- /dev/null +++ b/docs/api/interfaces/aws_amplify.auth_cognito._Reference_Types_.OAuthMetadata.html @@ -0,0 +1,3 @@ +OAuthMetadata | Amplify JS API Documentation +
interface OAuthMetadata {
    oauthSignIn: boolean;
}

Properties

Properties

oauthSignIn: boolean
\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.index._Reference_Types_.CustomOperationArgument.html b/docs/api/interfaces/aws_amplify.index._Reference_Types_.CustomOperationArgument.html index e7dc8ad4f78..957cce39925 100644 --- a/docs/api/interfaces/aws_amplify.index._Reference_Types_.CustomOperationArgument.html +++ b/docs/api/interfaces/aws_amplify.index._Reference_Types_.CustomOperationArgument.html @@ -1,7 +1,7 @@ CustomOperationArgument | Amplify JS API Documentation -
interface CustomOperationArgument {
    isArray: boolean;
    isArrayNullable?: boolean;
    isRequired: boolean;
    name: string;
    type: FieldType;
}

Properties

isArray +
interface CustomOperationArgument {
    isArray: boolean;
    isArrayNullable?: boolean;
    isRequired: boolean;
    name: string;
    type: InputFieldType;
}

Properties

isArray: boolean
isArrayNullable?: boolean
isRequired: boolean
name: string
type: FieldType
\ No newline at end of file +

Properties

isArray: boolean
isArrayNullable?: boolean
isRequired: boolean
name: string
\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.index._Reference_Types_.EnumType.html b/docs/api/interfaces/aws_amplify.index._Reference_Types_.EnumType.html new file mode 100644 index 00000000000..bc92c593fff --- /dev/null +++ b/docs/api/interfaces/aws_amplify.index._Reference_Types_.EnumType.html @@ -0,0 +1,3 @@ +EnumType | Amplify JS API Documentation +
interface EnumType {
    enum: string;
}

Properties

Properties

enum: string
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isModelAttributeCompositeKey.html b/docs/api/interfaces/aws_amplify.index._Reference_Types_.InputType.html similarity index 74% rename from docs/api/functions/aws_amplify.datastore.isModelAttributeCompositeKey.html rename to docs/api/interfaces/aws_amplify.index._Reference_Types_.InputType.html index 7c29539ea6f..89124e2dedf 100644 --- a/docs/api/functions/aws_amplify.datastore.isModelAttributeCompositeKey.html +++ b/docs/api/interfaces/aws_amplify.index._Reference_Types_.InputType.html @@ -1,2 +1,3 @@ -isModelAttributeCompositeKey | Amplify JS API Documentation -
\ No newline at end of file +InputType | Amplify JS API Documentation +
interface InputType {
    input: string;
}

Properties

Properties

input: string
\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.index._Reference_Types_.ModelIntrospectionSchema.html b/docs/api/interfaces/aws_amplify.index._Reference_Types_.ModelIntrospectionSchema.html index 30a48c6059c..fd8bfc48f4d 100644 --- a/docs/api/interfaces/aws_amplify.index._Reference_Types_.ModelIntrospectionSchema.html +++ b/docs/api/interfaces/aws_amplify.index._Reference_Types_.ModelIntrospectionSchema.html @@ -1,11 +1,13 @@ ModelIntrospectionSchema | Amplify JS API Documentation
interface ModelIntrospectionSchema {
    enums: SchemaEnums;
    models: SchemaModels;
    mutations?: CustomOperations;
    nonModels: SchemaNonModels;
    queries?: CustomOperations;
    subscriptions?: CustomOperations;
    version: 1;
}

Properties

interface ModelIntrospectionSchema {
    conversations?: SchemaConversationRoutes;
    enums: SchemaEnums;
    generations?: SchemaGenerationRoutes;
    models: SchemaModels;
    mutations?: CustomOperations;
    nonModels: SchemaNonModels;
    queries?: CustomOperations;
    subscriptions?: CustomOperations;
    version: 1;
}

Properties

models: SchemaModels
mutations?: CustomOperations
nonModels: SchemaNonModels
subscriptions?: CustomOperations
version: 1
\ No newline at end of file +

Properties

conversations?: SchemaConversationRoutes
models: SchemaModels
mutations?: CustomOperations
nonModels: SchemaNonModels
subscriptions?: CustomOperations
version: 1
\ No newline at end of file diff --git a/docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversation.html b/docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversation.html new file mode 100644 index 00000000000..ecce961cbce --- /dev/null +++ b/docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversation.html @@ -0,0 +1,3 @@ +SchemaConversation | Amplify JS API Documentation +
interface SchemaConversation {
    modelName: string;
}

Properties

Properties

modelName: string
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isModelAttributeKey.html b/docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversationMessage.html similarity index 67% rename from docs/api/functions/aws_amplify.datastore.isModelAttributeKey.html rename to docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversationMessage.html index 0af20619595..afa62925ee3 100644 --- a/docs/api/functions/aws_amplify.datastore.isModelAttributeKey.html +++ b/docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversationMessage.html @@ -1,2 +1,5 @@ -isModelAttributeKey | Amplify JS API Documentation -
\ No newline at end of file +SchemaConversationMessage | Amplify JS API Documentation +
interface SchemaConversationMessage {
    modelName: string;
    send: CustomOperation;
    subscribe: CustomOperation;
}

Properties

Properties

modelName: string
subscribe: CustomOperation
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isPredicateGroup.html b/docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversationRoute.html similarity index 58% rename from docs/api/functions/aws_amplify.datastore.isPredicateGroup.html rename to docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversationRoute.html index 8b5f8692b3d..8253f72e272 100644 --- a/docs/api/functions/aws_amplify.datastore.isPredicateGroup.html +++ b/docs/api/interfaces/aws_amplify.index._Reference_Types_.SchemaConversationRoute.html @@ -1,2 +1,8 @@ -isPredicateGroup | Amplify JS API Documentation -
\ No newline at end of file +SchemaConversationRoute | Amplify JS API Documentation +
interface SchemaConversationRoute {
    conversation: SchemaConversation;
    enums: SchemaEnums;
    message: SchemaConversationMessage;
    models: SchemaModels;
    name: string;
    nonModels: SchemaNonModels;
}

Properties

conversation: SchemaConversation
models: SchemaModels
name: string
nonModels: SchemaNonModels
\ No newline at end of file diff --git a/docs/api/modules/_aws_amplify_adapter_nextjs.api._Reference_Types_.html b/docs/api/modules/_aws_amplify_adapter_nextjs.api._Reference_Types_.html index 898f549b6fd..32fff701935 100644 --- a/docs/api/modules/_aws_amplify_adapter_nextjs.api._Reference_Types_.html +++ b/docs/api/modules/_aws_amplify_adapter_nextjs.api._Reference_Types_.html @@ -30,6 +30,7 @@ DirectiveDefinitionNode DirectiveNode DocumentNode +EnumType EnumTypeDefinitionNode EnumTypeExtensionNode EnumValueDefinitionNode @@ -55,6 +56,7 @@ InlineFragmentNode InputObjectTypeDefinitionNode InputObjectTypeExtensionNode +InputType InputValueDefinitionNode IntValueNode InteractionsLexV1Config @@ -104,6 +106,9 @@ S3ProviderConfig ScalarTypeDefinitionNode ScalarTypeExtensionNode +SchemaConversation +SchemaConversationMessage +SchemaConversationRoute SchemaDefinitionNode SchemaEnum SchemaExtensionNode @@ -165,6 +170,7 @@ GraphQLSubscription GraphQLVariablesV6 GraphqlSubscriptionResult +InputFieldType InteractionsConfig Maybe ModelTypes @@ -176,7 +182,10 @@ OperationTypeNode PredictionsConfig PromiseConstructorLike +ScalarType +SchemaConversationRoutes SchemaEnums +SchemaGenerationRoutes SchemaModels SchemaNonModels SelectionNode diff --git a/docs/api/modules/_aws_amplify_adapter_nextjs.html b/docs/api/modules/_aws_amplify_adapter_nextjs.html index 685f5023bc6..5f547379ee5 100644 --- a/docs/api/modules/_aws_amplify_adapter_nextjs.html +++ b/docs/api/modules/_aws_amplify_adapter_nextjs.html @@ -1,5 +1,5 @@ -@aws-amplify/adapter-nextjs - v1.2.13 | Amplify JS API Documentation -

Module @aws-amplify/adapter-nextjs - v1.2.13

This package contains the AWS Amplify Next.js Adapter. For more information on using Next.js in your application please reference the Amplify Dev Center.

+@aws-amplify/adapter-nextjs - v1.2.19 | Amplify JS API Documentation +

Module @aws-amplify/adapter-nextjs - v1.2.19

This package contains the AWS Amplify Next.js Adapter. For more information on using Next.js in your application please reference the Amplify Dev Center.

Index

Modules

api index utils diff --git a/docs/api/modules/_aws_amplify_datastore_storage_adapter.html b/docs/api/modules/_aws_amplify_datastore_storage_adapter.html index b7a1cf0f9df..d5ba4855913 100644 --- a/docs/api/modules/_aws_amplify_datastore_storage_adapter.html +++ b/docs/api/modules/_aws_amplify_datastore_storage_adapter.html @@ -1,5 +1,5 @@ -@aws-amplify/datastore-storage-adapter - v2.1.45 | Amplify JS API Documentation -

Module @aws-amplify/datastore-storage-adapter - v2.1.45

This package contains the AWS Amplify DataStore storage adapter. For more information on using the DataStore storage adapter in your application please reference the Amplify Dev Center.

+@aws-amplify/datastore-storage-adapter - v2.1.51 | Amplify JS API Documentation +

Module @aws-amplify/datastore-storage-adapter - v2.1.51

This package contains the AWS Amplify DataStore storage adapter. For more information on using the DataStore storage adapter in your application please reference the Amplify Dev Center.

Index

Modules

ExpoSQLiteAdapter/ExpoSQLiteAdapter SQLiteAdapter/SQLiteAdapter index diff --git a/docs/api/modules/_aws_amplify_geo.html b/docs/api/modules/_aws_amplify_geo.html index c3676097260..8ce5e20a24d 100644 --- a/docs/api/modules/_aws_amplify_geo.html +++ b/docs/api/modules/_aws_amplify_geo.html @@ -1,5 +1,5 @@ -@aws-amplify/geo - v3.0.43 | Amplify JS API Documentation -

Module @aws-amplify/geo - v3.0.43

This package contains the AWS Amplify Geo category. For more information on using Geo in your application please reference the Amplify Dev Center.

+@aws-amplify/geo - v3.0.49 | Amplify JS API Documentation +

Module @aws-amplify/geo - v3.0.49

This package contains the AWS Amplify Geo category. For more information on using Geo in your application please reference the Amplify Dev Center.

Index

Modules

\ No newline at end of file diff --git a/docs/api/modules/_aws_amplify_interactions.html b/docs/api/modules/_aws_amplify_interactions.html index a2bd17d5463..7ac801f91b0 100644 --- a/docs/api/modules/_aws_amplify_interactions.html +++ b/docs/api/modules/_aws_amplify_interactions.html @@ -1,5 +1,5 @@ -@aws-amplify/interactions - v6.0.42 | Amplify JS API Documentation -

Module @aws-amplify/interactions - v6.0.42

This package contains the AWS Amplify Interactions category. For more information on using Interactions in your application please reference the Amplify Dev Center.

+@aws-amplify/interactions - v6.0.48 | Amplify JS API Documentation +

Module @aws-amplify/interactions - v6.0.48

This package contains the AWS Amplify Interactions category. For more information on using Interactions in your application please reference the Amplify Dev Center.

Index

Modules

index lex-v1 lex-v2 diff --git a/docs/api/modules/_aws_amplify_predictions.html b/docs/api/modules/_aws_amplify_predictions.html index 32e5fb49e56..784fe1cf826 100644 --- a/docs/api/modules/_aws_amplify_predictions.html +++ b/docs/api/modules/_aws_amplify_predictions.html @@ -1,5 +1,5 @@ -@aws-amplify/predictions - v6.1.18 | Amplify JS API Documentation -

Module @aws-amplify/predictions - v6.1.18

This package contains the AWS Amplify Predictions category. For more information on using Predictions in your application please reference the Amplify Dev Center.

+@aws-amplify/predictions - v6.1.24 | Amplify JS API Documentation +

Module @aws-amplify/predictions - v6.1.24

This package contains the AWS Amplify Predictions category. For more information on using Predictions in your application please reference the Amplify Dev Center.

Index

Modules

Interfaces

IdentifyEntitiesInput IdentifyEntitiesOutput diff --git a/docs/api/modules/_aws_amplify_pubsub.html b/docs/api/modules/_aws_amplify_pubsub.html index 45940312abd..7ea9c8e179d 100644 --- a/docs/api/modules/_aws_amplify_pubsub.html +++ b/docs/api/modules/_aws_amplify_pubsub.html @@ -1,5 +1,5 @@ -@aws-amplify/pubsub - v6.1.18 | Amplify JS API Documentation -

Module @aws-amplify/pubsub - v6.1.18

This package contains the AWS Amplify PubSub category. For more information on using PubSub in your application please reference the Amplify Dev Center.

+@aws-amplify/pubsub - v6.1.24 | Amplify JS API Documentation +

Module @aws-amplify/pubsub - v6.1.24

This package contains the AWS Amplify PubSub category. For more information on using PubSub in your application please reference the Amplify Dev Center.

Index

Modules

clients/iot clients/mqtt index diff --git a/docs/api/modules/aws_amplify.auth_cognito._Reference_Types_.html b/docs/api/modules/aws_amplify.auth_cognito._Reference_Types_.html index c722d757ef6..28b2f5a62b8 100644 --- a/docs/api/modules/aws_amplify.auth_cognito._Reference_Types_.html +++ b/docs/api/modules/aws_amplify.auth_cognito._Reference_Types_.html @@ -6,6 +6,7 @@ DeviceMetadata Identity IdentityIdStore +OAuthMetadata

Type Aliases

AuthKeys CognitoAuthTokens TokenRefresher diff --git a/docs/api/modules/aws_amplify.datastore._Reference_Types_.__home_runner_work_amplify_js_amplify_js_amplify_js_packages_datastore_dist_esm_types_.html b/docs/api/modules/aws_amplify.datastore._Reference_Types_.__home_runner_work_amplify_js_amplify_js_amplify_js_packages_datastore_dist_esm_types_.html index 9e9710c0762..20427856326 100644 --- a/docs/api/modules/aws_amplify.datastore._Reference_Types_.__home_runner_work_amplify_js_amplify_js_amplify_js_packages_datastore_dist_esm_types_.html +++ b/docs/api/modules/aws_amplify.datastore._Reference_Types_.__home_runner_work_amplify_js_amplify_js_amplify_js_packages_datastore_dist_esm_types_.html @@ -118,22 +118,6 @@ WithoutNevers __identifierBrand__ __modelMeta__ -isAssociatedWith -isEnumFieldType -isFieldAssociation -isGraphQLScalarType -isIdentifierObject -isModelAttributeAuth -isModelAttributeCompositeKey -isModelAttributeKey -isModelAttributePrimaryKey -isModelFieldType -isNonModelFieldType -isPredicateGroup -isPredicateObj -isSchemaModel -isSchemaModelWithAttributes -isTargetNameAssociation syncExpression

Interfaces

References

Re-exports AllFieldOperators
Re-exports AllOperators
Re-exports AmplifyContext
Re-exports AuthModeStrategy
Re-exports AuthModeStrategyParams
Re-exports AuthModeStrategyReturn
Re-exports AuthModeStrategyType
Re-exports AuthProviders
Re-exports AuthorizationRule
Re-exports CompositeIdentifier
Re-exports ConflictHandler
Re-exports ControlMessageType
Re-exports CustomIdentifier
Re-exports DISCARD
Re-exports DataStoreConfig
Re-exports DataStoreSchema
Re-exports DataStoreSnapshot
Re-exports DefaultPersistentModelMetaData
Re-exports DeferredCallbackResolverOptions
Re-exports ErrorHandler
Re-exports ErrorType
Re-exports GraphQLCondition
Re-exports GraphQLField
Re-exports GraphQLFilter
Re-exports GraphQLScalarType
Re-exports Identifier
Re-exports IdentifierBrand
Re-exports IdentifierFieldOrIdentifierObject
Re-exports IdentifierFieldValue
Re-exports IdentifierFields
Re-exports IdentifierFieldsForInit
Re-exports IndexesType
Re-exports InternalSchema
Re-exports InternalSubscriptionMessage
Re-exports KeyType
Re-exports LimitTimerRaceResolvedValues
Re-exports ManagedIdentifier
Re-exports MatchableTypes
Re-exports MetadataOrDefault
Re-exports MetadataReadOnlyFields
Re-exports ModelAssociation
Re-exports ModelAttribute
Re-exports ModelAttributeAuth
Re-exports ModelAttributeAuthAllow
Re-exports ModelAttributeAuthProperty
Re-exports ModelAttributeAuthProvider
Re-exports ModelAttributes
Re-exports ModelAuthModes
Re-exports ModelAuthRule
Re-exports ModelField
Re-exports ModelFieldType
Re-exports ModelFields
Re-exports ModelInit
Re-exports ModelInitBase
Re-exports ModelInstanceMetadata
Re-exports ModelKeys
Re-exports ModelMeta
Re-exports ModelOperation
Re-exports ModelPredicate
Re-exports ModelPredicateAggregateExtender
Re-exports ModelPredicateExtender
Re-exports ModelPredicateNegation
Re-exports ModelPredicateOperator
Re-exports MutableModel
Re-exports NamespaceResolver
Re-exports NonModelFieldType
Re-exports NonModelTypeConstructor
Re-exports NonNeverKeys
Re-exports ObserveQueryOptions
Re-exports OpType
Re-exports OptionallyManagedIdentifier
Re-exports PaginationInput
Re-exports PersistentModel
Re-exports PersistentModelConstructor
Re-exports PersistentModelMetaData
Re-exports PredicateExpression
Re-exports PredicateFieldType
Re-exports PredicateGroups
Re-exports PredicateInternalsKey
Re-exports PredicateObject
Re-exports PredicatesGroup
Re-exports ProcessName
Re-exports ProducerModelPredicate
Re-exports ProducerPaginationInput
Re-exports ProducerSortPredicate
Re-exports QueryOne
Re-exports RecursiveModelPredicate
Re-exports RecursiveModelPredicateAggregateExtender
Re-exports RecursiveModelPredicateExtender
Re-exports RecursiveModelPredicateNegation
Re-exports RecursiveModelPredicateOperator
Re-exports RelationType
Re-exports RelationshipType
Re-exports Scalar
Re-exports Schema
Re-exports SchemaModel
Re-exports SchemaModels
Re-exports SchemaNamespace
Re-exports SchemaNamespaces
Re-exports SchemaNonModel
Re-exports SchemaNonModels
Re-exports SettableFieldType
Re-exports SortDirection
Re-exports SortPredicate
Re-exports SortPredicateExpression
Re-exports SortPredicateObject
Re-exports SortPredicatesGroup
Re-exports SubscriptionMessage
Re-exports SyncConflict
Re-exports SyncError
Re-exports SyncExpression
Re-exports SystemComponent
Re-exports TypeConstructorMap
Re-exports UserSchema
Re-exports V5ModelPredicate
Re-exports ValuePredicate
Re-exports WithoutNevers
Re-exports __identifierBrand__
Re-exports __modelMeta__
Re-exports isAssociatedWith
Re-exports isEnumFieldType
Re-exports isFieldAssociation
Re-exports isGraphQLScalarType
Re-exports isIdentifierObject
Re-exports isModelAttributeAuth
Re-exports isModelAttributeCompositeKey
Re-exports isModelAttributeKey
Re-exports isModelAttributePrimaryKey
Re-exports isModelFieldType
Re-exports isNonModelFieldType
Re-exports isPredicateGroup
Re-exports isPredicateObj
Re-exports isSchemaModel
Re-exports isSchemaModelWithAttributes
Re-exports isTargetNameAssociation
Re-exports syncExpression
\ No newline at end of file +

References

Re-exports AllFieldOperators
Re-exports AllOperators
Re-exports AmplifyContext
Re-exports AuthModeStrategy
Re-exports AuthModeStrategyParams
Re-exports AuthModeStrategyReturn
Re-exports AuthModeStrategyType
Re-exports AuthProviders
Re-exports AuthorizationRule
Re-exports CompositeIdentifier
Re-exports ConflictHandler
Re-exports ControlMessageType
Re-exports CustomIdentifier
Re-exports DISCARD
Re-exports DataStoreConfig
Re-exports DataStoreSchema
Re-exports DataStoreSnapshot
Re-exports DefaultPersistentModelMetaData
Re-exports DeferredCallbackResolverOptions
Re-exports ErrorHandler
Re-exports ErrorType
Re-exports GraphQLCondition
Re-exports GraphQLField
Re-exports GraphQLFilter
Re-exports GraphQLScalarType
Re-exports Identifier
Re-exports IdentifierBrand
Re-exports IdentifierFieldOrIdentifierObject
Re-exports IdentifierFieldValue
Re-exports IdentifierFields
Re-exports IdentifierFieldsForInit
Re-exports IndexesType
Re-exports InternalSchema
Re-exports InternalSubscriptionMessage
Re-exports KeyType
Re-exports LimitTimerRaceResolvedValues
Re-exports ManagedIdentifier
Re-exports MatchableTypes
Re-exports MetadataOrDefault
Re-exports MetadataReadOnlyFields
Re-exports ModelAssociation
Re-exports ModelAttribute
Re-exports ModelAttributeAuth
Re-exports ModelAttributeAuthAllow
Re-exports ModelAttributeAuthProperty
Re-exports ModelAttributeAuthProvider
Re-exports ModelAttributes
Re-exports ModelAuthModes
Re-exports ModelAuthRule
Re-exports ModelField
Re-exports ModelFieldType
Re-exports ModelFields
Re-exports ModelInit
Re-exports ModelInitBase
Re-exports ModelInstanceMetadata
Re-exports ModelKeys
Re-exports ModelMeta
Re-exports ModelOperation
Re-exports ModelPredicate
Re-exports ModelPredicateAggregateExtender
Re-exports ModelPredicateExtender
Re-exports ModelPredicateNegation
Re-exports ModelPredicateOperator
Re-exports MutableModel
Re-exports NamespaceResolver
Re-exports NonModelFieldType
Re-exports NonModelTypeConstructor
Re-exports NonNeverKeys
Re-exports ObserveQueryOptions
Re-exports OpType
Re-exports OptionallyManagedIdentifier
Re-exports PaginationInput
Re-exports PersistentModel
Re-exports PersistentModelConstructor
Re-exports PersistentModelMetaData
Re-exports PredicateExpression
Re-exports PredicateFieldType
Re-exports PredicateGroups
Re-exports PredicateInternalsKey
Re-exports PredicateObject
Re-exports PredicatesGroup
Re-exports ProcessName
Re-exports ProducerModelPredicate
Re-exports ProducerPaginationInput
Re-exports ProducerSortPredicate
Re-exports QueryOne
Re-exports RecursiveModelPredicate
Re-exports RecursiveModelPredicateAggregateExtender
Re-exports RecursiveModelPredicateExtender
Re-exports RecursiveModelPredicateNegation
Re-exports RecursiveModelPredicateOperator
Re-exports RelationType
Re-exports RelationshipType
Re-exports Scalar
Re-exports Schema
Re-exports SchemaModel
Re-exports SchemaModels
Re-exports SchemaNamespace
Re-exports SchemaNamespaces
Re-exports SchemaNonModel
Re-exports SchemaNonModels
Re-exports SettableFieldType
Re-exports SortDirection
Re-exports SortPredicate
Re-exports SortPredicateExpression
Re-exports SortPredicateObject
Re-exports SortPredicatesGroup
Re-exports SubscriptionMessage
Re-exports SyncConflict
Re-exports SyncError
Re-exports SyncExpression
Re-exports SystemComponent
Re-exports TypeConstructorMap
Re-exports UserSchema
Re-exports V5ModelPredicate
Re-exports ValuePredicate
Re-exports WithoutNevers
Re-exports __identifierBrand__
Re-exports __modelMeta__
Re-exports syncExpression
\ No newline at end of file diff --git a/docs/api/modules/aws_amplify.datastore.html b/docs/api/modules/aws_amplify.datastore.html index 6f0c4387067..7b988c46f20 100644 --- a/docs/api/modules/aws_amplify.datastore.html +++ b/docs/api/modules/aws_amplify.datastore.html @@ -132,21 +132,5 @@ __modelMeta__ utils

Functions

\ No newline at end of file diff --git a/docs/api/modules/aws_amplify.html b/docs/api/modules/aws_amplify.html index 8538cd19e81..a7615c10fbb 100644 --- a/docs/api/modules/aws_amplify.html +++ b/docs/api/modules/aws_amplify.html @@ -1,5 +1,5 @@ -aws-amplify - v6.5.1 | Amplify JS API Documentation -

Module aws-amplify - v6.5.1

AWS Amplify Package - aws-amplify

AWS Amplify is a JavaScript library for frontend and mobile developers building cloud-enabled applications. The library is a declarative interface across different categories of operations in order to make common tasks easier to add into your application. The default implementation works with Amazon Web Services (AWS) resources but is designed to be open and pluggable for usage with other cloud services that wish to provide an implementation or custom backends.

+aws-amplify - v6.6.2 | Amplify JS API Documentation +

Module aws-amplify - v6.6.2

AWS Amplify Package - aws-amplify

AWS Amplify is a JavaScript library for frontend and mobile developers building cloud-enabled applications. The library is a declarative interface across different categories of operations in order to make common tasks easier to add into your application. The default implementation works with Amazon Web Services (AWS) resources but is designed to be open and pluggable for usage with other cloud services that wish to provide an implementation or custom backends.

Documentation is available here.

Index

Modules

adapter-core analytics diff --git a/docs/api/modules/aws_amplify.index._Reference_Types_.html b/docs/api/modules/aws_amplify.index._Reference_Types_.html index 198e7105463..314878e6a95 100644 --- a/docs/api/modules/aws_amplify.index._Reference_Types_.html +++ b/docs/api/modules/aws_amplify.index._Reference_Types_.html @@ -10,6 +10,7 @@ ConvertConfig CustomOperation CustomOperationArgument +EnumType EventBufferConfig Field GraphQLProviderConfig @@ -18,6 +19,7 @@ IdentifyTextDefaults IdentityLabelsDefaults InAppMessagingProviderConfig +InputType InteractionsLexV1Config InteractionsLexV2Config InterpretConfig @@ -41,6 +43,9 @@ PushNotificationProviderConfig RESTProviderConfig S3ProviderConfig +SchemaConversation +SchemaConversationMessage +SchemaConversationRoute SchemaEnum SchemaModel SchemaNonModel @@ -60,13 +65,17 @@ Fields GeoConfig GraphQLAuthMode +InputFieldType InteractionsConfig NotificationsConfig Partial Pick PredictionsConfig Record +ScalarType +SchemaConversationRoutes SchemaEnums +SchemaGenerationRoutes SchemaModels SchemaNonModels StorageConfig diff --git a/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.FieldType.html b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.FieldType.html index 985f5888607..7c97ed889f9 100644 --- a/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.FieldType.html +++ b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.FieldType.html @@ -1,2 +1,2 @@ FieldType | Amplify JS API Documentation -
FieldType: "ID" | "String" | "Int" | "Float" | "AWSDate" | "AWSTime" | "AWSDateTime" | "AWSTimestamp" | "AWSEmail" | "AWSURL" | "AWSIPAddress" | "Boolean" | "AWSJSON" | "AWSPhone" | {
    enum: string;
} | ModelFieldType | NonModelFieldType

Type declaration

  • enum: string
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isSchemaModelWithAttributes.html b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.InputFieldType.html similarity index 88% rename from docs/api/functions/aws_amplify.datastore.isSchemaModelWithAttributes.html rename to docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.InputFieldType.html index 90957e3f9a0..ae8877fd113 100644 --- a/docs/api/functions/aws_amplify.datastore.isSchemaModelWithAttributes.html +++ b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.InputFieldType.html @@ -1,2 +1,2 @@ -isSchemaModelWithAttributes | Amplify JS API Documentation -
\ No newline at end of file +InputFieldType | Amplify JS API Documentation +
\ No newline at end of file diff --git a/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.ScalarType.html b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.ScalarType.html new file mode 100644 index 00000000000..304cc4425a9 --- /dev/null +++ b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.ScalarType.html @@ -0,0 +1,2 @@ +ScalarType | Amplify JS API Documentation +
ScalarType: "ID" | "String" | "Int" | "Float" | "AWSDate" | "AWSTime" | "AWSDateTime" | "AWSTimestamp" | "AWSEmail" | "AWSURL" | "AWSIPAddress" | "Boolean" | "AWSJSON" | "AWSPhone"
\ No newline at end of file diff --git a/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationRoutes.html b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationRoutes.html new file mode 100644 index 00000000000..f75c9601692 --- /dev/null +++ b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaConversationRoutes.html @@ -0,0 +1,2 @@ +SchemaConversationRoutes | Amplify JS API Documentation +
\ No newline at end of file diff --git a/docs/api/functions/aws_amplify.datastore.isNonModelFieldType.html b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaGenerationRoutes.html similarity index 89% rename from docs/api/functions/aws_amplify.datastore.isNonModelFieldType.html rename to docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaGenerationRoutes.html index 417d4d1a51f..4d15cc9e08b 100644 --- a/docs/api/functions/aws_amplify.datastore.isNonModelFieldType.html +++ b/docs/api/types/_aws_amplify_adapter_nextjs.api._Reference_Types_.SchemaGenerationRoutes.html @@ -1,2 +1,2 @@ -isNonModelFieldType | Amplify JS API Documentation -
\ No newline at end of file +SchemaGenerationRoutes | Amplify JS API Documentation +
\ No newline at end of file diff --git a/docs/api/types/aws_amplify.index._Reference_Types_.FieldType.html b/docs/api/types/aws_amplify.index._Reference_Types_.FieldType.html index 1f490bc0577..4ed26cca63a 100644 --- a/docs/api/types/aws_amplify.index._Reference_Types_.FieldType.html +++ b/docs/api/types/aws_amplify.index._Reference_Types_.FieldType.html @@ -1,2 +1,2 @@ FieldType | Amplify JS API Documentation -
FieldType: "ID" | "String" | "Int" | "Float" | "AWSDate" | "AWSTime" | "AWSDateTime" | "AWSTimestamp" | "AWSEmail" | "AWSURL" | "AWSIPAddress" | "Boolean" | "AWSJSON" | "AWSPhone" | {
    enum: string;
} | ModelFieldType | NonModelFieldType

Type declaration

  • enum: string
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/api/types/aws_amplify.index._Reference_Types_.InputFieldType.html b/docs/api/types/aws_amplify.index._Reference_Types_.InputFieldType.html new file mode 100644 index 00000000000..04549210e36 --- /dev/null +++ b/docs/api/types/aws_amplify.index._Reference_Types_.InputFieldType.html @@ -0,0 +1,2 @@ +InputFieldType | Amplify JS API Documentation +
\ No newline at end of file diff --git a/docs/api/types/aws_amplify.index._Reference_Types_.ScalarType.html b/docs/api/types/aws_amplify.index._Reference_Types_.ScalarType.html new file mode 100644 index 00000000000..feece45fe8a --- /dev/null +++ b/docs/api/types/aws_amplify.index._Reference_Types_.ScalarType.html @@ -0,0 +1,2 @@ +ScalarType | Amplify JS API Documentation +
ScalarType: "ID" | "String" | "Int" | "Float" | "AWSDate" | "AWSTime" | "AWSDateTime" | "AWSTimestamp" | "AWSEmail" | "AWSURL" | "AWSIPAddress" | "Boolean" | "AWSJSON" | "AWSPhone"
\ No newline at end of file diff --git a/docs/api/types/aws_amplify.index._Reference_Types_.SchemaConversationRoutes.html b/docs/api/types/aws_amplify.index._Reference_Types_.SchemaConversationRoutes.html new file mode 100644 index 00000000000..18b0096022d --- /dev/null +++ b/docs/api/types/aws_amplify.index._Reference_Types_.SchemaConversationRoutes.html @@ -0,0 +1,2 @@ +SchemaConversationRoutes | Amplify JS API Documentation +
\ No newline at end of file diff --git a/docs/api/types/aws_amplify.index._Reference_Types_.SchemaGenerationRoutes.html b/docs/api/types/aws_amplify.index._Reference_Types_.SchemaGenerationRoutes.html new file mode 100644 index 00000000000..8170049841b --- /dev/null +++ b/docs/api/types/aws_amplify.index._Reference_Types_.SchemaGenerationRoutes.html @@ -0,0 +1,2 @@ +SchemaGenerationRoutes | Amplify JS API Documentation +
\ No newline at end of file diff --git a/package.json b/package.json index a0348c9f736..7d5edc30915 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "eslint-plugin-promise": "^6.1.1", "eslint-plugin-unused-imports": "^3.0.0", "expect": "^29.7.0", - "glob": "10.3.10", + "glob": "^10.3.10", "husky": "^9.0.11", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -137,7 +137,9 @@ "**/glob/minipass": "6.0.2", "nx": "16.7.0", "xml2js": "0.5.0", - "tar": "6.2.1", - "glob@^10.0.0": "10.3.10" + "tar": "6.2.1" + }, + "overrides": { + "tar": "6.2.1" } } diff --git a/packages/adapter-nextjs/CHANGELOG.md b/packages/adapter-nextjs/CHANGELOG.md index e75880a7435..4c2e0b811c3 100644 --- a/packages/adapter-nextjs/CHANGELOG.md +++ b/packages/adapter-nextjs/CHANGELOG.md @@ -3,6 +3,32 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.2.19](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/adapter-nextjs@1.2.18...@aws-amplify/adapter-nextjs@1.2.19) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/adapter-nextjs + +## [1.2.18](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/adapter-nextjs@1.2.17...@aws-amplify/adapter-nextjs@1.2.18) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/adapter-nextjs + +## [1.2.17](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/adapter-nextjs@1.2.16...@aws-amplify/adapter-nextjs@1.2.17) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/adapter-nextjs + +## [1.2.16](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/adapter-nextjs@1.2.15...@aws-amplify/adapter-nextjs@1.2.16) (2024-09-03) + +### Bug Fixes + +- **adapter-nextjs:** duplicate response Set-Cookie headers in pages router ([#13765](https://github.com/aws-amplify/amplify-js/issues/13765)) ([3fedf63](https://github.com/aws-amplify/amplify-js/commit/3fedf6347823611ef5e28554911cf65c1419fce5)) + +## [1.2.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/adapter-nextjs@1.2.14...@aws-amplify/adapter-nextjs@1.2.15) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/adapter-nextjs + +## [1.2.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/adapter-nextjs@1.2.13...@aws-amplify/adapter-nextjs@1.2.14) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/adapter-nextjs + ## [1.2.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/adapter-nextjs@1.2.12...@aws-amplify/adapter-nextjs@1.2.13) (2024-08-15) **Note:** Version bump only for package @aws-amplify/adapter-nextjs diff --git a/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts b/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts index e27b4243511..a42ec085e9c 100644 --- a/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts +++ b/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts @@ -412,6 +412,41 @@ describe('createCookieStorageAdapterFromNextServerContext', () => { 'key3=;Expires=Thu, 01 Jan 1970 00:00:00 GMT', ]); }); + + it('does not add duplicate cookies when the cookies are defined in the response Set-Cookie headers', () => { + const mockExistingSetCookieValues = [ + 'CognitoIdentityServiceProvider.1234.accessToken=1234;Path=/', + 'CognitoIdentityServiceProvider.1234.refreshToken=1234;Path=/', + 'CognitoIdentityServiceProvider.1234.identityId=;Expires=Thu, 01 Jan 1970 00:00:00 GMT', + ]; + + const request = new IncomingMessage(new Socket()); + const response = new ServerResponse(request); + const appendHeaderSpy = jest.spyOn(response, 'appendHeader'); + const getHeaderSpy = jest.spyOn(response, 'getHeader'); + + Object.defineProperty(request, 'cookies', { + get() { + return {}; + }, + }); + + getHeaderSpy.mockReturnValue(mockExistingSetCookieValues); + + const result = createCookieStorageAdapterFromNextServerContext({ + request: request as any, + response, + }); + + result.set('CognitoIdentityServiceProvider.1234.accessToken', '5678'); + expect(appendHeaderSpy).not.toHaveBeenCalled(); + + result.set('CognitoIdentityServiceProvider.1234.refreshToken', '5678'); + expect(appendHeaderSpy).not.toHaveBeenCalled(); + + result.delete('CognitoIdentityServiceProvider.1234.identityId'); + expect(appendHeaderSpy).not.toHaveBeenCalled(); + }); }); it('should throw error when no cookie storage adapter is created from the context', () => { diff --git a/packages/adapter-nextjs/package.json b/packages/adapter-nextjs/package.json index fda15ce00f9..ca7c63c084d 100644 --- a/packages/adapter-nextjs/package.json +++ b/packages/adapter-nextjs/package.json @@ -1,7 +1,7 @@ { "author": "Amazon Web Services", "name": "@aws-amplify/adapter-nextjs", - "version": "1.2.13", + "version": "1.2.19", "description": "The adapter for the supporting of using Amplify APIs in Next.js.", "peerDependencies": { "aws-amplify": "^6.0.7", @@ -16,7 +16,7 @@ "@types/node": "^20.3.1", "@types/react": "^18.2.13", "@types/react-dom": "^18.2.6", - "aws-amplify": "6.5.1", + "aws-amplify": "6.6.2", "jest-fetch-mock": "3.0.3", "next": ">= 13.5.0 < 15.0.0", "typescript": "5.0.2" diff --git a/packages/adapter-nextjs/src/utils/createCookieStorageAdapterFromNextServerContext.ts b/packages/adapter-nextjs/src/utils/createCookieStorageAdapterFromNextServerContext.ts index 843235b7288..e3f99cbf96c 100644 --- a/packages/adapter-nextjs/src/utils/createCookieStorageAdapterFromNextServerContext.ts +++ b/packages/adapter-nextjs/src/utils/createCookieStorageAdapterFromNextServerContext.ts @@ -171,20 +171,44 @@ const createCookieStorageAdapterFromGetServerSidePropsContext = ( return allCookies; }, set(name, value, options) { + const encodedName = ensureEncodedForJSCookie(name); + + const existingValues = getExistingSetCookieValues( + response.getHeader('Set-Cookie'), + ); + + // if the cookies have already been set, we don't need to set them again. + if ( + existingValues.findIndex( + cookieValue => + cookieValue.startsWith(`${encodedName}=`) && + !cookieValue.startsWith(`${encodedName}=;`), + ) > -1 + ) { + return; + } + response.appendHeader( 'Set-Cookie', - `${ensureEncodedForJSCookie(name)}=${value};${ + `${encodedName}=${value};${ options ? serializeSetCookieOptions(options) : '' }`, ); }, delete(name) { - response.appendHeader( - 'Set-Cookie', - `${ensureEncodedForJSCookie( - name, - )}=;Expires=${DATE_IN_THE_PAST.toUTCString()}`, + const encodedName = ensureEncodedForJSCookie(name); + const setCookieValue = `${encodedName}=;Expires=${DATE_IN_THE_PAST.toUTCString()}`; + const existingValues = getExistingSetCookieValues( + response.getHeader('Set-Cookie'), ); + + // if the value for cookie deletion is already in the Set-Cookie header, we + // don't need to add the deletion value again. + if (existingValues.includes(setCookieValue)) { + return; + } + + response.appendHeader('Set-Cookie', setCookieValue); }, }; }; @@ -250,3 +274,8 @@ const serializeSetCookieOptions = ( // we are not using those chars in the auth keys. const ensureEncodedForJSCookie = (name: string): string => encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent); + +const getExistingSetCookieValues = ( + values: number | string | string[] | undefined, +): string[] => + values === undefined ? [] : Array.isArray(values) ? values : [String(values)]; diff --git a/packages/analytics/CHANGELOG.md b/packages/analytics/CHANGELOG.md index 548488213f2..158c642f74f 100644 --- a/packages/analytics/CHANGELOG.md +++ b/packages/analytics/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [7.0.49](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@7.0.48...@aws-amplify/analytics@7.0.49) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/analytics + +## [7.0.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@7.0.47...@aws-amplify/analytics@7.0.48) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/analytics + +## [7.0.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@7.0.46...@aws-amplify/analytics@7.0.47) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/analytics + +## [7.0.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@7.0.45...@aws-amplify/analytics@7.0.46) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/analytics + +## [7.0.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@7.0.44...@aws-amplify/analytics@7.0.45) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/analytics + +## [7.0.44](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@7.0.43...@aws-amplify/analytics@7.0.44) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/analytics + ## [7.0.43](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/analytics@7.0.42...@aws-amplify/analytics@7.0.43) (2024-08-15) **Note:** Version bump only for package @aws-amplify/analytics diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 4f18a70955d..36044ebe240 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/analytics", - "version": "7.0.43", + "version": "7.0.49", "description": "Analytics category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -103,8 +103,8 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", - "@aws-amplify/react-native": "1.1.4", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/react-native": "1.1.5", "@aws-sdk/types": "3.398.0", "typescript": "5.0.2" } diff --git a/packages/api-graphql/CHANGELOG.md b/packages/api-graphql/CHANGELOG.md index 8d4f758aff9..227ea1276da 100644 --- a/packages/api-graphql/CHANGELOG.md +++ b/packages/api-graphql/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.3.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@4.3.1...@aws-amplify/api-graphql@4.3.2) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/api-graphql + +## [4.3.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@4.3.0...@aws-amplify/api-graphql@4.3.1) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/api-graphql + +# [4.3.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@4.2.1...@aws-amplify/api-graphql@4.3.0) (2024-09-04) + +### Features + +- **api-graphql:** pass authToken via subprotocol ([#13727](https://github.com/aws-amplify/amplify-js/issues/13727)) ([ced891c](https://github.com/aws-amplify/amplify-js/commit/ced891c2e4f6b0f1fdeaf44ab80cae9d585b6d15)) + +## [4.2.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@4.2.0...@aws-amplify/api-graphql@4.2.1) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/api-graphql + +# [4.2.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@4.1.15...@aws-amplify/api-graphql@4.2.0) (2024-08-26) + +### Features + +- **api-graphql:** AppSync realtime - include custom headers as query string params ([#13735](https://github.com/aws-amplify/amplify-js/issues/13735)) ([5647497](https://github.com/aws-amplify/amplify-js/commit/56474971f45821d5049f9e8bc7ecbfc7810ea093)) + +## [4.1.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@4.1.14...@aws-amplify/api-graphql@4.1.15) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/api-graphql + ## [4.1.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-graphql@4.1.13...@aws-amplify/api-graphql@4.1.14) (2024-08-15) **Note:** Version bump only for package @aws-amplify/api-graphql diff --git a/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts b/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts index 29563594a30..d8456f5b373 100644 --- a/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts +++ b/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts @@ -245,8 +245,8 @@ describe('AWSAppSyncRealTimeProvider', () => { expect(newSocketSpy).toHaveBeenNthCalledWith( 1, - 'ws://localhost:8080/realtime?header=&payload=e30=', - 'graphql-ws', + 'ws://localhost:8080/realtime', + ['graphql-ws', 'header-'], ); }); @@ -271,8 +271,8 @@ describe('AWSAppSyncRealTimeProvider', () => { expect(newSocketSpy).toHaveBeenNthCalledWith( 1, - 'wss://localhost:8080/realtime?header=&payload=e30=', - 'graphql-ws', + 'wss://localhost:8080/realtime', + ['graphql-ws', 'header-'], ); }); @@ -298,8 +298,84 @@ describe('AWSAppSyncRealTimeProvider', () => { expect(newSocketSpy).toHaveBeenNthCalledWith( 1, - 'wss://testaccounturl123456789123.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=&payload=e30=', - 'graphql-ws', + 'wss://testaccounturl123456789123.appsync-realtime-api.us-east-1.amazonaws.com/graphql', + ['graphql-ws', 'header-'], + ); + }); + + test('subscription generates expected auth token', async () => { + expect.assertions(1); + + const newSocketSpy = jest + .spyOn(provider, 'getNewWebSocket') + .mockImplementation(() => { + fakeWebSocketInterface.newWebSocket(); + return fakeWebSocketInterface.webSocket; + }); + + provider + .subscribe({ + appSyncGraphqlEndpoint: + 'https://testaccounturl123456789123.appsync-api.us-east-1.amazonaws.com/graphql', + // using custom auth instead of apiKey, because the latter inserts a timestamp header => expected value changes + authenticationType: 'lambda', + additionalHeaders: { + Authorization: 'my-custom-auth-token', + }, + }) + .subscribe({ error: () => {} }); + + // Wait for the socket to be initialize + await fakeWebSocketInterface.readyForUse; + + /* + Regular base64 encoding of auth header {"Authorization":"my-custom-auth-token","host":"testaccounturl123456789123.appsync-api.us-east-1.amazonaws.com"} + Is: `eyJBdXRob3JpemF0aW9uIjoibXktY3VzdG9tLWF1dGgtdG9rZW4iLCJob3N0IjoidGVzdGFjY291bnR1cmwxMjM0NTY3ODkxMjMuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20ifQ==` + (note `==` at the end of the string) + base64url encoding is expected to drop padding chars `=` + */ + + expect(newSocketSpy).toHaveBeenNthCalledWith( + 1, + 'wss://testaccounturl123456789123.appsync-realtime-api.us-east-1.amazonaws.com/graphql', + [ + 'graphql-ws', + 'header-eyJBdXRob3JpemF0aW9uIjoibXktY3VzdG9tLWF1dGgtdG9rZW4iLCJob3N0IjoidGVzdGFjY291bnR1cmwxMjM0NTY3ODkxMjMuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20ifQ', + ], + ); + }); + + test('subscription generates expected auth token - custom domain', async () => { + expect.assertions(1); + + const newSocketSpy = jest + .spyOn(provider, 'getNewWebSocket') + .mockImplementation(() => { + fakeWebSocketInterface.newWebSocket(); + return fakeWebSocketInterface.webSocket; + }); + + provider + .subscribe({ + appSyncGraphqlEndpoint: 'https://unit-test.testurl.com', + // using custom auth instead of apiKey, because the latter inserts a timestamp header => expected value changes + authenticationType: 'lambda', + additionalHeaders: { + Authorization: 'my-custom-auth-token', + }, + }) + .subscribe({ error: () => {} }); + + // Wait for the socket to be initialize + await fakeWebSocketInterface.readyForUse; + + expect(newSocketSpy).toHaveBeenNthCalledWith( + 1, + 'wss://unit-test.testurl.com/realtime', + [ + 'graphql-ws', + 'header-eyJBdXRob3JpemF0aW9uIjoibXktY3VzdG9tLWF1dGgtdG9rZW4iLCJob3N0IjoidW5pdC10ZXN0LnRlc3R1cmwuY29tIn0', + ], ); }); diff --git a/packages/api-graphql/__tests__/GraphQLAPI.test.ts b/packages/api-graphql/__tests__/GraphQLAPI.test.ts index 43779fee5d6..dd88a7e056b 100644 --- a/packages/api-graphql/__tests__/GraphQLAPI.test.ts +++ b/packages/api-graphql/__tests__/GraphQLAPI.test.ts @@ -1558,4 +1558,60 @@ describe('API test', () => { ); }); }); + + test('request level custom headers are applied to query string', async () => { + Amplify.configure({ + API: { + GraphQL: { + defaultAuthMode: 'lambda', + endpoint: + 'https://testaccounturl123456789123.appsync-api.us-east-1.amazonaws.com/graphql', + region: 'local-host-h4x', + }, + }, + }); + + let done: Function; + const mockedFnHasBeenCalled = new Promise(res => (done = res)); + + const spyon_appsync_realtime = jest + .spyOn( + AWSAppSyncRealTimeProvider.prototype as any, + '_initializeRetryableHandshake', + ) + .mockImplementation( + jest.fn(() => { + done(); // resolve promise when called + }) as any, + ); + + const query = /* GraphQL */ ` + subscription SubscribeToEventComments { + subscribeToEventComments { + eventId + } + } + `; + + const resolvedUrl = + 'wss://testaccounturl123456789123.appsync-realtime-api.us-east-1.amazonaws.com/graphql?x-amz-user-agent=aws-amplify%2F6.4.0+api%2F1+framework%2F2&ex-machina=is+a+good+movie'; + + ( + client.graphql( + { query }, + { + 'x-amz-user-agent': 'aws-amplify/6.4.0 api/1 framework/2', + 'ex-machina': 'is a good movie', + // This should NOT get included in the querystring + Authorization: 'abc12345', + }, + ) as unknown as Observable + ).subscribe(); + + await mockedFnHasBeenCalled; + + expect(spyon_appsync_realtime).toHaveBeenCalledTimes(1); + const subscribeOptions = spyon_appsync_realtime.mock.calls[0][0]; + expect(subscribeOptions).toBe(resolvedUrl); + }); }); diff --git a/packages/api-graphql/__tests__/internals/generateClient.test.ts b/packages/api-graphql/__tests__/internals/generateClient.test.ts index c5104997df1..94ba7bcafe4 100644 --- a/packages/api-graphql/__tests__/internals/generateClient.test.ts +++ b/packages/api-graphql/__tests__/internals/generateClient.test.ts @@ -3,7 +3,7 @@ import { Amplify, AmplifyClassV6 } from '@aws-amplify/core'; import { generateClient } from '../../src/internals'; import configFixture from '../fixtures/modeled/amplifyconfiguration'; import { Schema } from '../fixtures/modeled/schema'; -import { from } from 'rxjs'; +import { Observable, from } from 'rxjs'; import { normalizePostGraphqlCalls, expectSubWithHeaders, @@ -11,6 +11,7 @@ import { expectSubWithlibraryConfigHeaders, mockApiResponse, } from '../utils/index'; +import { AWSAppSyncRealTimeProvider } from '../../src/Providers/AWSAppSyncRealTimeProvider'; const serverManagedFields = { id: 'some-id', @@ -332,6 +333,30 @@ describe('generateClient', () => { expect(normalizePostGraphqlCalls(spy)).toMatchSnapshot(); }); + test('with custom client headers - graphql', async () => { + const headers = { + 'client-header': 'should exist', + }; + + const client = generateClient({ + amplify: Amplify, + headers, + }); + + await client.graphql({ + query: /* GraphQL */ ` + query listPosts { + id + } + `, + }); + + const receivedArgs = normalizePostGraphqlCalls(spy)[0][1]; + const receivedHeaders = receivedArgs.options.headers; + + expect(receivedHeaders).toEqual(expect.objectContaining(headers)); + }); + test('with custom client header functions', async () => { const client = generateClient({ amplify: Amplify, @@ -495,6 +520,39 @@ describe('generateClient', () => { }); }); + test('with client-level custom headers', done => { + const customHeaders = { + 'subscription-header': 'should-exist', + }; + + const client = generateClient({ + amplify: Amplify, + headers: customHeaders, + }); + + const spy = jest.fn(() => from([graphqlMessage])); + (raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy }; + + client.models.Note.onCreate({ + filter: graphqlVariables.filter, + }).subscribe({ + next(value) { + expectSubWithHeaders( + spy, + 'onCreateNote', + graphqlVariables, + customHeaders, + ); + expect(value).toEqual(expect.objectContaining(noteToSend)); + done(); + }, + error(error) { + expect(error).toBeUndefined(); + done('bad news!'); + }, + }); + }); + test('with a custom header function', done => { const customHeaders = { 'subscription-header-function': 'should-return-this-header', diff --git a/packages/api-graphql/package.json b/packages/api-graphql/package.json index e8dd4c108e5..cc1c3061b6b 100644 --- a/packages/api-graphql/package.json +++ b/packages/api-graphql/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/api-graphql", - "version": "4.1.14", + "version": "4.3.2", "description": "Api-graphql category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -84,9 +84,9 @@ "server" ], "dependencies": { - "@aws-amplify/api-rest": "4.0.43", - "@aws-amplify/core": "6.3.10", - "@aws-amplify/data-schema": "^1.0.0", + "@aws-amplify/api-rest": "4.0.49", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/data-schema": "^1.5.0", "@aws-sdk/types": "3.387.0", "graphql": "15.8.0", "rxjs": "^7.8.1", diff --git a/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts b/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts index 37cafbf719e..61a1f6149bc 100644 --- a/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts +++ b/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts @@ -11,6 +11,7 @@ import { import { signRequest } from '@aws-amplify/core/internals/aws-client-utils'; import { AmplifyUrl, + AmplifyUrlSearchParams, CustomUserAgentDetails, DocumentType, GraphQLAuthMode, @@ -181,7 +182,7 @@ export class AWSAppSyncRealTimeProvider { this.reconnectionMonitor.close(); } - getNewWebSocket(url: string, protocol: string) { + getNewWebSocket(url: string, protocol: string[]) { return new WebSocket(url, protocol); } @@ -712,6 +713,87 @@ export class AWSAppSyncRealTimeProvider { } } + /** + * Strips out `Authorization` header if present + */ + private _extractNonAuthHeaders( + headers?: AWSAppSyncRealTimeProviderOptions['additionalCustomHeaders'], + ): Record { + if (!headers) { + return {}; + } + + if ('Authorization' in headers) { + const { Authorization: _, ...nonAuthHeaders } = headers; + + return nonAuthHeaders; + } + + return headers; + } + + /** + * + * @param headers - http headers + * @returns uri-encoded query parameters derived from custom headers + */ + private _queryParamsFromCustomHeaders( + headers?: AWSAppSyncRealTimeProviderOptions['additionalCustomHeaders'], + ): URLSearchParams { + const nonAuthHeaders = this._extractNonAuthHeaders(headers); + + const params = new AmplifyUrlSearchParams(); + + Object.entries(nonAuthHeaders).forEach(([k, v]) => { + params.append(k, v); + }); + + return params; + } + + /** + * Normalizes AppSync realtime endpoint URL + * + * @param appSyncGraphqlEndpoint - AppSync endpointUri from config + * @param urlParams - URLSearchParams + * @returns fully resolved string realtime endpoint URL + */ + private _realtimeUrlWithQueryString( + appSyncGraphqlEndpoint: string | undefined, + urlParams: URLSearchParams, + ): string { + const protocol = 'wss://'; + + let realtimeEndpoint = appSyncGraphqlEndpoint ?? ''; + + if (this.isCustomDomain(realtimeEndpoint)) { + realtimeEndpoint = realtimeEndpoint.concat(customDomainPath); + } else { + realtimeEndpoint = realtimeEndpoint + .replace('appsync-api', 'appsync-realtime-api') + .replace('gogi-beta', 'grt-beta'); + } + + realtimeEndpoint = realtimeEndpoint + .replace('https://', protocol) + .replace('http://', protocol); + + const realtimeEndpointUrl = new AmplifyUrl(realtimeEndpoint); + + // preserves any query params a customer might manually set in the configuration + const existingParams = new AmplifyUrlSearchParams( + realtimeEndpointUrl.search, + ); + + for (const [k, v] of urlParams.entries()) { + existingParams.append(k, v); + } + + realtimeEndpointUrl.search = existingParams.toString(); + + return realtimeEndpointUrl.toString(); + } + private _initializeWebSocketConnection({ appSyncGraphqlEndpoint, authenticationType, @@ -745,30 +827,27 @@ export class AWSAppSyncRealTimeProvider { }); const headerString = authHeader ? JSON.stringify(authHeader) : ''; - const headerQs = base64Encoder.convert(headerString); - - const payloadQs = base64Encoder.convert(payloadString); - - let discoverableEndpoint = appSyncGraphqlEndpoint ?? ''; + // base64url-encoded string + const encodedHeader = base64Encoder.convert(headerString, { + urlSafe: true, + skipPadding: true, + }); - if (this.isCustomDomain(discoverableEndpoint)) { - discoverableEndpoint = - discoverableEndpoint.concat(customDomainPath); - } else { - discoverableEndpoint = discoverableEndpoint - .replace('appsync-api', 'appsync-realtime-api') - .replace('gogi-beta', 'grt-beta'); - } + const authTokenSubprotocol = `header-${encodedHeader}`; - // Creating websocket url with required query strings - const protocol = 'wss://'; - discoverableEndpoint = discoverableEndpoint - .replace('https://', protocol) - .replace('http://', protocol); + const queryParams = this._queryParamsFromCustomHeaders( + additionalCustomHeaders, + ); - const awsRealTimeUrl = `${discoverableEndpoint}?header=${headerQs}&payload=${payloadQs}`; + const awsRealTimeUrl = this._realtimeUrlWithQueryString( + appSyncGraphqlEndpoint, + queryParams, + ); - await this._initializeRetryableHandshake(awsRealTimeUrl); + await this._initializeRetryableHandshake( + awsRealTimeUrl, + authTokenSubprotocol, + ); this.promiseArray.forEach(({ res }) => { logger.debug('Notifying connection successful'); @@ -795,23 +874,37 @@ export class AWSAppSyncRealTimeProvider { }); } - private async _initializeRetryableHandshake(awsRealTimeUrl: string) { + private async _initializeRetryableHandshake( + awsRealTimeUrl: string, + subprotocol: string, + ) { logger.debug(`Initializaling retryable Handshake`); await jitteredExponentialRetry( this._initializeHandshake.bind(this), - [awsRealTimeUrl], + [awsRealTimeUrl, subprotocol], MAX_DELAY_MS, ); } - private async _initializeHandshake(awsRealTimeUrl: string) { + /** + * + * @param subprotocol - + */ + private async _initializeHandshake( + awsRealTimeUrl: string, + subprotocol: string, + ) { logger.debug(`Initializing handshake ${awsRealTimeUrl}`); // Because connecting the socket is async, is waiting until connection is open // Step 1: connect websocket try { await (() => { return new Promise((resolve, reject) => { - const newSocket = this.getNewWebSocket(awsRealTimeUrl, 'graphql-ws'); + const newSocket = this.getNewWebSocket(awsRealTimeUrl, [ + 'graphql-ws', + subprotocol, + ]); + newSocket.onerror = () => { logger.debug(`WebSocket connection error`); }; diff --git a/packages/api-graphql/src/internals/v6.ts b/packages/api-graphql/src/internals/v6.ts index 0cdcf483927..c5d362908c8 100644 --- a/packages/api-graphql/src/internals/v6.ts +++ b/packages/api-graphql/src/internals/v6.ts @@ -106,6 +106,7 @@ export function graphql< const internals = getInternals(this as any); options.authMode = options.authMode || internals.authMode; options.authToken = options.authToken || internals.authToken; + const headers = additionalHeaders || internals.headers; /** * The correctness of these typings depends on correct string branding or overrides. @@ -116,7 +117,7 @@ export function graphql< // TODO: move V6Client back into this package? internals.amplify as any, options, - additionalHeaders, + headers, ); return result as any; diff --git a/packages/api-rest/CHANGELOG.md b/packages/api-rest/CHANGELOG.md index 25425526f94..56840cb1fe0 100644 --- a/packages/api-rest/CHANGELOG.md +++ b/packages/api-rest/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [4.0.49](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@4.0.48...@aws-amplify/api-rest@4.0.49) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/api-rest + +## [4.0.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@4.0.47...@aws-amplify/api-rest@4.0.48) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/api-rest + +## [4.0.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@4.0.46...@aws-amplify/api-rest@4.0.47) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/api-rest + +## [4.0.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@4.0.45...@aws-amplify/api-rest@4.0.46) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/api-rest + +## [4.0.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@4.0.44...@aws-amplify/api-rest@4.0.45) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/api-rest + +## [4.0.44](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@4.0.43...@aws-amplify/api-rest@4.0.44) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/api-rest + ## [4.0.43](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api-rest@4.0.42...@aws-amplify/api-rest@4.0.43) (2024-08-15) **Note:** Version bump only for package @aws-amplify/api-rest diff --git a/packages/api-rest/__tests__/apis/common/internalPost.test.ts b/packages/api-rest/__tests__/apis/common/internalPost.test.ts index acfd9ae4530..f4887e9d2ad 100644 --- a/packages/api-rest/__tests__/apis/common/internalPost.test.ts +++ b/packages/api-rest/__tests__/apis/common/internalPost.test.ts @@ -91,6 +91,47 @@ describe('internal post', () => { expect.objectContaining({ region: 'us-west-2', service: 'lambda' }), ); }); + + it('should call authenticatedHandler for appsync-api service with default signing name', async () => { + const appsyncApiEndpoint = new URL( + 'https://123.appsync-api.us-west-2.amazonaws.com/graphql', + ); + await post(mockAmplifyInstance, { + url: appsyncApiEndpoint, + options: { + signingServiceInfo: { region: 'us-east-1' }, + }, + }); + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( + { + url: appsyncApiEndpoint, + method: 'POST', + headers: {}, + }, + expect.objectContaining({ region: 'us-east-1', service: 'appsync' }), + ); + }); + + it('should call authenticatedHandler for appsync-api with specified service from signingServiceInfo', async () => { + const appsyncApiEndpoint = new URL( + 'https://123.appsync-api.us-west-2.amazonaws.com/graphql', + ); + await post(mockAmplifyInstance, { + url: appsyncApiEndpoint, + options: { + signingServiceInfo: { service: 'appsync', region: 'us-east-1' }, + }, + }); + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( + { + url: appsyncApiEndpoint, + method: 'POST', + headers: {}, + }, + expect.objectContaining({ region: 'us-east-1', service: 'appsync' }), + ); + }); + it('should call authenticatedHandler with empty signingServiceInfo', async () => { await post(mockAmplifyInstance, { url: apiGatewayUrl, diff --git a/packages/api-rest/__tests__/utils/isIamAuthApplicable.test.ts b/packages/api-rest/__tests__/utils/isIamAuthApplicable.test.ts new file mode 100644 index 00000000000..a75733f738a --- /dev/null +++ b/packages/api-rest/__tests__/utils/isIamAuthApplicable.test.ts @@ -0,0 +1,74 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { HttpRequest } from '@aws-amplify/core/internals/aws-client-utils'; + +import { + isIamAuthApplicableForGraphQL, + isIamAuthApplicableForRest, +} from '../../src/utils/isIamAuthApplicable'; + +describe('iamAuthApplicable', () => { + const url = new URL('https://url'); + const baseRequest: HttpRequest = { + headers: {}, + url, + method: 'put', + }; + + describe('iamAuthApplicableForGraphQL', () => { + it('should return true if there is no authorization header, no x-api-key header, and signingServiceInfo is provided', () => { + const signingServiceInfo = {}; + expect( + isIamAuthApplicableForGraphQL(baseRequest, signingServiceInfo), + ).toBe(true); + }); + + it('should return false if there is an authorization header', () => { + const request = { + ...baseRequest, + headers: { authorization: 'SampleToken' }, + }; + const signingServiceInfo = {}; + expect(isIamAuthApplicableForGraphQL(request, signingServiceInfo)).toBe( + false, + ); + }); + + it('should return false if there is an x-api-key header', () => { + const request = { ...baseRequest, headers: { 'x-api-key': 'key' } }; + const signingServiceInfo = {}; + expect(isIamAuthApplicableForGraphQL(request, signingServiceInfo)).toBe( + false, + ); + }); + + it('should return false if signingServiceInfo is not provided', () => { + expect(isIamAuthApplicableForGraphQL(baseRequest)).toBe(false); + }); + }); + + describe('iamAuthApplicableForPublic', () => { + it('should return true if there is no authorization header and signingServiceInfo is provided', () => { + const signingServiceInfo = {}; + expect(isIamAuthApplicableForRest(baseRequest, signingServiceInfo)).toBe( + true, + ); + }); + + it('should return false if there is an authorization header', () => { + const request = { + ...baseRequest, + headers: { authorization: 'SampleToken' }, + }; + const signingServiceInfo = {}; + expect(isIamAuthApplicableForRest(request, signingServiceInfo)).toBe( + false, + ); + }); + + it('should return false if signingServiceInfo is not provided', () => { + expect(isIamAuthApplicableForRest(baseRequest)).toBe(false); + }); + }); +}); diff --git a/packages/api-rest/package.json b/packages/api-rest/package.json index db16386e5e0..d64fbd67fea 100644 --- a/packages/api-rest/package.json +++ b/packages/api-rest/package.json @@ -1,7 +1,7 @@ { "name": "@aws-amplify/api-rest", "private": false, - "version": "4.0.43", + "version": "4.0.49", "description": "Api-rest category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -87,8 +87,8 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", - "@aws-amplify/react-native": "1.1.4", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/react-native": "1.1.5", "typescript": "5.0.2" }, "size-limit": [ diff --git a/packages/api-rest/src/apis/common/handler.ts b/packages/api-rest/src/apis/common/handler.ts index 9ae021e4e4e..d17a8c72b6a 100644 --- a/packages/api-rest/src/apis/common/handler.ts +++ b/packages/api-rest/src/apis/common/handler.ts @@ -20,7 +20,7 @@ import { parseSigningInfo, } from '../../utils'; import { resolveHeaders } from '../../utils/resolveHeaders'; -import { RestApiResponse } from '../../types'; +import { RestApiResponse, SigningServiceInfo } from '../../types'; type HandlerOptions = Omit & { body?: DocumentType | FormData; @@ -28,11 +28,6 @@ type HandlerOptions = Omit & { withCredentials?: boolean; }; -interface SigningServiceInfo { - service?: string; - region?: string; -} - /** * Make REST API call with best-effort IAM auth. * @param amplify Amplify instance to to resolve credentials and tokens. Should use different instance in client-side @@ -40,12 +35,17 @@ interface SigningServiceInfo { * @param options Options accepted from public API options when calling the handlers. * @param signingServiceInfo Internal-only options enable IAM auth as well as to to overwrite the IAM signing service * and region. If specified, and NONE of API Key header or Auth header is present, IAM auth will be used. + * @param iamAuthApplicable Callback function that is used to determine if IAM Auth should be used or not. * * @internal */ export const transferHandler = async ( amplify: AmplifyClassV6, options: HandlerOptions & { abortSignal: AbortSignal }, + iamAuthApplicable: ( + { headers }: HttpRequest, + signingServiceInfo?: SigningServiceInfo, + ) => boolean, signingServiceInfo?: SigningServiceInfo, ): Promise => { const { url, method, headers, body, withCredentials, abortSignal } = options; @@ -69,6 +69,7 @@ export const transferHandler = async ( }; const isIamAuthApplicable = iamAuthApplicable(request, signingServiceInfo); + let response: RestApiResponse; const credentials = await resolveCredentials(amplify); if (isIamAuthApplicable && credentials) { @@ -97,11 +98,6 @@ export const transferHandler = async ( }; }; -const iamAuthApplicable = ( - { headers }: HttpRequest, - signingServiceInfo?: SigningServiceInfo, -) => !headers.authorization && !headers['x-api-key'] && !!signingServiceInfo; - const resolveCredentials = async ( amplify: AmplifyClassV6, ): Promise => { diff --git a/packages/api-rest/src/apis/common/internalPost.ts b/packages/api-rest/src/apis/common/internalPost.ts index 835c3581d56..6dabea22072 100644 --- a/packages/api-rest/src/apis/common/internalPost.ts +++ b/packages/api-rest/src/apis/common/internalPost.ts @@ -6,6 +6,7 @@ import { AmplifyClassV6 } from '@aws-amplify/core'; import { InternalPostInput, RestApiResponse } from '../../types'; import { createCancellableOperation } from '../../utils'; import { CanceledError } from '../../errors'; +import { isIamAuthApplicableForGraphQL } from '../../utils/isIamAuthApplicable'; import { transferHandler } from './handler'; @@ -46,7 +47,7 @@ const cancelTokenMap = new WeakMap, AbortController>(); * @param postInput.abortController The abort controller used to cancel the POST request * @returns a {@link RestApiResponse} * - * @throws an {@link Error} with `Network error` as the `message` when the external resource is unreachable due to one + * @throws an {@link AmplifyError} with `Network Error` as the `message` when the external resource is unreachable due to one * of the following reasons: * 1. no network connection * 2. CORS error @@ -66,6 +67,7 @@ export const post = ( ...options, abortSignal: controller.signal, }, + isIamAuthApplicableForGraphQL, options?.signingServiceInfo, ); diff --git a/packages/api-rest/src/apis/common/publicApis.ts b/packages/api-rest/src/apis/common/publicApis.ts index 6a132a6b277..8c7a58cb6fc 100644 --- a/packages/api-rest/src/apis/common/publicApis.ts +++ b/packages/api-rest/src/apis/common/publicApis.ts @@ -25,6 +25,7 @@ import { parseSigningInfo, resolveApiUrl, } from '../../utils'; +import { isIamAuthApplicableForRest } from '../../utils/isIamAuthApplicable'; import { transferHandler } from './handler'; @@ -71,6 +72,7 @@ const publicHandler = ( headers, abortSignal, }, + isIamAuthApplicableForRest, signingServiceInfo, ); }); diff --git a/packages/api-rest/src/errors/CanceledError.ts b/packages/api-rest/src/errors/CanceledError.ts index ce4082212e0..67278d62a7c 100644 --- a/packages/api-rest/src/errors/CanceledError.ts +++ b/packages/api-rest/src/errors/CanceledError.ts @@ -29,6 +29,9 @@ export class CanceledError extends RestApiError { * * @note This function works **ONLY** for errors thrown by REST API. For GraphQL APIs, use `client.isCancelError(error)` * instead. `client` is generated from `generateClient()` API from `aws-amplify/api`. + * + * @param {unknown} error The unknown exception to be checked. + * @returns - A boolean indicating if the error was from an upload cancellation */ export const isCancelError = (error: unknown): error is CanceledError => !!error && error instanceof CanceledError; diff --git a/packages/api-rest/src/types/index.ts b/packages/api-rest/src/types/index.ts index f2f3c214b17..7e0ecb61e7c 100644 --- a/packages/api-rest/src/types/index.ts +++ b/packages/api-rest/src/types/index.ts @@ -112,3 +112,12 @@ export interface InternalPostInput { */ abortController?: AbortController; } + +/** + * Type for signingServiceInfo which enable IAM auth as well as overwrite the IAM signing info. + * @internal + */ +export interface SigningServiceInfo { + service?: string; + region?: string; +} diff --git a/packages/api-rest/src/utils/isIamAuthApplicable.ts b/packages/api-rest/src/utils/isIamAuthApplicable.ts new file mode 100644 index 00000000000..ba48e7be3de --- /dev/null +++ b/packages/api-rest/src/utils/isIamAuthApplicable.ts @@ -0,0 +1,44 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { HttpRequest } from '@aws-amplify/core/internals/aws-client-utils'; + +import { SigningServiceInfo } from '../types'; + +/** + * Determines if IAM authentication should be applied for a GraphQL request. + * + * This function checks the `headers` of the HTTP request to determine if IAM authentication + * is applicable. IAM authentication is considered applicable if there is no `authorization` + * header, no `x-api-key` header, and `signingServiceInfo` is provided. + * + * @param request - The HTTP request object containing headers. + * @param signingServiceInfo - Optional signing service information, + * including service and region. + * @returns A boolean `true` if IAM authentication should be applied. + * + * @internal + */ +export const isIamAuthApplicableForGraphQL = ( + { headers }: HttpRequest, + signingServiceInfo?: SigningServiceInfo, +) => !headers.authorization && !headers['x-api-key'] && !!signingServiceInfo; + +/** + * Determines if IAM authentication should be applied for a REST request. + * + * This function checks the `headers` of the HTTP request to determine if IAM authentication + * is applicable. IAM authentication is considered applicable if there is no `authorization` + * header and `signingServiceInfo` is provided. + * + * @param request - The HTTP request object containing headers. + * @param signingServiceInfo - Optional signing service information, + * including service and region. + * @returns A boolean `true` if IAM authentication should be applied. + * + * @internal + */ +export const isIamAuthApplicableForRest = ( + { headers }: HttpRequest, + signingServiceInfo?: SigningServiceInfo, +) => !headers.authorization && !!signingServiceInfo; diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 1747e039922..dc714d5e55c 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.0.51](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@6.0.50...@aws-amplify/api@6.0.51) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/api + +## [6.0.50](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@6.0.49...@aws-amplify/api@6.0.50) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/api + +## [6.0.49](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@6.0.48...@aws-amplify/api@6.0.49) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/api + +## [6.0.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@6.0.47...@aws-amplify/api@6.0.48) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/api + +## [6.0.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@6.0.46...@aws-amplify/api@6.0.47) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/api + +## [6.0.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@6.0.45...@aws-amplify/api@6.0.46) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/api + ## [6.0.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/api@6.0.44...@aws-amplify/api@6.0.45) (2024-08-15) **Note:** Version bump only for package @aws-amplify/api diff --git a/packages/api/package.json b/packages/api/package.json index de745c1df01..b1b3253549b 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/api", - "version": "6.0.45", + "version": "6.0.51", "description": "Api category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -79,8 +79,8 @@ "server" ], "dependencies": { - "@aws-amplify/api-graphql": "4.1.14", - "@aws-amplify/api-rest": "4.0.43", + "@aws-amplify/api-graphql": "4.3.2", + "@aws-amplify/api-rest": "4.0.49", "tslib": "^2.5.0" } } diff --git a/packages/api/src/API.ts b/packages/api/src/API.ts index db0559e4477..8aee0fc3334 100644 --- a/packages/api/src/API.ts +++ b/packages/api/src/API.ts @@ -6,6 +6,9 @@ import { Amplify } from '@aws-amplify/core'; /** * Generates an API client that can work with models or raw GraphQL + * + * @returns {@link V6Client} + * @throws {@link Error} - Throws error when client cannot be generated due to configuration issues. */ export function generateClient = never>( options: CommonPublicClientOptions = {}, diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index ad1962463d9..7abc1e1a0a5 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.4.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@6.4.1...@aws-amplify/auth@6.4.2) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/auth + +## [6.4.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@6.4.0...@aws-amplify/auth@6.4.1) (2024-09-16) + +### Bug Fixes + +- **auth:** custom `userPoolEndpoint` cannot be applied on the server-side ([#13739](https://github.com/aws-amplify/amplify-js/issues/13739)) ([a76b594](https://github.com/aws-amplify/amplify-js/commit/a76b594562430a85fd37f00bb2788959f7a69d6a)) + +# [6.4.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@6.3.17...@aws-amplify/auth@6.4.0) (2024-09-04) + +### Features + +- **auth:** HostedUI oidc signout ([#13512](https://github.com/aws-amplify/amplify-js/issues/13512)) ([e8fb997](https://github.com/aws-amplify/amplify-js/commit/e8fb9973f8e3e3490619416a778ec1460cafaf9a)), closes [#13712](https://github.com/aws-amplify/amplify-js/issues/13712) [#13736](https://github.com/aws-amplify/amplify-js/issues/13736) + +## [6.3.17](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@6.3.16...@aws-amplify/auth@6.3.17) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/auth + +## [6.3.16](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@6.3.15...@aws-amplify/auth@6.3.16) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/auth + +## [6.3.15](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@6.3.14...@aws-amplify/auth@6.3.15) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/auth + ## [6.3.14](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/auth@6.3.13...@aws-amplify/auth@6.3.14) (2024-08-15) **Note:** Version bump only for package @aws-amplify/auth diff --git a/packages/auth/__tests__/foundation/cognitoUserPoolEndpointResolver.test.ts b/packages/auth/__tests__/foundation/cognitoUserPoolEndpointResolver.test.ts new file mode 100644 index 00000000000..04bbff52546 --- /dev/null +++ b/packages/auth/__tests__/foundation/cognitoUserPoolEndpointResolver.test.ts @@ -0,0 +1,16 @@ +import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; + +import { cognitoUserPoolEndpointResolver } from '../../src/foundation/cognitoUserPoolEndpointResolver'; +import { COGNITO_IDP_SERVICE_NAME } from '../../src/foundation/constants'; + +describe('cognitoUserPoolEndpointResolver', () => { + it('should return the Cognito User Pool endpoint', () => { + const region = 'us-west-2'; + const { url } = cognitoUserPoolEndpointResolver({ region }); + + expect(url instanceof AmplifyUrl).toBe(true); + expect(url.toString()).toEqual( + `https://${COGNITO_IDP_SERVICE_NAME}.us-west-2.amazonaws.com/`, + ); + }); +}); diff --git a/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/index.test.ts b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/index.test.ts new file mode 100644 index 00000000000..9138718bb58 --- /dev/null +++ b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/index.test.ts @@ -0,0 +1,41 @@ +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import * as serviceClients from '../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from '../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/constants'; + +import { mockServiceClientAPIConfig } from './testUtils/data'; + +jest.mock('@aws-amplify/core/internals/aws-client-utils/composers', () => ({ + ...jest.requireActual( + '@aws-amplify/core/internals/aws-client-utils/composers', + ), + composeServiceApi: jest.fn(), +})); + +export const mockComposeServiceApi = jest.mocked(composeServiceApi); + +describe('service clients', () => { + const serviceClientFactories = Object.keys(serviceClients); + + afterEach(() => { + mockComposeServiceApi.mockClear(); + }); + + test.each(serviceClientFactories)( + 'factory `%s` should invoke composeServiceApi with expected parameters', + serviceClientFactory => { + // eslint-disable-next-line import/namespace + serviceClients[serviceClientFactory](mockServiceClientAPIConfig); + + expect(mockComposeServiceApi).toHaveBeenCalledWith( + expect.any(Function), + expect.any(Function), + expect.any(Function), + expect.objectContaining({ + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...mockServiceClientAPIConfig, + }), + ); + }, + ); +}); diff --git a/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/cognitoUserPoolTransferHandler.test.ts b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/cognitoUserPoolTransferHandler.test.ts new file mode 100644 index 00000000000..8f5bbc8c7f9 --- /dev/null +++ b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/cognitoUserPoolTransferHandler.test.ts @@ -0,0 +1,43 @@ +import { unauthenticatedHandler } from '@aws-amplify/core/internals/aws-client-utils'; +import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { cognitoUserPoolTransferHandler } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler'; + +jest.mock('@aws-amplify/core/internals/aws-client-utils/composers'); +jest.mock('@aws-amplify/core/internals/aws-client-utils'); + +const mockComposeTransferHandler = jest.mocked(composeTransferHandler); +const mockUnauthenticatedHandler = jest.mocked(unauthenticatedHandler); + +describe('cognitoUserPoolTransferHandler', () => { + beforeAll(() => { + // need to make sure cognitoUserPoolTransferHandler is imported and used in + // the scope of the test + const _ = cognitoUserPoolTransferHandler; + }); + + it('adds the disableCacheMiddlewareFactory at module loading', () => { + expect(mockComposeTransferHandler).toHaveBeenCalledTimes(1); + + const [core, middleware] = mockComposeTransferHandler.mock.calls[0]; + + expect(core).toStrictEqual(mockUnauthenticatedHandler); + expect(middleware).toHaveLength(1); + + const disableCacheMiddlewareFactory = middleware[0] as any; + const disableCacheMiddlewarePendingNext = disableCacheMiddlewareFactory(); + + const mockNext = jest.fn(); + const disableCacheMiddleware = disableCacheMiddlewarePendingNext(mockNext); + const mockRequest = { + headers: {}, + }; + + disableCacheMiddleware(mockRequest); + + expect(mockNext).toHaveBeenCalledWith(mockRequest); + expect(mockRequest.headers).toEqual({ + 'cache-control': 'no-store', + }); + }); +}); diff --git a/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer.test.ts b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer.test.ts new file mode 100644 index 00000000000..80f9ddfedb7 --- /dev/null +++ b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer.test.ts @@ -0,0 +1,55 @@ +import { + HttpResponse, + parseJsonError, +} from '@aws-amplify/core/internals/aws-client-utils'; + +import { createEmptyResponseDeserializer } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer'; +import { AuthError } from '../../../../../../../src/errors/AuthError'; + +jest.mock('@aws-amplify/core/internals/aws-client-utils'); + +const mockParseJsonError = jest.mocked(parseJsonError); + +describe('createEmptyResponseDeserializer created response deserializer', () => { + const deserializer = createEmptyResponseDeserializer(); + + it('returns undefined for 2xx status code', async () => { + const response: HttpResponse = { + statusCode: 200, + body: { + json: () => Promise.resolve({}), + blob: () => Promise.resolve(new Blob()), + text: () => Promise.resolve(''), + }, + headers: {}, + }; + const output = await deserializer(response); + + expect(output).toBeUndefined(); + }); + + it('throws AuthError for 4xx status code', async () => { + const expectedErrorName = 'TestError'; + const expectedErrorMessage = 'TestErrorMessage'; + const expectedError = new Error(expectedErrorMessage); + expectedError.name = expectedErrorName; + + mockParseJsonError.mockReturnValueOnce(expectedError as any); + const response: HttpResponse = { + statusCode: 400, + body: { + json: () => Promise.resolve({}), + blob: () => Promise.resolve(new Blob()), + text: () => Promise.resolve(''), + }, + headers: {}, + }; + + expect(deserializer(response as any)).rejects.toThrow( + new AuthError({ + name: expectedErrorName, + message: expectedErrorMessage, + }), + ); + }); +}); diff --git a/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.test.ts b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.test.ts new file mode 100644 index 00000000000..18bc775caca --- /dev/null +++ b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.test.ts @@ -0,0 +1,59 @@ +import { + HttpResponse, + parseJsonBody, + parseJsonError, +} from '@aws-amplify/core/internals/aws-client-utils'; + +import { createUserPoolDeserializer } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer'; +import { AuthError } from '../../../../../../../src/errors/AuthError'; + +jest.mock('@aws-amplify/core/internals/aws-client-utils'); + +const mockParseJsonBody = jest.mocked(parseJsonBody); +const mockParseJsonError = jest.mocked(parseJsonError); + +describe('buildUserPoolDeserializer created response deserializer', () => { + const deserializer = createUserPoolDeserializer(); + + it('returns body for 2xx status code', async () => { + const expectedBody = { test: 'test' }; + mockParseJsonBody.mockResolvedValueOnce(expectedBody); + const response: HttpResponse = { + statusCode: 200, + body: { + json: () => Promise.resolve({}), + blob: () => Promise.resolve(new Blob()), + text: () => Promise.resolve(''), + }, + headers: {}, + }; + const output = await deserializer(response); + + expect(output).toStrictEqual(expectedBody); + }); + + it('throws AuthError for 4xx status code', async () => { + const expectedErrorName = 'TestError'; + const expectedErrorMessage = 'TestErrorMessage'; + const expectedError = new Error(expectedErrorMessage); + expectedError.name = expectedErrorName; + + mockParseJsonError.mockReturnValueOnce(expectedError as any); + const response: HttpResponse = { + statusCode: 400, + body: { + json: () => Promise.resolve({}), + blob: () => Promise.resolve(new Blob()), + text: () => Promise.resolve(''), + }, + headers: {}, + }; + + expect(deserializer(response as any)).rejects.toThrow( + new AuthError({ + name: expectedErrorName, + message: expectedErrorMessage, + }), + ); + }); +}); diff --git a/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer.test.ts b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer.test.ts new file mode 100644 index 00000000000..70d9a054a42 --- /dev/null +++ b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer.test.ts @@ -0,0 +1,27 @@ +import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; + +import { createUserPoolSerializer } from '../../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer'; + +describe('createUserPoolSerializer created request serializer', () => { + test.each(['SignUp', 'InitiateAuth', 'RevokeToken'] as const)( + `it serializes requests from operation %s`, + operation => { + const testInput = { testBody: 'testBody' }; + const testEndpoint = { + url: new AmplifyUrl('http://test.com'), + }; + const serializer = createUserPoolSerializer(operation); + const result = serializer(testInput, testEndpoint); + + expect(result).toEqual({ + method: 'POST', + url: testEndpoint.url, + headers: { + 'content-type': 'application/x-amz-json-1.1', + 'x-amz-target': `AWSCognitoIdentityProviderService.${operation}`, + }, + body: JSON.stringify(testInput), + }); + }, + ); +}); diff --git a/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/testUtils/data.ts b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/testUtils/data.ts new file mode 100644 index 00000000000..33a9a3d5534 --- /dev/null +++ b/packages/auth/__tests__/foundation/factories/serviceClients/cognitoIdentityProvider/testUtils/data.ts @@ -0,0 +1,7 @@ +import { ServiceClientFactoryInput } from '../../../../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; + +export const mockServiceClientAPIConfig: ServiceClientFactoryInput = { + endpointResolver: jest.fn() as jest.MockedFunction< + ServiceClientFactoryInput['endpointResolver'] + >, +}; diff --git a/packages/auth/__tests__/foundation/parsers/regionParsers.test.ts b/packages/auth/__tests__/foundation/parsers/regionParsers.test.ts new file mode 100644 index 00000000000..978ac7d8029 --- /dev/null +++ b/packages/auth/__tests__/foundation/parsers/regionParsers.test.ts @@ -0,0 +1,47 @@ +import { AuthError } from '../../../src/errors/AuthError'; +import { + getRegionFromIdentityPoolId, + getRegionFromUserPoolId, +} from '../../../src/foundation/parsers/regionParsers'; + +describe('getRegionFromIdentityPoolId()', () => { + it('returns the region from the identity pool id', () => { + const identityPoolId = 'us-west-2:12345678-1234-1234-1234-123456789012'; + const region = getRegionFromIdentityPoolId(identityPoolId); + expect(region).toEqual('us-west-2'); + }); + + test.each([undefined, 'invalid-id-123'])( + `throws an error when the identity pool id is invalid as %p`, + identityPoolId => { + expect(() => getRegionFromIdentityPoolId(identityPoolId)).toThrow( + new AuthError({ + name: 'InvalidIdentityPoolIdException', + message: 'Invalid identity pool id provided.', + recoverySuggestion: + 'Make sure a valid identityPoolId is given in the config.', + }), + ); + }, + ); +}); + +describe('getRegionFromUserPoolId()', () => { + it('should return the region from the user pool id', () => { + const userPoolId = 'us-west-2_12345678'; + const region = getRegionFromUserPoolId(userPoolId); + expect(region).toEqual('us-west-2'); + }); + + test.each([undefined, 'invalid-id-123'])( + `throws an error when the user pool id is invalid as %p`, + userPoolId => { + expect(() => getRegionFromUserPoolId(userPoolId)).toThrow( + new AuthError({ + name: 'InvalidUserPoolId', + message: 'Invalid user pool id provided.', + }), + ); + }, + ); +}); diff --git a/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts b/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts index 783fc2e9699..d787c2cdedf 100644 --- a/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts +++ b/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts @@ -8,13 +8,10 @@ import { signUp, } from '../../../src/providers/cognito'; import { autoSignIn } from '../../../src/providers/cognito/apis/autoSignIn'; -import * as signUpClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { - RespondToAuthChallengeCommandOutput, - SignUpCommandOutput, -} from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import * as initiateAuthHelpers from '../../../src/providers/cognito/utils/signInHelpers'; import { AuthError } from '../../../src/errors/AuthError'; +import { createSignUpClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { RespondToAuthChallengeCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; @@ -23,6 +20,9 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), isBrowser: jest.fn(() => false), })); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); const authConfig = { Cognito: { @@ -35,27 +35,30 @@ Amplify.configure({ Auth: authConfig, }); describe('Auto sign-in API Happy Path Cases:', () => { - let signUpSpy; - let handleUserSRPAuthflowSpy; + let handleUserSRPAuthFlowSpy: jest.SpyInstance; + + const mockSignUp = jest.fn(); + const mockCreateSignUpClient = jest.mocked(createSignUpClient); + const { user1 } = authAPITestParams; beforeEach(async () => { - signUpSpy = jest - .spyOn(signUpClient, 'signUp') - .mockImplementationOnce( - async () => ({ UserConfirmed: true }) as SignUpCommandOutput, - ); + mockSignUp.mockResolvedValueOnce({ UserConfirmed: true }); + mockCreateSignUpClient.mockReturnValueOnce(mockSignUp); - handleUserSRPAuthflowSpy = jest + handleUserSRPAuthFlowSpy = jest .spyOn(initiateAuthHelpers, 'handleUserSRPAuthFlow') .mockImplementationOnce( async (): Promise => authAPITestParams.RespondToAuthChallengeCommandOutput, ); }); + afterEach(() => { - signUpSpy.mockClear(); - handleUserSRPAuthflowSpy.mockClear(); + mockSignUp.mockClear(); + mockCreateSignUpClient.mockClear(); + handleUserSRPAuthFlowSpy.mockClear(); }); + test('signUp should enable autoSignIn and return COMPLETE_AUTO_SIGN_IN step', async () => { const resp = await signUp({ username: user1.username, @@ -71,13 +74,13 @@ describe('Auto sign-in API Happy Path Cases:', () => { signUpStep: 'COMPLETE_AUTO_SIGN_IN', }, }); - expect(signUpSpy).toHaveBeenCalledTimes(1); + expect(mockSignUp).toHaveBeenCalledTimes(1); }); test('Auto sign-in should resolve to a signIn output', async () => { const signInOutput = await autoSignIn(); expect(signInOutput).toEqual(authAPITestParams.signInResult()); - expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); + expect(handleUserSRPAuthFlowSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts b/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts index df8167e5030..d07979c5d9c 100644 --- a/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts @@ -7,7 +7,8 @@ import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { confirmResetPassword } from '../../../src/providers/cognito'; import { ConfirmForgotPasswordException } from '../../../src/providers/cognito/types/errors'; -import { confirmForgotPassword } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createConfirmForgotPasswordClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { getMockError } from './testUtils/data'; @@ -22,12 +23,19 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('confirmResetPassword', () => { // assert mocks - const mockConfirmForgotPassword = confirmForgotPassword as jest.Mock; + const mockConfirmForgotPassword = jest.fn(); + const mockCreateConfirmResetPasswordClient = jest.mocked( + createConfirmForgotPasswordClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -37,10 +45,15 @@ describe('confirmResetPassword', () => { mockConfirmForgotPassword.mockResolvedValue( authAPITestParams.confirmResetPasswordHttpCallResult, ); + mockCreateConfirmResetPasswordClient.mockReturnValueOnce( + mockConfirmForgotPassword, + ); }); afterEach(() => { mockConfirmForgotPassword.mockReset(); + mockCreateConfirmResetPasswordClient.mockClear(); + mockCreateCognitoUserPoolEndpointResolver.mockClear(); }); it('should call the confirmForgotPassword and return void', async () => { @@ -50,6 +63,26 @@ describe('confirmResetPassword', () => { expect(mockConfirmForgotPassword).toHaveBeenCalled(); }); + it('invokes createCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + + await confirmResetPassword(authAPITestParams.confirmResetPasswordRequest); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should contain clientMetadata from request', async () => { await confirmResetPassword({ username: 'username', diff --git a/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts b/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts index 0f20b1703f3..a2d561799d9 100644 --- a/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts @@ -4,8 +4,8 @@ import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { confirmSignIn } from '../../../src/providers/cognito/apis/confirmSignIn'; import { RespondToAuthChallengeException } from '../../../src/providers/cognito/types/errors'; -import { respondToAuthChallenge } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { signInStore } from '../../../src/providers/cognito/utils/signInStore'; +import { createRespondToAuthChallengeClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; import { getMockError } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -15,10 +15,11 @@ jest.mock('@aws-amplify/core', () => ({ ...(jest.createMockFromModule('@aws-amplify/core') as object), Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock('../../../src/providers/cognito/utils/signInStore'); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); -jest.mock('../../../src/providers/cognito/utils/signInStore'); +jest.mock('../../../src/providers/cognito/factories'); describe('confirmSignIn API error path cases:', () => { const challengeName = 'SELECT_MFA_TYPE'; @@ -26,7 +27,10 @@ describe('confirmSignIn API error path cases:', () => { const { username } = authAPITestParams.user1; // assert mocks const mockStoreGetState = signInStore.getState as jest.Mock; - const mockRespondToAuthChallenge = respondToAuthChallenge as jest.Mock; + const mockRespondToAuthChallenge = jest.fn(); + const mockCreateRespondToAuthChallengeClient = jest.mocked( + createRespondToAuthChallengeClient, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -37,8 +41,15 @@ describe('confirmSignIn API error path cases:', () => { }); }); + beforeEach(() => { + mockCreateRespondToAuthChallengeClient.mockReturnValueOnce( + mockRespondToAuthChallenge, + ); + }); + afterEach(() => { mockRespondToAuthChallenge.mockReset(); + mockCreateRespondToAuthChallengeClient.mockClear(); }); it('confirmSignIn API should throw an error when challengeResponse is empty', async () => { diff --git a/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts b/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts index ddeb3c368fd..ddfcc9c2d8e 100644 --- a/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts @@ -9,16 +9,22 @@ import { signIn, } from '../../../src/providers/cognito/'; import * as signInHelpers from '../../../src/providers/cognito/utils/signInHelpers'; -import { RespondToAuthChallengeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { cognitoUserPoolsTokenProvider, tokenOrchestrator, } from '../../../src/providers/cognito/tokenProvider'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { + createInitiateAuthClient, + createRespondToAuthChallengeClient, +} from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { RespondToAuthChallengeCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; jest.mock('../../../src/providers/cognito/apis/getCurrentUser'); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); const authConfig = { Cognito: { @@ -35,6 +41,9 @@ describe('confirmSignIn API happy path cases', () => { let handleChallengeNameSpy: jest.SpyInstance; const { username, password } = authAPITestParams.user1; + const mockInitiateAuth = jest.fn(); + const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); + beforeEach(async () => { cognitoUserPoolsTokenProvider.setAuthConfig(authConfig); @@ -56,10 +65,14 @@ describe('confirmSignIn API happy path cases', () => { $metadata: {}, }), ); + + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); }); afterEach(() => { handleChallengeNameSpy.mockClear(); + mockInitiateAuth.mockClear(); + mockCreateInitiateAuthClient.mockClear(); }); afterAll(() => { @@ -234,20 +247,16 @@ describe('confirmSignIn API happy path cases', () => { const mockedUserSub = '1111-2222-3333-4444'; const activeSignInSession = '1234234232'; const activeChallengeName = 'SMS_MFA'; - const initiateAuthSpy = jest - .spyOn(clients, 'initiateAuth') - .mockImplementationOnce( - async (): Promise => ({ - ChallengeName: activeChallengeName, - Session: activeSignInSession, - $metadata: {}, - ChallengeParameters: { - USER_ID_FOR_SRP: mockedUserSub, - CODE_DELIVERY_DELIVERY_MEDIUM: 'SMS', - CODE_DELIVERY_DESTINATION: '*******9878', - }, - }), - ); + mockInitiateAuth.mockResolvedValueOnce({ + ChallengeName: activeChallengeName, + Session: activeSignInSession, + $metadata: {}, + ChallengeParameters: { + USER_ID_FOR_SRP: mockedUserSub, + CODE_DELIVERY_DELIVERY_MEDIUM: 'SMS', + CODE_DELIVERY_DESTINATION: '*******9878', + }, + }); await signIn({ username, password, @@ -260,6 +269,7 @@ describe('confirmSignIn API happy path cases', () => { options: authAPITestParams.configWithClientMetadata, }); const options = authAPITestParams.configWithClientMetadata; + expect(handleChallengeNameSpy).toHaveBeenCalledWith( mockedUserSub, activeChallengeName, @@ -270,14 +280,17 @@ describe('confirmSignIn API happy path cases', () => { authAPITestParams.configWithClientMetadata.clientMetadata, options, ); - initiateAuthSpy.mockClear(); }); }); describe('Cognito ASF', () => { - let respondToAuthChallengeSpy: jest.SpyInstance; let handleUserSRPAuthFlowSpy: jest.SpyInstance; + const mockRespondToAuthChallenge = jest.fn(); + const mockCreateRespondToAuthChallengeClient = jest.mocked( + createRespondToAuthChallengeClient, + ); + const { username } = authAPITestParams.user1; const { password } = authAPITestParams.user1; beforeEach(() => { @@ -292,30 +305,28 @@ describe('Cognito ASF', () => { }, }; - respondToAuthChallengeSpy = jest - .spyOn(clients, 'respondToAuthChallenge') - .mockImplementation( - async (): Promise => { - return { - Session: '1234234232', - $metadata: {}, - ChallengeName: undefined, - ChallengeParameters: {}, - AuthenticationResult: { - AccessToken: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', - ExpiresIn: 1000, - IdToken: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', - RefreshToken: 'qwersfsafsfssfasf', - }, - }; - }, - ); + mockRespondToAuthChallenge.mockResolvedValueOnce({ + Session: '1234234232', + $metadata: {}, + ChallengeName: undefined, + ChallengeParameters: {}, + AuthenticationResult: { + AccessToken: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', + ExpiresIn: 1000, + IdToken: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', + RefreshToken: 'qwersfsafsfssfasf', + }, + }); + mockCreateRespondToAuthChallengeClient.mockReturnValueOnce( + mockRespondToAuthChallenge, + ); }); afterEach(() => { - respondToAuthChallengeSpy.mockClear(); + mockRespondToAuthChallenge.mockClear(); + mockCreateRespondToAuthChallengeClient.mockClear(); handleUserSRPAuthFlowSpy.mockClear(); (window as any).AmazonCognitoAdvancedSecurityData = undefined; }); @@ -342,15 +353,11 @@ describe('Cognito ASF', () => { expect(result.isSignedIn).toBe(false); expect(result.nextStep.signInStep).toBe('CONFIRM_SIGN_IN_WITH_SMS_CODE'); - try { - await confirmSignIn({ - challengeResponse: '777', - }); - } catch (err) { - console.log(err); - } - - expect(respondToAuthChallengeSpy).toHaveBeenCalledWith( + await confirmSignIn({ + challengeResponse: '777', + }); + + expect(mockRespondToAuthChallenge).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), @@ -384,15 +391,11 @@ describe('Cognito ASF', () => { expect(result.nextStep.signInStep).toBe( 'CONTINUE_SIGN_IN_WITH_MFA_SELECTION', ); - try { - await confirmSignIn({ - challengeResponse: 'SMS', - }); - } catch (err) { - console.log(err); - } - - expect(respondToAuthChallengeSpy).toHaveBeenCalledWith( + await confirmSignIn({ + challengeResponse: 'SMS', + }); + + expect(mockRespondToAuthChallenge).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), @@ -427,15 +430,11 @@ describe('Cognito ASF', () => { expect(result.isSignedIn).toBe(false); expect(result.nextStep.signInStep).toBe('CONFIRM_SIGN_IN_WITH_TOTP_CODE'); - try { - await confirmSignIn({ - challengeResponse: '123456', - }); - } catch (err) { - console.log(err); - } - - expect(respondToAuthChallengeSpy).toHaveBeenCalledWith( + await confirmSignIn({ + challengeResponse: '123456', + }); + + expect(mockRespondToAuthChallenge).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), @@ -472,15 +471,11 @@ describe('Cognito ASF', () => { expect(result.nextStep.signInStep).toBe( 'CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED', ); - try { - await confirmSignIn({ - challengeResponse: 'password', - }); - } catch (err) { - console.log(err); - } - - expect(respondToAuthChallengeSpy).toHaveBeenCalledWith( + await confirmSignIn({ + challengeResponse: 'password', + }); + + expect(mockRespondToAuthChallenge).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), @@ -516,15 +511,11 @@ describe('Cognito ASF', () => { expect(result.nextStep.signInStep).toBe( 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE', ); - try { - await confirmSignIn({ - challengeResponse: 'secret-answer', - }); - } catch (err) { - console.log(err); - } - - expect(respondToAuthChallengeSpy).toHaveBeenCalledWith( + await confirmSignIn({ + challengeResponse: 'secret-answer', + }); + + expect(mockRespondToAuthChallenge).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts b/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts index e6528e4b1ed..3523f9495aa 100644 --- a/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts @@ -4,16 +4,22 @@ import { Amplify } from '@aws-amplify/core'; import { confirmSignUp } from '../../../src/providers/cognito'; -import { confirmSignUp as providerConfirmSignUp } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { AuthError } from '../../../src/errors/AuthError'; import { ConfirmSignUpException } from '../../../src/providers/cognito/types/errors'; -import { ConfirmSignUpCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; +import { createConfirmSignUpClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; +import { ConfirmSignUpCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { getMockError } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); +jest.mock('../../../src/providers/cognito/factories'); + jest.mock('@aws-amplify/core', () => ({ ...(jest.createMockFromModule('@aws-amplify/core') as object), Amplify: { getConfig: jest.fn(() => ({})) }, @@ -22,15 +28,16 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), isBrowser: jest.fn(() => false), })); -jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', -); describe('confirmSignUp', () => { const { user1 } = authAPITestParams; const confirmationCode = '123456'; // assert mocks - const mockConfirmSignUp = providerConfirmSignUp as jest.Mock; + const mockConfirmSignUp = jest.fn(); + const mockCreateConfirmSignUpClient = jest.mocked(createConfirmSignUpClient); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -38,10 +45,13 @@ describe('confirmSignUp', () => { beforeEach(() => { mockConfirmSignUp.mockResolvedValue({} as ConfirmSignUpCommandOutput); + mockCreateConfirmSignUpClient.mockReturnValueOnce(mockConfirmSignUp); }); afterEach(() => { mockConfirmSignUp.mockReset(); + mockCreateConfirmSignUpClient.mockClear(); + mockCreateCognitoUserPoolEndpointResolver.mockClear(); }); it('should call confirmSignUp and return a SignUpResult', async () => { @@ -68,6 +78,29 @@ describe('confirmSignUp', () => { expect(mockConfirmSignUp).toHaveBeenCalledTimes(1); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + + await confirmSignUp({ + username: user1.username, + confirmationCode, + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should contain force alias creation', async () => { await confirmSignUp({ username: user1.username, diff --git a/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts b/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts index 3c7961d125a..56608241897 100644 --- a/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts @@ -7,8 +7,9 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { confirmUserAttribute } from '../../../src/providers/cognito'; import { VerifyUserAttributeException } from '../../../src/providers/cognito/types/errors'; -import { verifyUserAttribute } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; +import { createVerifyUserAttributeClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -22,14 +23,21 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('confirmUserAttribute', () => { const confirmationCode = '123456'; // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockVerifyUserAttribute = verifyUserAttribute as jest.Mock; + const mockVerifyUserAttribute = jest.fn(); + const mockCreateVerifyUserAttributeClient = jest.mocked( + createVerifyUserAttributeClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -40,11 +48,15 @@ describe('confirmUserAttribute', () => { beforeEach(() => { mockVerifyUserAttribute.mockResolvedValue({ $metadata: {} }); + mockCreateVerifyUserAttributeClient.mockReturnValueOnce( + mockVerifyUserAttribute, + ); }); afterEach(() => { mockVerifyUserAttribute.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateVerifyUserAttributeClient.mockClear(); }); it('should call the service', async () => { @@ -63,6 +75,28 @@ describe('confirmUserAttribute', () => { ); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await confirmUserAttribute({ + userAttributeKey: 'email', + confirmationCode, + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when confirmationCode is not defined', async () => { try { await confirmUserAttribute({ diff --git a/packages/auth/__tests__/providers/cognito/credentialsProvider/IdentityIdStore.test.ts b/packages/auth/__tests__/providers/cognito/credentialsProvider/IdentityIdStore.test.ts new file mode 100644 index 00000000000..94475367ec3 --- /dev/null +++ b/packages/auth/__tests__/providers/cognito/credentialsProvider/IdentityIdStore.test.ts @@ -0,0 +1,125 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { Identity, ResourcesConfig } from '@aws-amplify/core'; + +import { DefaultIdentityIdStore } from '../../../../src/providers/cognito/credentialsProvider/IdentityIdStore'; + +const mockKeyValueStorage = { + setItem: jest.fn(), + getItem: jest.fn(), + removeItem: jest.fn(), + clear: jest.fn(), +}; + +const validAuthConfig: ResourcesConfig = { + Auth: { + Cognito: { + userPoolId: 'us-east-1_test-id', + identityPoolId: 'us-east-1:test-id', + userPoolClientId: 'test-id', + allowGuestAccess: true, + }, + }, +}; +const validAuthKey = { + identityId: `com.amplify.Cognito.${ + validAuthConfig.Auth!.Cognito!.identityPoolId + }.identityId`, +}; +const validGuestIdentityId: Identity = { type: 'guest', id: 'guest-id' }; +const validPrimaryIdentityId: Identity = { type: 'primary', id: 'primary-id' }; + +const noIdentityPoolIdAuthConfig: ResourcesConfig = { + Auth: { + Cognito: { + userPoolId: 'us-east-1_test-id', + userPoolClientId: 'test-id', + }, + }, +}; + +describe('DefaultIdentityIdStore', () => { + const defaultIdStore = new DefaultIdentityIdStore(mockKeyValueStorage); + beforeAll(() => { + defaultIdStore.setAuthConfig(validAuthConfig.Auth!); + }); + + afterEach(() => { + mockKeyValueStorage.setItem.mockClear(); + mockKeyValueStorage.getItem.mockClear(); + mockKeyValueStorage.removeItem.mockClear(); + mockKeyValueStorage.clear.mockClear(); + }); + + it('should set the Auth config required to form the storage keys', async () => { + expect(defaultIdStore._authKeys).toEqual(validAuthKey); + }); + + it('should store guest identityId in keyValueStorage', async () => { + defaultIdStore.storeIdentityId(validGuestIdentityId); + expect(mockKeyValueStorage.setItem).toHaveBeenCalledWith( + validAuthKey.identityId, + validGuestIdentityId.id, + ); + expect(defaultIdStore._primaryIdentityId).toBeUndefined(); + expect(defaultIdStore._hasGuestIdentityId).toBe(true); + }); + + it('should load guest identityId from keyValueStorage', async () => { + mockKeyValueStorage.getItem.mockReturnValue(validGuestIdentityId.id); + + expect(await defaultIdStore.loadIdentityId()).toEqual(validGuestIdentityId); + }); + + it('should store primary identityId in keyValueStorage', async () => { + defaultIdStore.storeIdentityId(validPrimaryIdentityId); + expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith( + validAuthKey.identityId, + ); + expect(defaultIdStore._primaryIdentityId).toEqual( + validPrimaryIdentityId.id, + ); + expect(defaultIdStore._hasGuestIdentityId).toBe(false); + }); + + it('should load primary identityId from keyValueStorage', async () => { + expect(await defaultIdStore.loadIdentityId()).toEqual( + validPrimaryIdentityId, + ); + }); + + it('should clear the cached identityId', async () => { + defaultIdStore.clearIdentityId(); + expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith( + validAuthKey.identityId, + ); + expect(defaultIdStore._primaryIdentityId).toBeUndefined(); + }); + + it('should throw when identityPoolId is not present while setting the auth config', async () => { + expect(() => { + defaultIdStore.setAuthConfig(noIdentityPoolIdAuthConfig.Auth!); + }).toThrow('Invalid identity pool id provided.'); + }); + + it('should return null when the underlying keyValueStorage method returns null', async () => { + mockKeyValueStorage.getItem.mockReturnValue(null); + expect(await defaultIdStore.loadIdentityId()).toBeNull(); + }); + + it('should return null when the underlying keyValueStorage method throws', async () => { + mockKeyValueStorage.getItem.mockRejectedValue(new Error('Error')); + expect(await defaultIdStore.loadIdentityId()).toBeNull(); + }); + + it('should not call keyValueStorage.removeItem when there is no guest identityId to clear', async () => { + const refreshIdentityIdStore = new DefaultIdentityIdStore( + mockKeyValueStorage, + ); + refreshIdentityIdStore.setAuthConfig(validAuthConfig.Auth!); + + refreshIdentityIdStore.storeIdentityId(validPrimaryIdentityId); + expect(mockKeyValueStorage.removeItem).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/auth/__tests__/providers/cognito/deleteUser.test.ts b/packages/auth/__tests__/providers/cognito/deleteUser.test.ts index ec1cf3a90d9..b56e9736e12 100644 --- a/packages/auth/__tests__/providers/cognito/deleteUser.test.ts +++ b/packages/auth/__tests__/providers/cognito/deleteUser.test.ts @@ -7,9 +7,10 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { deleteUser } from '../../../src/providers/cognito'; import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; -import { deleteUser as providerDeleteUser } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { DeleteUserException } from '../../../src/providers/cognito/types/errors'; import { signOut } from '../../../src/providers/cognito/apis/signOut'; +import { createDeleteUserClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -23,18 +24,23 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock('../../../src/providers/cognito/apis/signOut'); +jest.mock('../../../src/providers/cognito/tokenProvider'); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); -jest.mock('../../../src/providers/cognito/tokenProvider'); +jest.mock('../../../src/providers/cognito/factories'); describe('deleteUser', () => { // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockDeleteUser = providerDeleteUser as jest.Mock; + const mockDeleteUser = jest.fn(); + const mockCreateDeleteUserClient = jest.mocked(createDeleteUserClient); const mockSignOut = signOut as jest.Mock; const mockClearDeviceMetadata = tokenOrchestrator.clearDeviceMetadata as jest.Mock; + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -45,12 +51,14 @@ describe('deleteUser', () => { beforeEach(() => { mockDeleteUser.mockResolvedValue({ $metadata: {} }); + mockCreateDeleteUserClient.mockReturnValueOnce(mockDeleteUser); }); afterEach(() => { mockDeleteUser.mockReset(); mockClearDeviceMetadata.mockClear(); mockFetchAuthSession.mockClear(); + mockCreateDeleteUserClient.mockClear(); }); it('should delete user, sign out and clear device tokens', async () => { @@ -72,6 +80,25 @@ describe('deleteUser', () => { ); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await deleteUser(); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockDeleteUser.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts b/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts index 959592a5b87..c791b224fdb 100644 --- a/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts +++ b/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts @@ -7,7 +7,8 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { deleteUserAttributes } from '../../../src/providers/cognito'; import { DeleteUserAttributesException } from '../../../src/providers/cognito/types/errors'; -import { deleteUserAttributes as providerDeleteUserAttributes } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createDeleteUserAttributesClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -21,13 +22,20 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('deleteUserAttributes', () => { // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockDeleteUserAttributes = providerDeleteUserAttributes as jest.Mock; + const mockDeleteUserAttributes = jest.fn(); + const mockCreateDeleteUserAttributesClient = jest.mocked( + createDeleteUserAttributesClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -38,11 +46,15 @@ describe('deleteUserAttributes', () => { beforeEach(() => { mockDeleteUserAttributes.mockResolvedValue({ $metadata: {} }); + mockCreateDeleteUserAttributesClient.mockReturnValueOnce( + mockDeleteUserAttributes, + ); }); afterEach(() => { mockDeleteUserAttributes.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateDeleteUserAttributesClient.mockClear(); }); it('should delete user attributes', async () => { @@ -60,6 +72,27 @@ describe('deleteUserAttributes', () => { expect(mockDeleteUserAttributes).toHaveBeenCalledTimes(1); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await deleteUserAttributes({ + userAttributeKeys: ['given_name', 'address'], + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockDeleteUserAttributes.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/factories/createCognitoUserPoolEndpointResolver.test.ts b/packages/auth/__tests__/providers/cognito/factories/createCognitoUserPoolEndpointResolver.test.ts new file mode 100644 index 00000000000..1c499146921 --- /dev/null +++ b/packages/auth/__tests__/providers/cognito/factories/createCognitoUserPoolEndpointResolver.test.ts @@ -0,0 +1,55 @@ +import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; + +import { cognitoUserPoolEndpointResolver } from '../../../../src/foundation/cognitoUserPoolEndpointResolver'; +import { createCognitoUserPoolEndpointResolver } from '../../../../src/providers/cognito/factories/createCognitoUserPoolEndpointResolver'; + +jest.mock('../../../../src/foundation/cognitoUserPoolEndpointResolver'); + +const mockCognitoUserPoolEndpointResolver = jest.mocked( + cognitoUserPoolEndpointResolver, +); + +describe('createCognitoUserPoolEndpointResolver()', () => { + afterEach(() => { + mockCognitoUserPoolEndpointResolver.mockClear(); + }); + + describe('creating a resolver with overrideEndpoint as `undefined`', () => { + const resolver = createCognitoUserPoolEndpointResolver({ + endpointOverride: undefined, + }); + + it('invokes cognitoUserPoolEndpointResolver with the expected region', () => { + const expectedReturningUrl = { + url: new AmplifyUrl('https://cognito-idp.us-west-2.amazonaws.com/'), + }; + mockCognitoUserPoolEndpointResolver.mockReturnValueOnce( + expectedReturningUrl, + ); + + const expectedRegion = 'us-west-2'; + const { url } = resolver({ region: expectedRegion }); + + expect(mockCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + region: expectedRegion, + }); + expect(url).toStrictEqual(expectedReturningUrl.url); + }); + }); + + describe('creating a resolver with overrideEndpoint', () => { + const endpointOverride = 'https://cognito-idp.example.com'; + const resolver = createCognitoUserPoolEndpointResolver({ + endpointOverride, + }); + + it('returns the endpoint override', () => { + const expectedRegion = 'us-west-2'; + const { url } = resolver({ region: expectedRegion }); + expect(mockCognitoUserPoolEndpointResolver).not.toHaveBeenCalled(); + expect(url).toStrictEqual( + new AmplifyUrl('https://cognito-idp.example.com'), + ); + }); + }); +}); diff --git a/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts b/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts index 1e8a48ab84e..4cdb79a13bd 100644 --- a/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts +++ b/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts @@ -6,8 +6,9 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { fetchDevices } from '../../../src/providers/cognito'; -import { listDevices } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { ListDevicesException } from '../../../src/providers/cognito/types/errors'; +import { createListDevicesClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -21,8 +22,9 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('fetchDevices', () => { const dateEpoch = 1.696296885807e9; @@ -51,7 +53,11 @@ describe('fetchDevices', () => { }; // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockListDevices = listDevices as jest.Mock; + const mockListDevices = jest.fn(); + const mockCreateListDevicesClient = jest.mocked(createListDevicesClient); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -65,11 +71,13 @@ describe('fetchDevices', () => { Devices: [clientResponseDevice], $metadata: {}, }); + mockCreateListDevicesClient.mockReturnValueOnce(mockListDevices); }); afterEach(() => { mockListDevices.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateListDevicesClient.mockClear(); }); it('should fetch devices and parse client response correctly', async () => { @@ -84,6 +92,25 @@ describe('fetchDevices', () => { expect(mockListDevices).toHaveBeenCalledTimes(1); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await fetchDevices(); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockListDevices.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts b/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts index ed2517a358e..c4d8a7a9efa 100644 --- a/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts +++ b/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts @@ -4,10 +4,11 @@ import { Amplify, fetchAuthSession } from '@aws-amplify/core'; import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { getUser } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthError } from '../../../src/errors/AuthError'; import { fetchMFAPreference } from '../../../src/providers/cognito/apis/fetchMFAPreference'; import { GetUserException } from '../../../src/providers/cognito/types/errors'; +import { createGetUserClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -17,13 +18,18 @@ jest.mock('@aws-amplify/core', () => ({ Amplify: { getConfig: jest.fn(() => ({})) }, })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('fetchMFAPreference', () => { // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockGetUser = getUser as jest.Mock; + const mockGetUser = jest.fn(); + const mockCreateGetUserClient = jest.mocked(createGetUserClient); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -40,6 +46,7 @@ describe('fetchMFAPreference', () => { UserMFASettingList: ['SMS_MFA', 'SOFTWARE_TOKEN_MFA'], $metadata: {}, }); + mockCreateGetUserClient.mockReturnValueOnce(mockGetUser); }); afterEach(() => { @@ -62,6 +69,25 @@ describe('fetchMFAPreference', () => { ); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await fetchMFAPreference(); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockGetUser.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts b/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts index cff5ff01b64..87cf79e715d 100644 --- a/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts +++ b/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts @@ -4,10 +4,11 @@ import { Amplify } from '@aws-amplify/core'; import { decodeJWT, fetchAuthSession } from '@aws-amplify/core/internals/utils'; -import { getUser } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthError } from '../../../src/errors/AuthError'; import { GetUserException } from '../../../src/providers/cognito/types/errors'; import { fetchUserAttributes } from '../../../src/providers/cognito/apis/fetchUserAttributes'; +import { createGetUserClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -21,13 +22,18 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ fetchAuthSession: jest.fn(), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('fetchUserAttributes', () => { // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockGetUser = getUser as jest.Mock; + const mockGetUser = jest.fn(); + const mockCreateGetUserClient = jest.mocked(createGetUserClient); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -47,11 +53,13 @@ describe('fetchUserAttributes', () => { UserMFASettingList: ['SMS_MFA', 'SOFTWARE_TOKEN_MFA'], $metadata: {}, }); + mockCreateGetUserClient.mockReturnValueOnce(mockGetUser); }); afterEach(() => { mockGetUser.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateGetUserClient.mockClear(); }); it('should return the current user attributes into a map format', async () => { @@ -71,6 +79,25 @@ describe('fetchUserAttributes', () => { ); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await fetchUserAttributes(); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockGetUser.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts b/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts index 6371e2b41a8..cc0a2d37407 100644 --- a/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts +++ b/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts @@ -8,8 +8,9 @@ import { AuthError } from '../../../src/errors/AuthError'; import { DEVICE_METADATA_NOT_FOUND_EXCEPTION } from '../../../src/errors/constants'; import { forgetDevice } from '../../../src/providers/cognito'; import { ForgetDeviceException } from '../../../src/providers/cognito/types/errors'; -import { forgetDevice as providerForgetDevice } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; +import { createForgetDeviceClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -22,10 +23,11 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), isBrowser: jest.fn(() => false), })); +jest.mock('../../../src/providers/cognito/tokenProvider'); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); -jest.mock('../../../src/providers/cognito/tokenProvider'); +jest.mock('../../../src/providers/cognito/factories'); describe('fetchMFAPreference', () => { const mockDeviceMetadata = { @@ -35,11 +37,15 @@ describe('fetchMFAPreference', () => { }; // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockForgetDevice = providerForgetDevice as jest.Mock; + const mockForgetDevice = jest.fn(); + const mockCreateForgetDeviceClient = jest.mocked(createForgetDeviceClient); const mockClearDeviceMetadata = tokenOrchestrator.clearDeviceMetadata as jest.Mock; const mockGetDeviceMetadata = tokenOrchestrator.getDeviceMetadata as jest.Mock; + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -51,6 +57,7 @@ describe('fetchMFAPreference', () => { beforeEach(() => { mockForgetDevice.mockResolvedValue({ $metadata: {} }); mockGetDeviceMetadata.mockResolvedValue(mockDeviceMetadata); + mockCreateForgetDeviceClient.mockReturnValueOnce(mockForgetDevice); }); afterEach(() => { @@ -58,6 +65,7 @@ describe('fetchMFAPreference', () => { mockGetDeviceMetadata.mockReset(); mockFetchAuthSession.mockClear(); mockClearDeviceMetadata.mockClear(); + mockCreateForgetDeviceClient.mockClear(); }); it(`should forget 'external device' 'with' inputParams when tokenStore deviceMetadata 'present'`, async () => { @@ -74,6 +82,25 @@ describe('fetchMFAPreference', () => { expect(mockClearDeviceMetadata).not.toHaveBeenCalled(); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await forgetDevice({ device: { id: 'externalDeviceKey' } }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it(`should forget 'current device' 'with' inputParams when tokenStore deviceMetadata 'present'`, async () => { expect.assertions(3); await forgetDevice({ device: { id: mockDeviceMetadata.deviceKey } }); diff --git a/packages/auth/__tests__/providers/cognito/getNewDeviceMetadata.test.ts b/packages/auth/__tests__/providers/cognito/getNewDeviceMetadata.test.ts index cb600ce133e..6058fc363b7 100644 --- a/packages/auth/__tests__/providers/cognito/getNewDeviceMetadata.test.ts +++ b/packages/auth/__tests__/providers/cognito/getNewDeviceMetadata.test.ts @@ -5,11 +5,17 @@ import { Amplify } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { ConfirmDeviceException } from '../../../src/providers/cognito/types/errors'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { ConfirmDeviceCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { getNewDeviceMetatada } from '../../../src/providers/cognito/utils/signInHelpers'; +import { getNewDeviceMetadata } from '../../../src/providers/cognito/utils/signInHelpers'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; +import { createConfirmDeviceClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; + +jest.mock('../../../src/providers/cognito/factories'); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); const userPoolId = 'us-west-2_zzzzz'; + Amplify.configure({ Auth: { Cognito: { @@ -22,66 +28,95 @@ Amplify.configure({ const mockedAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, +); + describe('test getNewDeviceMetadata API', () => { + const mockConfirmDevice = jest.fn(); + const mockCreateConfirmDeviceClient = jest.mocked(createConfirmDeviceClient); + + beforeEach(() => { + mockCreateConfirmDeviceClient.mockReturnValueOnce(mockConfirmDevice); + }); + + afterEach(() => { + mockConfirmDevice.mockClear(); + mockCreateConfirmDeviceClient.mockClear(); + }); + test('getNewDeviceMetadata should call confirmDevice and return DeviceMetadata', async () => { - const confirmDeviceClientSpy = jest - .spyOn(clients, 'confirmDevice') - .mockImplementationOnce(async (): Promise => { - return { UserConfirmationNecessary: true, $metadata: {} }; - }); + mockConfirmDevice.mockResolvedValueOnce({ + UserConfirmationNecessary: true, + $metadata: {}, + }); + const mockedDeviceKey = 'mockedDeviceKey'; const mockedGroupDeviceKey = 'mockedGroupDeviceKey'; - const deviceMetadata = await getNewDeviceMetatada( + const deviceMetadata = await getNewDeviceMetadata({ userPoolId, - { + userPoolEndpoint: undefined, + newDeviceMetadata: { DeviceKey: mockedDeviceKey, DeviceGroupKey: mockedGroupDeviceKey, }, - mockedAccessToken, - ); + accessToken: mockedAccessToken, + }); expect(deviceMetadata?.deviceKey).toBe(mockedDeviceKey); expect(deviceMetadata?.deviceGroupKey).toBe(mockedGroupDeviceKey); - expect(confirmDeviceClientSpy).toHaveBeenCalledWith( + expect(mockConfirmDevice).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ AccessToken: mockedAccessToken, DeviceKey: mockedDeviceKey, }), ); - - confirmDeviceClientSpy.mockClear(); }); test('getNewDeviceMetadata should return undefined when ConfirmDevice throws an error', async () => { - const confirmDeviceClientSpy = jest - .spyOn(clients, 'confirmDevice') - .mockImplementationOnce(async (): Promise => { - throw new AuthError({ - name: ConfirmDeviceException.InternalErrorException, - message: 'error while calling confirmDevice', - }); - }); + mockConfirmDevice.mockRejectedValueOnce( + new AuthError({ + name: ConfirmDeviceException.InternalErrorException, + message: 'error while calling confirmDevice', + }), + ); const mockedDeviceKey = 'mockedDeviceKey'; const mockedGroupDeviceKey = 'mockedGroupDeviceKey'; - const deviceMetadata = await getNewDeviceMetatada( + const deviceMetadata = await getNewDeviceMetadata({ userPoolId, - { + userPoolEndpoint: undefined, + newDeviceMetadata: { DeviceKey: mockedDeviceKey, DeviceGroupKey: mockedGroupDeviceKey, }, - mockedAccessToken, - ); + accessToken: mockedAccessToken, + }); expect(deviceMetadata).toBeUndefined(); - expect(confirmDeviceClientSpy).toHaveBeenCalledWith( + expect(mockConfirmDevice).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ AccessToken: mockedAccessToken, DeviceKey: mockedDeviceKey, }), ); + }); + + it('invokes createCognitoUserPoolEndpointResolver with expected userPoolEndpoint parameter', async () => { + const expectedEndpoint = 'https://custom-endpoint.com'; + await getNewDeviceMetadata({ + userPoolId, + userPoolEndpoint: expectedEndpoint, + newDeviceMetadata: { + DeviceKey: 'devicekey', + DeviceGroupKey: 'groupkey', + }, + accessToken: mockedAccessToken, + }); - confirmDeviceClientSpy.mockClear(); + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedEndpoint, + }); }); }); diff --git a/packages/auth/__tests__/providers/cognito/identityIdStore.test.ts b/packages/auth/__tests__/providers/cognito/identityIdStore.test.ts deleted file mode 100644 index 8eeb1fef5e3..00000000000 --- a/packages/auth/__tests__/providers/cognito/identityIdStore.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import { Identity, ResourcesConfig } from '@aws-amplify/core'; - -import { DefaultIdentityIdStore } from '../../../src/providers/cognito'; - -const mockKeyValueStorage = { - setItem: jest.fn(), - getItem: jest.fn(), - removeItem: jest.fn(), - clear: jest.fn(), -}; - -const validAuthConfig: ResourcesConfig = { - Auth: { - Cognito: { - userPoolId: 'us-east-1_test-id', - identityPoolId: 'us-east-1:test-id', - userPoolClientId: 'test-id', - allowGuestAccess: true, - }, - }, -}; -const validAuthKey = { - identityId: `com.amplify.Cognito.${ - validAuthConfig.Auth!.Cognito!.identityPoolId - }.identityId`, -}; -const validGuestIdentityId: Identity = { type: 'guest', id: 'guest-id' }; -const validPrimaryIdentityId: Identity = { type: 'primary', id: 'primary-id' }; - -const noIdentityPoolIdAuthConfig: ResourcesConfig = { - Auth: { - Cognito: { - userPoolId: 'us-east-1_test-id', - userPoolClientId: 'test-id', - }, - }, -}; - -describe('DefaultIdentityIdStore', () => { - const defaultIdStore = new DefaultIdentityIdStore(mockKeyValueStorage); - describe('Happy Path Cases:', () => { - beforeAll(() => { - defaultIdStore.setAuthConfig(validAuthConfig.Auth!); - }); - it('Should set the Auth config required to form the storage keys', async () => { - expect(defaultIdStore._authKeys).toEqual(validAuthKey); - }); - it('Should store guest identityId in keyValueStorage', async () => { - defaultIdStore.storeIdentityId(validGuestIdentityId); - expect(mockKeyValueStorage.setItem).toHaveBeenCalledWith( - validAuthKey.identityId, - validGuestIdentityId.id, - ); - expect(defaultIdStore._primaryIdentityId).toBeUndefined(); - }); - it('Should load guest identityId from keyValueStorage', async () => { - mockKeyValueStorage.getItem.mockReturnValue(validGuestIdentityId.id); - - expect(await defaultIdStore.loadIdentityId()).toEqual( - validGuestIdentityId, - ); - }); - it('Should store primary identityId in keyValueStorage', async () => { - defaultIdStore.storeIdentityId(validPrimaryIdentityId); - expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith( - validAuthKey.identityId, - ); - expect(defaultIdStore._primaryIdentityId).toEqual( - validPrimaryIdentityId.id, - ); - }); - it('Should load primary identityId from keyValueStorage', async () => { - expect(await defaultIdStore.loadIdentityId()).toEqual( - validPrimaryIdentityId, - ); - }); - it('Should clear the cached identityId', async () => { - defaultIdStore.clearIdentityId(); - expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith( - validAuthKey.identityId, - ); - expect(defaultIdStore._primaryIdentityId).toBeUndefined(); - }); - }); - describe('Error Path Cases:', () => { - it('Should assert when identityPoolId is not present while setting the auth config', async () => { - try { - defaultIdStore.setAuthConfig(noIdentityPoolIdAuthConfig.Auth!); - } catch (e: any) { - expect(e.name).toEqual('InvalidIdentityPoolIdException'); - } - }); - }); -}); diff --git a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts index 86ac80a1fee..bef5cb28d61 100644 --- a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts +++ b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts @@ -2,23 +2,39 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { refreshAuthTokens } from '../../../src/providers/cognito/utils/refreshAuthTokens'; import { CognitoAuthTokens } from '../../../src/providers/cognito/tokenProvider/types'; -import { initiateAuth } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { oAuthTokenRefreshException, tokenRefreshException, } from '../../../src/providers/cognito/utils/types'; +import { createInitiateAuthClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { mockAccessToken, mockRequestId } from './testUtils/data'; jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); +jest.mock('../../../src/providers/cognito/factories'); + +const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); +const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, ); describe('refreshToken', () => { const mockedUsername = 'mockedUsername'; const mockedRefreshToken = 'mockedRefreshToken'; - // assert mocks - const mockInitiateAuth = initiateAuth as jest.Mock; + const mockInitiateAuth = jest.fn(); + + beforeEach(() => { + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); + }); + + afterEach(() => { + mockCreateInitiateAuthClient.mockClear(); + mockCreateCognitoUserPoolEndpointResolver.mockClear(); + }); + describe('positive cases', () => { beforeEach(() => { mockInitiateAuth.mockResolvedValue({ @@ -119,6 +135,39 @@ describe('refreshToken', () => { ); (window as any).AmazonCognitoAdvancedSecurityData = undefined; }); + + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected parameters', async () => { + const expectedParam = 'https://my-custom-endpoint.com'; + const expectedEndpointResolver = jest.fn(); + mockCreateCognitoUserPoolEndpointResolver.mockReturnValueOnce( + expectedEndpointResolver, + ); + + await refreshAuthTokens({ + username: 'username', + tokens: { + accessToken: { payload: {} }, + idToken: { payload: {} }, + clockDrift: 0, + refreshToken: 'refreshtoken', + username: 'username', + }, + authConfig: { + Cognito: { + userPoolId: 'us-east-1_aaaaaaa', + userPoolClientId: 'aaaaaaaaaaaa', + userPoolEndpoint: expectedParam, + }, + }, + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedParam, + }); + expect(mockCreateInitiateAuthClient).toHaveBeenCalledWith({ + endpointResolver: expectedEndpointResolver, + }); + }); }); describe('negative cases', () => { @@ -153,6 +202,7 @@ describe('refreshToken', () => { }), ).rejects.toThrow(oAuthTokenRefreshException); }); + it('should throw an exception when cognito tokens are not available', async () => { await expect( refreshAuthTokens({ diff --git a/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts b/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts index 820b2a1ef5f..0521e928654 100644 --- a/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts +++ b/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts @@ -7,9 +7,10 @@ import { Amplify, fetchAuthSession } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { rememberDevice } from '../../../src/providers/cognito'; import { UpdateDeviceStatusException } from '../../../src/providers/cognito/types/errors'; -import { updateDeviceStatus } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; import { DeviceMetadata } from '../../../src/providers/cognito/tokenProvider/types'; +import { createUpdateDeviceStatusClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -23,8 +24,9 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); jest.mock('../../../src/providers/cognito/tokenProvider'); describe('rememberDevice', () => { @@ -35,7 +37,13 @@ describe('rememberDevice', () => { }; // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockUpdateDeviceStatus = updateDeviceStatus as jest.Mock; + const mockUpdateDeviceStatus = jest.fn(); + const mockCreateUpdateDeviceStatusClient = jest.mocked( + createUpdateDeviceStatusClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); const mockGetDeviceMetadata = tokenOrchestrator.getDeviceMetadata as jest.Mock; @@ -49,12 +57,16 @@ describe('rememberDevice', () => { beforeEach(() => { mockGetDeviceMetadata.mockResolvedValue(mockDeviceMetadata); mockUpdateDeviceStatus.mockResolvedValue({ $metadata: {} }); + mockCreateUpdateDeviceStatusClient.mockReturnValueOnce( + mockUpdateDeviceStatus, + ); }); afterEach(() => { mockGetDeviceMetadata.mockReset(); mockUpdateDeviceStatus.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateUpdateDeviceStatusClient.mockClear(); }); it('should call updateDeviceStatus client with correct request', async () => { @@ -71,6 +83,25 @@ describe('rememberDevice', () => { expect(mockUpdateDeviceStatus).toHaveBeenCalledTimes(1); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await rememberDevice(); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockUpdateDeviceStatus.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts b/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts index d723a69eda8..d351a950484 100644 --- a/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts +++ b/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts @@ -7,7 +7,8 @@ import { resendSignUpCode } from '../../../src/providers/cognito'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { AuthError } from '../../../src/errors/AuthError'; import { ResendConfirmationException } from '../../../src/providers/cognito/types/errors'; -import { resendConfirmationCode } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createResendConfirmationCodeClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { getMockError } from './testUtils/data'; @@ -22,13 +23,20 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('resendSignUpCode', () => { const { user1 } = authAPITestParams; // assert mocks - const mockResendConfirmationCode = resendConfirmationCode as jest.Mock; + const mockResendConfirmationCode = jest.fn(); + const mockCreateResendConfirmationCodeClient = jest.mocked( + createResendConfirmationCodeClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -38,6 +46,9 @@ describe('resendSignUpCode', () => { mockResendConfirmationCode.mockResolvedValue( authAPITestParams.resendSignUpClientResult, ); + mockCreateResendConfirmationCodeClient.mockReturnValueOnce( + mockResendConfirmationCode, + ); }); afterEach(() => { @@ -63,6 +74,26 @@ describe('resendSignUpCode', () => { expect(mockResendConfirmationCode).toHaveBeenCalledTimes(1); }); + it('invokes createCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await resendSignUpCode({ + username: user1.username, + }); + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when username is empty', async () => { expect.assertions(2); try { diff --git a/packages/auth/__tests__/providers/cognito/resetPassword.test.ts b/packages/auth/__tests__/providers/cognito/resetPassword.test.ts index 3432ae17c0a..41deeeb170a 100644 --- a/packages/auth/__tests__/providers/cognito/resetPassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/resetPassword.test.ts @@ -6,7 +6,8 @@ import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { resetPassword } from '../../../src/providers/cognito'; import { ForgotPasswordException } from '../../../src/providers/cognito/types/errors'; -import { forgotPassword } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createForgotPasswordClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { getMockError } from './testUtils/data'; @@ -21,12 +22,19 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('resetPassword', () => { // assert mocks - const mockForgotPassword = forgotPassword as jest.Mock; + const mockForgotPassword = jest.fn(); + const mockCreateForgotPasswordClient = jest.mocked( + createForgotPasswordClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -36,10 +44,13 @@ describe('resetPassword', () => { mockForgotPassword.mockResolvedValue( authAPITestParams.resetPasswordHttpCallResult, ); + mockCreateForgotPasswordClient.mockReturnValueOnce(mockForgotPassword); }); afterEach(() => { mockForgotPassword.mockReset(); + mockCreateForgotPasswordClient.mockClear(); + mockCreateCognitoUserPoolEndpointResolver.mockClear(); }); it('should call forgotPassword and return a result', async () => { @@ -47,6 +58,26 @@ describe('resetPassword', () => { expect(result).toEqual(authAPITestParams.resetPasswordResult); }); + it('invokes createCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + + await resetPassword(authAPITestParams.resetPasswordRequest); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should contain clientMetadata from request', async () => { await resetPassword({ username: 'username', diff --git a/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts b/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts index 2b236d1db5a..31376edf642 100644 --- a/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts +++ b/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts @@ -7,7 +7,8 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { sendUserAttributeVerificationCode } from '../../../src/providers/cognito'; import { GetUserAttributeVerificationException } from '../../../src/providers/cognito/types/errors'; -import { getUserAttributeVerificationCode } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createGetUserAttributeVerificationCodeClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { getMockError, mockAccessToken } from './testUtils/data'; @@ -22,14 +23,20 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('sendUserAttributeVerificationCode', () => { // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockGetUserAttributeVerificationCode = - getUserAttributeVerificationCode as jest.Mock; + const mockGetUserAttributeVerificationCode = jest.fn(); + const mockCreateGetUserAttributeVerificationCodeClient = jest.mocked( + createGetUserAttributeVerificationCodeClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -42,11 +49,15 @@ describe('sendUserAttributeVerificationCode', () => { mockGetUserAttributeVerificationCode.mockResolvedValue( authAPITestParams.resendSignUpClientResult, ); + mockCreateGetUserAttributeVerificationCodeClient.mockReturnValueOnce( + mockGetUserAttributeVerificationCode, + ); }); afterEach(() => { mockGetUserAttributeVerificationCode.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateGetUserAttributeVerificationCodeClient.mockClear(); }); it('should return a result', async () => { @@ -69,6 +80,30 @@ describe('sendUserAttributeVerificationCode', () => { expect(mockGetUserAttributeVerificationCode).toHaveBeenCalledTimes(1); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await sendUserAttributeVerificationCode({ + userAttributeKey: 'email', + options: { + clientMetadata: { foo: 'bar' }, + }, + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockGetUserAttributeVerificationCode.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts b/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts index 1f7399093cc..1a7d0cfbc4b 100644 --- a/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts +++ b/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts @@ -6,8 +6,9 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { AssociateSoftwareTokenException } from '../../../src/providers/cognito/types/errors'; -import { associateSoftwareToken } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { setUpTOTP } from '../../../src/providers/cognito'; +import { createAssociateSoftwareTokenClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -21,14 +22,21 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('setUpTOTP', () => { const secretCode = 'secret-code'; // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockAssociateSoftwareToken = associateSoftwareToken as jest.Mock; + const mockAssociateSoftwareToken = jest.fn(); + const mockCreateAssociateSoftwareTokenClient = jest.mocked( + createAssociateSoftwareTokenClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -42,11 +50,15 @@ describe('setUpTOTP', () => { SecretCode: secretCode, $metadata: {}, }); + mockCreateAssociateSoftwareTokenClient.mockReturnValueOnce( + mockAssociateSoftwareToken, + ); }); afterEach(() => { mockAssociateSoftwareToken.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateAssociateSoftwareTokenClient.mockClear(); }); it('setUpTOTP API should call the UserPoolClient and should return a TOTPSetupDetails', async () => { @@ -64,6 +76,26 @@ describe('setUpTOTP', () => { expect(result.getSetupUri('appName', 'amplify')).toBeInstanceOf(URL); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + + await setUpTOTP(); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockAssociateSoftwareToken.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts b/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts index b4e8453b17d..f66241497f3 100644 --- a/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts @@ -6,9 +6,9 @@ import { Amplify } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { getCurrentUser, signIn } from '../../../src/providers/cognito'; -import { initiateAuth } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { InitiateAuthException } from '../../../src/providers/cognito/types/errors'; import { USER_ALREADY_AUTHENTICATED_EXCEPTION } from '../../../src/errors/constants'; +import { createInitiateAuthClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { getMockError } from './testUtils/data'; @@ -24,18 +24,23 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ })); jest.mock('../../../src/providers/cognito/apis/getCurrentUser'); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); describe('signIn API error path cases:', () => { // assert mocks - const mockInitiateAuth = initiateAuth as jest.Mock; + const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); + const mockInitiateAuth = jest.fn(); const mockedGetCurrentUser = getCurrentUser as jest.Mock; beforeAll(() => { setUpGetConfig(Amplify); }); + beforeEach(() => { + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); + }); + afterEach(() => { mockedGetCurrentUser.mockReset(); mockInitiateAuth.mockClear(); diff --git a/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts b/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts index dcefb80a121..80006cbf675 100644 --- a/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts @@ -6,8 +6,8 @@ import { Amplify } from '@aws-amplify/core'; import { getCurrentUser, signIn } from '../../../src/providers/cognito'; import * as signInHelpers from '../../../src/providers/cognito/utils/signInHelpers'; import { signInStore } from '../../../src/providers/cognito/utils/signInStore'; -import { RespondToAuthChallengeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { cognitoUserPoolsTokenProvider } from '../../../src/providers/cognito/tokenProvider'; +import { RespondToAuthChallengeCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; diff --git a/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts b/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts index 87828e427f8..c9e5ec7ab68 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts @@ -6,12 +6,12 @@ import { Amplify } from 'aws-amplify'; import { signIn } from '../../../src/providers/cognito'; import { signInWithCustomAuth } from '../../../src/providers/cognito/apis/signInWithCustomAuth'; import * as initiateAuthHelpers from '../../../src/providers/cognito/utils/signInHelpers'; -import { InitiateAuthCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { cognitoUserPoolsTokenProvider, tokenOrchestrator, } from '../../../src/providers/cognito/tokenProvider'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createInitiateAuthClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { InitiateAuthCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; @@ -19,6 +19,9 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), isBrowser: jest.fn(() => false), })); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); const authConfig = { Cognito: { @@ -85,25 +88,23 @@ describe('signIn API happy path cases', () => { }); describe('Cognito ASF', () => { - let initiateAuthSpy: jest.SpyInstance; + const mockInitiateAuth = jest.fn(); + const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); afterAll(() => { jest.restoreAllMocks(); }); beforeEach(() => { - initiateAuthSpy = jest - .spyOn(clients, 'initiateAuth') - .mockImplementationOnce( - async (): Promise => ({ - ChallengeName: 'SMS_MFA', - Session: '1234234232', - $metadata: {}, - ChallengeParameters: { - CODE_DELIVERY_DELIVERY_MEDIUM: 'SMS', - CODE_DELIVERY_DESTINATION: '*******9878', - }, - }), - ); + mockInitiateAuth.mockResolvedValueOnce({ + ChallengeName: 'SMS_MFA', + Session: '1234234232', + $metadata: {}, + ChallengeParameters: { + CODE_DELIVERY_DELIVERY_MEDIUM: 'SMS', + CODE_DELIVERY_DESTINATION: '*******9878', + }, + }); + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); // load Cognito ASF polyfill (window as any).AmazonCognitoAdvancedSecurityData = { getData() { @@ -113,7 +114,7 @@ describe('Cognito ASF', () => { }); afterEach(() => { - initiateAuthSpy.mockClear(); + mockInitiateAuth.mockClear(); (window as any).AmazonCognitoAdvancedSecurityData = undefined; }); @@ -124,7 +125,7 @@ describe('Cognito ASF', () => { authFlowType: 'CUSTOM_WITHOUT_SRP', }, }); - expect(initiateAuthSpy).toHaveBeenCalledWith( + expect(mockInitiateAuth).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts b/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts index 108e928d683..5d6aa8a1740 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts @@ -6,12 +6,12 @@ import { Amplify } from 'aws-amplify'; import { signIn } from '../../../src/providers/cognito'; import * as initiateAuthHelpers from '../../../src/providers/cognito/utils/signInHelpers'; import { signInWithCustomSRPAuth } from '../../../src/providers/cognito/apis/signInWithCustomSRPAuth'; -import { RespondToAuthChallengeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { cognitoUserPoolsTokenProvider, tokenOrchestrator, } from '../../../src/providers/cognito/tokenProvider'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createInitiateAuthClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { RespondToAuthChallengeCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; @@ -20,6 +20,10 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); + const authConfig = { Cognito: { userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', @@ -92,22 +96,23 @@ describe('signIn API happy path cases', () => { }); describe('Cognito ASF', () => { - let initiateAuthSpy: jest.SpyInstance; + const mockInitiateAuth = jest.fn(); + const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); afterAll(() => { jest.restoreAllMocks(); }); beforeEach(() => { - initiateAuthSpy = jest - .spyOn(clients, 'initiateAuth') - .mockImplementationOnce(async () => ({ - ChallengeName: 'SRP_AUTH', - Session: '1234234232', - $metadata: {}, - ChallengeParameters: { - USER_ID_FOR_SRP: authAPITestParams.user1.username, - }, - })); + mockInitiateAuth.mockResolvedValueOnce({ + ChallengeName: 'SRP_AUTH', + Session: '1234234232', + $metadata: {}, + ChallengeParameters: { + USER_ID_FOR_SRP: authAPITestParams.user1.username, + }, + }); + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); + // load Cognito ASF polyfill (window as any).AmazonCognitoAdvancedSecurityData = { getData() { @@ -117,7 +122,8 @@ describe('Cognito ASF', () => { }); afterEach(() => { - initiateAuthSpy.mockClear(); + mockInitiateAuth.mockClear(); + mockCreateInitiateAuthClient.mockClear(); (window as any).AmazonCognitoAdvancedSecurityData = undefined; }); @@ -133,7 +139,7 @@ describe('Cognito ASF', () => { } catch (_) { // only want to test the contents } - expect(initiateAuthSpy).toHaveBeenCalledWith( + expect(mockInitiateAuth).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts b/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts index c43e773f1d7..36c8d3c118a 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts @@ -6,14 +6,17 @@ import { Amplify } from 'aws-amplify'; import { signIn } from '../../../src/providers/cognito'; import { signInWithSRP } from '../../../src/providers/cognito/apis/signInWithSRP'; import * as initiateAuthHelpers from '../../../src/providers/cognito/utils/signInHelpers'; -import { RespondToAuthChallengeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { cognitoUserPoolsTokenProvider, tokenOrchestrator, } from '../../../src/providers/cognito/tokenProvider'; import { AuthError } from '../../../src'; import { createKeysForAuthStorage } from '../../../src/providers/cognito/tokenProvider/TokenStore'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { + createInitiateAuthClient, + createRespondToAuthChallengeClient, +} from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { RespondToAuthChallengeCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; @@ -33,6 +36,9 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), isBrowser: jest.fn(() => false), })); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); const authConfig = { Cognito: { @@ -193,15 +199,17 @@ describe('signIn API happy path cases', () => { }); describe('sign in with device keys', () => { - const initiateAuthSpy = jest.spyOn(clients, 'initiateAuth'); - const respondToAuthChallengeAuthSpy = jest.spyOn( - clients, - 'respondToAuthChallenge', + const mockInitiateAuth = jest.fn(); + const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); + const mockRespondToAuthChallenge = jest.fn(); + const mockCreateRespondToAuthChallengeClient = jest.mocked( + createRespondToAuthChallengeClient, ); + beforeEach(() => { setDeviceKeys(); handleUserSRPAuthflowSpy.mockRestore(); - initiateAuthSpy.mockResolvedValueOnce({ + mockInitiateAuth.mockResolvedValueOnce({ ChallengeName: 'SRP_AUTH', Session: '1234234232', $metadata: {}, @@ -209,14 +217,20 @@ describe('signIn API happy path cases', () => { USER_ID_FOR_SRP: lastAuthUser, }, }); - respondToAuthChallengeAuthSpy.mockResolvedValueOnce( + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); + mockRespondToAuthChallenge.mockResolvedValueOnce( authAPITestParams.RespondToAuthChallengeCommandOutput, ); + mockCreateRespondToAuthChallengeClient.mockReturnValueOnce( + mockRespondToAuthChallenge, + ); }); afterEach(() => { - initiateAuthSpy.mockClear(); - respondToAuthChallengeAuthSpy.mockClear(); + mockInitiateAuth.mockClear(); + mockCreateInitiateAuthClient.mockClear(); + mockRespondToAuthChallenge.mockClear(); + mockCreateRespondToAuthChallengeClient.mockClear(); }); test('respondToAuthChallenge should include device key in the request', async () => { @@ -225,9 +239,9 @@ describe('signIn API happy path cases', () => { password: 'XXXXXXXX', }); - expect(respondToAuthChallengeAuthSpy).toHaveBeenCalledTimes(1); + expect(mockRespondToAuthChallenge).toHaveBeenCalledTimes(1); const deviceKeyFromRequest = - respondToAuthChallengeAuthSpy.mock.calls[0][1].ChallengeResponses + mockRespondToAuthChallenge.mock.calls[0][1].ChallengeResponses ?.DEVICE_KEY; expect(deviceKeyFromRequest).toBe('mockedKey'); }); @@ -245,9 +259,9 @@ describe('signIn API happy path cases', () => { password: 'XXXXXXXX', }); - expect(respondToAuthChallengeAuthSpy).toHaveBeenCalledTimes(1); + expect(mockRespondToAuthChallenge).toHaveBeenCalledTimes(1); const deviceKeyFromRequest = - respondToAuthChallengeAuthSpy.mock.calls[0][1].ChallengeResponses + mockRespondToAuthChallenge.mock.calls[0][1].ChallengeResponses ?.DEVICE_KEY; expect(deviceKeyFromRequest).toBe(undefined); }, @@ -256,22 +270,23 @@ describe('signIn API happy path cases', () => { }); describe('Cognito ASF', () => { - let initiateAuthSpy: jest.SpyInstance; + const mockInitiateAuth = jest.fn(); + const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); beforeAll(() => { jest.restoreAllMocks(); }); + beforeEach(() => { - initiateAuthSpy = jest - .spyOn(clients, 'initiateAuth') - .mockImplementationOnce(async () => ({ - ChallengeName: 'SRP_AUTH', - Session: '1234234232', - $metadata: {}, - ChallengeParameters: { - USER_ID_FOR_SRP: authAPITestParams.user1.username, - }, - })); + mockInitiateAuth.mockResolvedValueOnce({ + ChallengeName: 'SRP_AUTH', + Session: '1234234232', + $metadata: {}, + ChallengeParameters: { + USER_ID_FOR_SRP: authAPITestParams.user1.username, + }, + }); + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); // load Cognito ASF polyfill (window as any).AmazonCognitoAdvancedSecurityData = { getData() { @@ -281,7 +296,8 @@ describe('Cognito ASF', () => { }); afterEach(() => { - initiateAuthSpy.mockClear(); + mockInitiateAuth.mockClear(); + mockCreateInitiateAuthClient.mockClear(); (window as any).AmazonCognitoAdvancedSecurityData = undefined; }); @@ -294,7 +310,7 @@ describe('Cognito ASF', () => { } catch (_) { // only want to test the contents } - expect(initiateAuthSpy).toHaveBeenCalledWith( + expect(mockInitiateAuth).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts b/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts index 83f3a7d2813..d675ace40a2 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts @@ -6,12 +6,12 @@ import { Amplify } from 'aws-amplify'; import { signIn } from '../../../src/providers/cognito'; import * as initiateAuthHelpers from '../../../src/providers/cognito/utils/signInHelpers'; import { signInWithUserPassword } from '../../../src/providers/cognito/apis/signInWithUserPassword'; -import { RespondToAuthChallengeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { cognitoUserPoolsTokenProvider, tokenOrchestrator, } from '../../../src/providers/cognito/tokenProvider'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createInitiateAuthClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { RespondToAuthChallengeCommandOutput } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { authAPITestParams } from './testUtils/authApiTestParams'; @@ -20,21 +20,28 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), isBrowser: jest.fn(() => false), })); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); const authConfig = { Cognito: { userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', userPoolId: 'us-west-2_zzzzz', + userPoolEndpoint: 'https://custom-endpoint.com', }, }; -cognitoUserPoolsTokenProvider.setAuthConfig(authConfig); -Amplify.configure({ - Auth: authConfig, -}); describe('signIn API happy path cases', () => { let handleUserPasswordFlowSpy: jest.SpyInstance; + beforeAll(() => { + Amplify.configure({ + Auth: authConfig, + }); + cognitoUserPoolsTokenProvider.setAuthConfig(authConfig); + }); + beforeEach(() => { handleUserPasswordFlowSpy = jest .spyOn(initiateAuthHelpers, 'handleUserPasswordAuthFlow') @@ -60,7 +67,7 @@ describe('signIn API happy path cases', () => { expect(handleUserPasswordFlowSpy).toHaveBeenCalledTimes(1); }); - test('handleUserPasswordAuthFlow should be called with clientMetada from request', async () => { + test('handleUserPasswordAuthFlow should be called with clientMetadata from request', async () => { const { username } = authAPITestParams.user1; const { password } = authAPITestParams.user1; await signInWithUserPassword({ @@ -79,22 +86,19 @@ describe('signIn API happy path cases', () => { }); describe('Cognito ASF', () => { - let initiateAuthSpy: jest.SpyInstance; + const mockInitiateAuth = jest.fn(); + const mockCreateInitiateAuthClient = jest.mocked(createInitiateAuthClient); - afterAll(() => { - jest.restoreAllMocks(); - }); beforeEach(() => { - initiateAuthSpy = jest - .spyOn(clients, 'initiateAuth') - .mockImplementationOnce(async () => ({ - ChallengeName: 'SRP_AUTH', - Session: '1234234232', - $metadata: {}, - ChallengeParameters: { - USER_ID_FOR_SRP: authAPITestParams.user1.username, - }, - })); + mockInitiateAuth.mockResolvedValueOnce({ + ChallengeName: 'SRP_AUTH', + Session: '1234234232', + $metadata: {}, + ChallengeParameters: { + USER_ID_FOR_SRP: authAPITestParams.user1.username, + }, + }); + mockCreateInitiateAuthClient.mockReturnValueOnce(mockInitiateAuth); // load Cognito ASF polyfill (window as any).AmazonCognitoAdvancedSecurityData = { getData() { @@ -104,7 +108,8 @@ describe('Cognito ASF', () => { }); afterEach(() => { - initiateAuthSpy.mockClear(); + mockInitiateAuth.mockClear(); + mockCreateInitiateAuthClient.mockClear(); (window as any).AmazonCognitoAdvancedSecurityData = undefined; }); @@ -120,7 +125,7 @@ describe('Cognito ASF', () => { } catch (_) { // only want to test the contents } - expect(initiateAuthSpy).toHaveBeenCalledWith( + expect(mockInitiateAuth).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signOut.test.ts b/packages/auth/__tests__/providers/cognito/signOut.test.ts index adae8c494cc..49779a748ca 100644 --- a/packages/auth/__tests__/providers/cognito/signOut.test.ts +++ b/packages/auth/__tests__/providers/cognito/signOut.test.ts @@ -11,26 +11,26 @@ import { AMPLIFY_SYMBOL } from '@aws-amplify/core/internals/utils'; import { signOut } from '../../../src/providers/cognito/apis/signOut'; import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; -import { - globalSignOut, - revokeToken, -} from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/utils'; import { DefaultOAuthStore } from '../../../src/providers/cognito/utils/signInWithRedirectStore'; import { handleOAuthSignOut } from '../../../src/providers/cognito/utils/oauth'; import { AuthTokenStore } from '../../../src/providers/cognito/tokenProvider/types'; +import { + createGlobalSignOutClient, + createRevokeTokenClient, +} from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { getRegionFromUserPoolId } from '../../../src/foundation/parsers'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; jest.mock('@aws-amplify/core'); jest.mock('../../../src/providers/cognito/tokenProvider'); -jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', -); -jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/utils', -); jest.mock('../../../src/providers/cognito/utils/oauth'); jest.mock('../../../src/providers/cognito/utils/signInWithRedirectStore'); jest.mock('../../../src/utils'); +jest.mock( + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', +); +jest.mock('../../../src/foundation/parsers'); +jest.mock('../../../src/providers/cognito/factories'); describe('signOut', () => { // eslint-disable-next-line camelcase @@ -54,15 +54,20 @@ describe('signOut', () => { // assert mocks const mockAmplify = Amplify as jest.Mocked; const mockClearCredentials = clearCredentials as jest.Mock; - const mockGetRegion = getRegion as jest.Mock; - const mockGlobalSignOut = globalSignOut as jest.Mock; + const mockGetRegionFromUserPoolId = jest.mocked(getRegionFromUserPoolId); + const mockGlobalSignOut = jest.fn(); + const mockCreateGlobalSignOutClient = jest.mocked(createGlobalSignOutClient); const mockHandleOAuthSignOut = handleOAuthSignOut as jest.Mock; const mockHub = Hub as jest.Mocked; - const mockRevokeToken = revokeToken as jest.Mock; + const mockRevokeToken = jest.fn(); + const mockedRevokeTokenClient = jest.mocked(createRevokeTokenClient); const mockTokenOrchestrator = tokenOrchestrator as jest.Mocked< typeof tokenOrchestrator >; const MockDefaultOAuthStore = DefaultOAuthStore as jest.Mock; + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); // create mocks const mockLoadTokens = jest.fn(); const mockAuthTokenStore = { @@ -95,7 +100,7 @@ describe('signOut', () => { }); beforeAll(() => { - mockGetRegion.mockReturnValue(region); + mockGetRegionFromUserPoolId.mockReturnValue(region); MockDefaultOAuthStore.mockImplementation( () => mockDefaultOAuthStoreInstance, ); @@ -104,7 +109,9 @@ describe('signOut', () => { beforeEach(() => { mockAmplify.getConfig.mockReturnValue({ Auth: { Cognito: cognitoConfig } }); mockGlobalSignOut.mockResolvedValue({ $metadata: {} }); + mockCreateGlobalSignOutClient.mockReturnValueOnce(mockGlobalSignOut); mockRevokeToken.mockResolvedValue({}); + mockedRevokeTokenClient.mockReturnValueOnce(mockRevokeToken); mockTokenOrchestrator.getTokenStore.mockReturnValue(mockAuthTokenStore); mockLoadTokens.mockResolvedValue(cognitoAuthTokens); }); @@ -114,10 +121,11 @@ describe('signOut', () => { mockGlobalSignOut.mockReset(); mockRevokeToken.mockReset(); mockClearCredentials.mockClear(); - mockGetRegion.mockClear(); + mockGetRegionFromUserPoolId.mockClear(); mockHub.dispatch.mockClear(); mockTokenOrchestrator.clearTokens.mockClear(); loggerDebugSpy.mockClear(); + mockCreateCognitoUserPoolEndpointResolver.mockClear(); }); describe('Without OAuth configured', () => { @@ -128,11 +136,36 @@ describe('signOut', () => { { region }, { ClientId: cognitoConfig.userPoolClientId, Token: refreshToken }, ); - expect(mockGetRegion).toHaveBeenCalledTimes(1); + expect(mockGetRegionFromUserPoolId).toHaveBeenCalledTimes(1); expect(mockGlobalSignOut).not.toHaveBeenCalled(); expectSignOut().toComplete(); }); + it('invokes createCognitoUserPoolEndpointResolver with the userPoolEndpoint for creating the revokeToken client', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + const expectedEndpointResolver = jest.fn(); + mockAmplify.getConfig.mockReturnValueOnce({ + Auth: { + Cognito: { + ...cognitoConfig, + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + mockCreateCognitoUserPoolEndpointResolver.mockReturnValueOnce( + expectedEndpointResolver, + ); + + await signOut(); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + expect(mockedRevokeTokenClient).toHaveBeenCalledWith({ + endpointResolver: expectedEndpointResolver, + }); + }); + it('should perform client sign out on an irrevocable session', async () => { mockLoadTokens.mockResolvedValue({ ...cognitoAuthTokens, @@ -143,7 +176,7 @@ describe('signOut', () => { expect(mockRevokeToken).not.toHaveBeenCalled(); expect(mockGlobalSignOut).not.toHaveBeenCalled(); - expect(mockGetRegion).not.toHaveBeenCalled(); + expect(mockGetRegionFromUserPoolId).not.toHaveBeenCalled(); expectSignOut().toComplete(); }); @@ -154,11 +187,36 @@ describe('signOut', () => { { region: 'us-west-2' }, { AccessToken: accessToken.toString() }, ); - expect(mockGetRegion).toHaveBeenCalledTimes(1); + expect(mockGetRegionFromUserPoolId).toHaveBeenCalledTimes(1); expect(mockRevokeToken).not.toHaveBeenCalled(); expectSignOut().toComplete(); }); + it('invokes createCognitoUserPoolEndpointResolver with the userPoolEndpoint for creating the globalSignOut client', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + const expectedEndpointResolver = jest.fn(); + mockAmplify.getConfig.mockReturnValueOnce({ + Auth: { + Cognito: { + ...cognitoConfig, + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + mockCreateCognitoUserPoolEndpointResolver.mockReturnValueOnce( + expectedEndpointResolver, + ); + + await signOut({ global: true }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + expect(mockCreateGlobalSignOutClient).toHaveBeenCalledWith({ + endpointResolver: expectedEndpointResolver, + }); + }); + it('should still perform client sign out if token revoke fails', async () => { mockRevokeToken.mockRejectedValue(new Error()); @@ -167,7 +225,7 @@ describe('signOut', () => { expect(loggerDebugSpy).toHaveBeenCalledWith( expect.stringContaining('Client signOut error caught'), ); - expect(mockGetRegion).toHaveBeenCalledTimes(1); + expect(mockGetRegionFromUserPoolId).toHaveBeenCalledTimes(1); expectSignOut().toComplete(); }); @@ -179,7 +237,7 @@ describe('signOut', () => { expect(loggerDebugSpy).toHaveBeenCalledWith( expect.stringContaining('Global signOut error caught'), ); - expect(mockGetRegion).toHaveBeenCalledTimes(1); + expect(mockGetRegionFromUserPoolId).toHaveBeenCalledTimes(1); expectSignOut().toComplete(); }); }); @@ -220,6 +278,8 @@ describe('signOut', () => { expect(mockHandleOAuthSignOut).toHaveBeenCalledWith( cognitoConfigWithOauth, mockDefaultOAuthStoreInstance, + mockTokenOrchestrator, + undefined, ); // In cases of OAuth, token removal and Hub dispatch should be performed by the OAuth handling since // these actions can be deferred or canceled out of altogether. diff --git a/packages/auth/__tests__/providers/cognito/signUp.test.ts b/packages/auth/__tests__/providers/cognito/signUp.test.ts index 87e0dda27c6..cb2b9b84d64 100644 --- a/packages/auth/__tests__/providers/cognito/signUp.test.ts +++ b/packages/auth/__tests__/providers/cognito/signUp.test.ts @@ -4,10 +4,11 @@ import { Amplify } from '@aws-amplify/core'; import { signUp } from '../../../src/providers/cognito'; -import { signUp as providerSignUp } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { AuthError } from '../../../src/errors/AuthError'; import { SignUpException } from '../../../src/providers/cognito/types/errors'; +import { createSignUpClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { getMockError } from './testUtils/data'; @@ -21,21 +22,35 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), isBrowser: jest.fn(() => false), })); + jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); - -const userId = '1234567890'; +jest.mock('../../../src/providers/cognito/factories'); describe('signUp', () => { + const userId = '1234567890'; const { user1 } = authAPITestParams; // assert mocks - const mockSignUp = providerSignUp as jest.Mock; + const mockSignUp = jest.fn(); + const mockCreateSignUpClient = jest.mocked(createSignUpClient); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); }); + beforeEach(() => { + mockCreateSignUpClient.mockReturnValueOnce(mockSignUp); + }); + + afterEach(() => { + mockCreateSignUpClient.mockClear(); + mockCreateCognitoUserPoolEndpointResolver.mockClear(); + }); + describe('Happy Path Cases:', () => { beforeEach(() => { mockSignUp.mockResolvedValue(authAPITestParams.signUpHttpCallResult); @@ -70,6 +85,31 @@ describe('signUp', () => { expect(mockSignUp).toHaveBeenCalledTimes(1); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await signUp({ + username: user1.username, + password: user1.password, + options: { + userAttributes: { email: user1.email }, + }, + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should return `CONFIRM_SIGN_UP` step when user isn`t confirmed yet', async () => { const result = await signUp({ username: user1.username, diff --git a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts index 5a31dbf0c74..8906d8d7eed 100644 --- a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts +++ b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts @@ -25,6 +25,8 @@ const mockAuthTokenStore = { setKeyValueStorage: jest.fn(), getDeviceMetadata: jest.fn(), clearDeviceMetadata: jest.fn(), + setOAuthMetadata: jest.fn(), + getOAuthMetadata: jest.fn(), }; const mockTokenRefresher = jest.fn(); const validAuthConfig: ResourcesConfig = { diff --git a/packages/auth/__tests__/providers/cognito/tokenProvider/tokenOrchestrator.test.ts b/packages/auth/__tests__/providers/cognito/tokenProvider/tokenOrchestrator.test.ts index e1c25ec86f7..c0853b51f23 100644 --- a/packages/auth/__tests__/providers/cognito/tokenProvider/tokenOrchestrator.test.ts +++ b/packages/auth/__tests__/providers/cognito/tokenProvider/tokenOrchestrator.test.ts @@ -24,6 +24,8 @@ describe('tokenOrchestrator', () => { setKeyValueStorage: jest.fn(), getDeviceMetadata: jest.fn(), clearDeviceMetadata: jest.fn(), + getOAuthMetadata: jest.fn(), + setOAuthMetadata: jest.fn(), }; beforeAll(() => { diff --git a/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts b/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts index dbaeca398f6..a9d4d6c9e65 100644 --- a/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts +++ b/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts @@ -8,10 +8,11 @@ import { UpdateMFAPreferenceInput, updateMFAPreference, } from '../../../src/providers/cognito'; -import { setUserMFAPreference } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthError } from '../../../src/errors/AuthError'; import { SetUserMFAPreferenceException } from '../../../src/providers/cognito/types/errors'; import { getMFASettings } from '../../../src/providers/cognito/apis/updateMFAPreference'; +import { createSetUserMFAPreferenceClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -25,8 +26,9 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); const mfaChoices: UpdateMFAPreferenceInput[] = [ { sms: 'DISABLED', totp: 'DISABLED' }, @@ -51,7 +53,13 @@ const mfaChoices: UpdateMFAPreferenceInput[] = [ describe('updateMFAPreference', () => { // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockSetUserMFAPreference = setUserMFAPreference as jest.Mock; + const mockSetUserMFAPreference = jest.fn(); + const mockCreateSetUserMFAPreferenceClient = jest.mocked( + createSetUserMFAPreferenceClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -62,11 +70,15 @@ describe('updateMFAPreference', () => { beforeEach(() => { mockSetUserMFAPreference.mockResolvedValue({}); + mockCreateSetUserMFAPreferenceClient.mockReturnValueOnce( + mockSetUserMFAPreference, + ); }); afterEach(() => { mockSetUserMFAPreference.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateSetUserMFAPreferenceClient.mockClear(); }); it.each(mfaChoices)( @@ -88,6 +100,25 @@ describe('updateMFAPreference', () => { }, ); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await updateMFAPreference(mfaChoices[0]); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); mockSetUserMFAPreference.mockImplementation(() => { diff --git a/packages/auth/__tests__/providers/cognito/updatePassword.test.ts b/packages/auth/__tests__/providers/cognito/updatePassword.test.ts index 42c0869a9a3..72dfe80119e 100644 --- a/packages/auth/__tests__/providers/cognito/updatePassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/updatePassword.test.ts @@ -8,7 +8,8 @@ import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { updatePassword } from '../../../src/providers/cognito'; import { ChangePasswordException } from '../../../src/providers/cognito/types/errors'; -import { changePassword } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createChangePasswordClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -22,15 +23,22 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('updatePassword', () => { const oldPassword = 'oldPassword'; const newPassword = 'newPassword'; // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockChangePassword = changePassword as jest.Mock; + const mockChangePassword = jest.fn(); + const mockCreateChangePasswordClient = jest.mocked( + createChangePasswordClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -41,11 +49,13 @@ describe('updatePassword', () => { beforeEach(() => { mockChangePassword.mockResolvedValue({}); + mockCreateChangePasswordClient.mockReturnValueOnce(mockChangePassword); }); afterEach(() => { mockChangePassword.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateChangePasswordClient.mockClear(); }); it('should call changePassword', async () => { @@ -61,6 +71,25 @@ describe('updatePassword', () => { ); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await updatePassword({ oldPassword, newPassword }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when oldPassword is empty', async () => { expect.assertions(2); try { diff --git a/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts b/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts index 3b1ca0f9d99..bfa9643b76d 100644 --- a/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts +++ b/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts @@ -7,8 +7,9 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { updateUserAttributes } from '../../../src/providers/cognito'; import { UpdateUserAttributesException } from '../../../src/providers/cognito/types/errors'; -import { updateUserAttributes as providerUpdateUserAttributes } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { toAttributeType } from '../../../src/providers/cognito/utils/apiHelpers'; +import { createUpdateUserAttributesClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -22,13 +23,20 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('updateUserAttributes', () => { // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockUpdateUserAttributes = providerUpdateUserAttributes as jest.Mock; + const mockUpdateUserAttributes = jest.fn(); + const mockCreateUpdateUserAttributesClient = jest.mocked( + createUpdateUserAttributesClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -52,11 +60,15 @@ describe('updateUserAttributes', () => { }, ], }); + mockCreateUpdateUserAttributesClient.mockReturnValueOnce( + mockUpdateUserAttributes, + ); }); afterEach(() => { mockUpdateUserAttributes.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateUpdateUserAttributesClient.mockClear(); }); it('should return a map with updated and not updated attributes', async () => { @@ -121,6 +133,30 @@ describe('updateUserAttributes', () => { ); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + await updateUserAttributes({ + userAttributes: {}, + options: { + clientMetadata: { foo: 'bar' }, + }, + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('updateUserAttributes API should return a map with updated attributes only', async () => { mockUpdateUserAttributes.mockResolvedValue({}); const userAttributes = { diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthFlow.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthFlow.test.ts index 78e95120977..8d62c014a94 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthFlow.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthFlow.test.ts @@ -13,6 +13,7 @@ import { AuthErrorTypes } from '../../../../../src/types/Auth'; import { OAuthStore } from '../../../../../src/providers/cognito/utils/types'; import { completeOAuthFlow } from '../../../../../src/providers/cognito/utils/oauth/completeOAuthFlow'; +jest.mock('../../../../../src/providers/cognito/tokenProvider'); jest.mock('@aws-amplify/core', () => ({ Hub: { dispatch: jest.fn(), diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/getRedirectUrl.native.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/getRedirectUrl.native.test.ts new file mode 100644 index 00000000000..248bc00814a --- /dev/null +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/getRedirectUrl.native.test.ts @@ -0,0 +1,35 @@ +import { invalidAppSchemeException } from '../../../../../src/errors/constants'; +import { getRedirectUrl } from '../../../../../src/providers/cognito/utils/oauth/getRedirectUrl.native'; + +describe('getRedirectUrl (native)', () => { + const mockRedirectUrls = [ + 'myDevApp://', + 'myProdApp://', + 'https://intermidiateSite.com', + ]; + + it('should return the first non http/s url from the array when redirectUrl is not provided', () => { + expect(getRedirectUrl(mockRedirectUrls)).toStrictEqual(mockRedirectUrls[0]); + }); + + it('should return redirectUrl if it matches at least one of the redirect urls from config', () => { + const configRedirectUrl = mockRedirectUrls[2]; + + expect(getRedirectUrl(mockRedirectUrls, configRedirectUrl)).toStrictEqual( + configRedirectUrl, + ); + }); + + it('should throw an exception when there is no url with no http nor https as prefix irrespective of a redirectUrl is given or not', () => { + const mockRedirectUrlsWithNoAppScheme = ['https://intermidiateSite.com']; + expect(() => + getRedirectUrl( + mockRedirectUrlsWithNoAppScheme, + mockRedirectUrlsWithNoAppScheme[0], + ), + ).toThrow(invalidAppSchemeException); + expect(() => getRedirectUrl(mockRedirectUrlsWithNoAppScheme)).toThrow( + invalidAppSchemeException, + ); + }); +}); diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/getRedirectUrl.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/getRedirectUrl.test.ts new file mode 100644 index 00000000000..0f75d28c640 --- /dev/null +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/getRedirectUrl.test.ts @@ -0,0 +1,66 @@ +import { getRedirectUrl } from '../../../../../src/providers/cognito/utils/oauth'; +import { + invalidOriginException, + invalidPreferredRedirectUrlException, + invalidRedirectException, +} from '../../../../../src/errors/constants'; + +describe('getRedirectUrl', () => { + const mockRedirectUrls = ['https://example.com/app']; + let windowSpy: jest.SpyInstance; + + beforeEach(() => { + windowSpy = jest.spyOn(window, 'window', 'get'); + }); + + afterEach(() => { + windowSpy.mockRestore(); + }); + + it('should return the redirect url that has the same origin and same pathName', () => { + windowSpy.mockReturnValue({ + location: { + origin: 'https://example.com/', + pathname: 'app', + }, + }); + expect(getRedirectUrl(mockRedirectUrls)).toStrictEqual(mockRedirectUrls[0]); + }); + + it('should throw an invalid origin exception if there is no url that is the same origin and pathname', () => { + windowSpy.mockReturnValue({ + location: { + origin: 'https://differentOrigin.com/', + pathname: 'differentApp', + }, + }); + expect(() => getRedirectUrl(mockRedirectUrls)).toThrow( + invalidOriginException, + ); + }); + + it('should throw an invalid redirect exception if there is no url that is the same origin/pathname and is also not http or https', () => { + const mockNonHttpRedirectUrls = ['test-non-http-string']; + windowSpy.mockReturnValue({ + location: { + origin: 'https://differentOrigin.com/', + pathname: 'differentApp', + }, + }); + expect(() => getRedirectUrl(mockNonHttpRedirectUrls)).toThrow( + invalidRedirectException, + ); + }); + + it('should return the redirectUrl if it is provided and matches one of the redirectUrls from config', () => { + expect(getRedirectUrl(mockRedirectUrls, mockRedirectUrls[0])).toStrictEqual( + mockRedirectUrls[0], + ); + }); + + it('should throw an exception if redirectUrl is given but does not match any of the redirectUrls from config', () => { + expect(() => + getRedirectUrl(mockRedirectUrls, 'https://unknownOrigin.com'), + ).toThrow(invalidPreferredRedirectUrlException); + }); +}); diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts index 3d56cca1b90..bd056ccdf23 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { tokenOrchestrator } from '../../../../../src/providers/cognito/tokenProvider'; import { completeOAuthSignOut } from '../../../../../src/providers/cognito/utils/oauth/completeOAuthSignOut'; import { handleOAuthSignOut } from '../../../../../src/providers/cognito/utils/oauth/handleOAuthSignOut.native'; import { oAuthSignOutRedirect } from '../../../../../src/providers/cognito/utils/oauth/oAuthSignOutRedirect'; @@ -23,6 +24,9 @@ describe('handleOAuthSignOut (native)', () => { // assert mocks const mockCompleteOAuthSignOut = completeOAuthSignOut as jest.Mock; const mockOAuthSignOutRedirect = oAuthSignOutRedirect as jest.Mock; + const mockTokenOrchestrator = tokenOrchestrator as jest.Mocked< + typeof tokenOrchestrator + >; // create mocks const mockStore = { loadOAuthSignIn: jest.fn(), @@ -43,33 +47,51 @@ describe('handleOAuthSignOut (native)', () => { }); it('should complete OAuth sign out and redirect', async () => { mockOAuthSignOutRedirect.mockResolvedValue({ type: 'success' }); - await handleOAuthSignOut(cognitoConfig, mockStore); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( cognitoConfig, false, + undefined, ); expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); }); it('should not complete OAuth sign out if redirect is canceled', async () => { mockOAuthSignOutRedirect.mockResolvedValue({ type: 'canceled' }); - await handleOAuthSignOut(cognitoConfig, mockStore); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( cognitoConfig, false, + undefined, ); expect(mockCompleteOAuthSignOut).not.toHaveBeenCalled(); }); it('should not complete OAuth sign out if redirect failed', async () => { mockOAuthSignOutRedirect.mockResolvedValue({ type: 'error' }); - await handleOAuthSignOut(cognitoConfig, mockStore); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( cognitoConfig, false, + undefined, ); expect(mockCompleteOAuthSignOut).not.toHaveBeenCalled(); }); @@ -81,9 +103,18 @@ describe('handleOAuthSignOut (native)', () => { preferPrivateSession: true, }); mockOAuthSignOutRedirect.mockResolvedValue({ type: 'error' }); - await handleOAuthSignOut(cognitoConfig, mockStore); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); - expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith(cognitoConfig, true); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( + cognitoConfig, + true, + undefined, + ); expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); }); @@ -92,7 +123,12 @@ describe('handleOAuthSignOut (native)', () => { isOAuthSignIn: false, preferPrivateSession: false, }); - await handleOAuthSignOut(cognitoConfig, mockStore); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); expect(mockOAuthSignOutRedirect).not.toHaveBeenCalled(); expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts index f6fab30158f..6109b2e68e7 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { TokenOrchestrator } from '../../../../../src/providers/cognito'; import { completeOAuthSignOut } from '../../../../../src/providers/cognito/utils/oauth/completeOAuthSignOut'; import { handleOAuthSignOut } from '../../../../../src/providers/cognito/utils/oauth/handleOAuthSignOut'; import { oAuthSignOutRedirect } from '../../../../../src/providers/cognito/utils/oauth/oAuthSignOutRedirect'; @@ -12,6 +13,7 @@ jest.mock( jest.mock( '../../../../../src/providers/cognito/utils/oauth/oAuthSignOutRedirect', ); +jest.mock('../../../../../src/providers/cognito/tokenProvider'); describe('handleOAuthSignOut', () => { const region = 'us-west-2'; @@ -27,9 +29,13 @@ describe('handleOAuthSignOut', () => { const mockStore = { loadOAuthSignIn: jest.fn(), } as unknown as jest.Mocked; + const mockTokenOrchestrator = { + getOAuthMetadata: jest.fn(), + } as unknown as jest.Mocked; afterEach(() => { mockStore.loadOAuthSignIn.mockReset(); + mockTokenOrchestrator.getOAuthMetadata.mockReset(); mockCompleteOAuthSignOut.mockClear(); mockOAuthSignOutRedirect.mockClear(); }); @@ -39,10 +45,42 @@ describe('handleOAuthSignOut', () => { isOAuthSignIn: true, preferPrivateSession: false, }); - await handleOAuthSignOut(cognitoConfig, mockStore); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); - expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith(cognitoConfig); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( + cognitoConfig, + false, + undefined, + ); + }); + + it('should complete OAuth sign out and redirect when there oauth metadata in tokenOrchestrator', async () => { + mockTokenOrchestrator.getOAuthMetadata.mockResolvedValue({ + oauthSignIn: true, + }); + mockStore.loadOAuthSignIn.mockResolvedValue({ + isOAuthSignIn: false, + preferPrivateSession: false, + }); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); + + expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( + cognitoConfig, + false, + undefined, + ); }); it('should complete OAuth sign out but not redirect', async () => { @@ -50,7 +88,12 @@ describe('handleOAuthSignOut', () => { isOAuthSignIn: false, preferPrivateSession: false, }); - await handleOAuthSignOut(cognitoConfig, mockStore); + await handleOAuthSignOut( + cognitoConfig, + mockStore, + mockTokenOrchestrator, + undefined, + ); expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); expect(mockOAuthSignOutRedirect).not.toHaveBeenCalled(); diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts index a16bbb54eb1..97cde00e5a0 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts @@ -47,6 +47,7 @@ describe('oAuthSignOutRedirect', () => { expect(mockGetRedirectUrl).toHaveBeenCalledWith( authConfig.loginWith.oauth.redirectSignOut, + undefined, ); expect(mockOpenAuthSession).toHaveBeenCalledWith( `https://${domain}/logout?client_id=${userPoolClientId}&logout_uri=${encodedSignOutRedirectUrl}`, diff --git a/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts b/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts index aceb6ed480a..0f7c5bcb109 100644 --- a/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts +++ b/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts @@ -8,7 +8,8 @@ import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { VerifySoftwareTokenException } from '../../../src/providers/cognito/types/errors'; import { verifyTOTPSetup } from '../../../src/providers/cognito'; -import { verifySoftwareToken } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { createVerifySoftwareTokenClient } from '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../../src/providers/cognito/factories'; import { getMockError, mockAccessToken } from './testUtils/data'; import { setUpGetConfig } from './testUtils/setUpGetConfig'; @@ -22,15 +23,22 @@ jest.mock('@aws-amplify/core/internals/utils', () => ({ isBrowser: jest.fn(() => false), })); jest.mock( - '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider', + '../../../src/foundation/factories/serviceClients/cognitoIdentityProvider', ); +jest.mock('../../../src/providers/cognito/factories'); describe('verifyTOTPSetup', () => { const code = '123456'; const friendlyDeviceName = 'FriendlyDeviceName'; // assert mocks const mockFetchAuthSession = fetchAuthSession as jest.Mock; - const mockVerifySoftwareToken = verifySoftwareToken as jest.Mock; + const mockVerifySoftwareToken = jest.fn(); + const mockCreateVerifySoftwareTokenClient = jest.mocked( + createVerifySoftwareTokenClient, + ); + const mockCreateCognitoUserPoolEndpointResolver = jest.mocked( + createCognitoUserPoolEndpointResolver, + ); beforeAll(() => { setUpGetConfig(Amplify); @@ -41,11 +49,15 @@ describe('verifyTOTPSetup', () => { beforeEach(() => { mockVerifySoftwareToken.mockResolvedValue({}); + mockCreateVerifySoftwareTokenClient.mockReturnValueOnce( + mockVerifySoftwareToken, + ); }); afterEach(() => { mockVerifySoftwareToken.mockReset(); mockFetchAuthSession.mockClear(); + mockCreateVerifySoftwareTokenClient.mockClear(); }); it('should return successful response', async () => { @@ -64,6 +76,29 @@ describe('verifyTOTPSetup', () => { ); }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected endpointOverride', async () => { + const expectedUserPoolEndpoint = 'https://my-custom-endpoint.com'; + jest.mocked(Amplify.getConfig).mockReturnValueOnce({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + userPoolEndpoint: expectedUserPoolEndpoint, + }, + }, + }); + + await verifyTOTPSetup({ + code, + options: { friendlyDeviceName }, + }); + + expect(mockCreateCognitoUserPoolEndpointResolver).toHaveBeenCalledWith({ + endpointOverride: expectedUserPoolEndpoint, + }); + }); + it('should throw an error when code is empty', async () => { expect.assertions(2); try { diff --git a/packages/auth/package.json b/packages/auth/package.json index d8b852f9657..705e909d167 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/auth", - "version": "6.3.14", + "version": "6.4.2", "description": "Auth category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -97,8 +97,8 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", - "@aws-amplify/react-native": "1.1.4", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/react-native": "1.1.5", "@jest/test-sequencer": "^29.7.0", "typescript": "5.0.2" } diff --git a/packages/auth/src/errors/constants.ts b/packages/auth/src/errors/constants.ts index 18ae41d71a6..faf1ceba375 100644 --- a/packages/auth/src/errors/constants.ts +++ b/packages/auth/src/errors/constants.ts @@ -10,6 +10,10 @@ export const DEVICE_METADATA_NOT_FOUND_EXCEPTION = 'DeviceMetadataNotFoundException'; export const AUTO_SIGN_IN_EXCEPTION = 'AutoSignInException'; export const INVALID_REDIRECT_EXCEPTION = 'InvalidRedirectException'; +export const INVALID_APP_SCHEME_EXCEPTION = 'InvalidAppSchemeException'; +export const INVALID_PREFERRED_REDIRECT_EXCEPTION = + 'InvalidPreferredRedirectUrlException'; + export const invalidRedirectException = new AuthError({ name: INVALID_REDIRECT_EXCEPTION, message: @@ -17,6 +21,19 @@ export const invalidRedirectException = new AuthError({ recoverySuggestion: 'Please make sure the signIn/Out redirect in your oauth config is valid.', }); +export const invalidAppSchemeException = new AuthError({ + name: INVALID_APP_SCHEME_EXCEPTION, + message: 'A valid non-http app scheme was not found in the config.', + recoverySuggestion: + 'Please make sure a valid custom app scheme is present in the config.', +}); +export const invalidPreferredRedirectUrlException = new AuthError({ + name: INVALID_PREFERRED_REDIRECT_EXCEPTION, + message: + 'The given preferredRedirectUrl does not match any items in the redirectSignOutUrls array from the config.', + recoverySuggestion: + 'Please make sure a matching preferredRedirectUrl is provided.', +}); export const INVALID_ORIGIN_EXCEPTION = 'InvalidOriginException'; export const invalidOriginException = new AuthError({ name: INVALID_ORIGIN_EXCEPTION, diff --git a/packages/auth/src/foundation/cognitoUserPoolEndpointResolver.ts b/packages/auth/src/foundation/cognitoUserPoolEndpointResolver.ts new file mode 100644 index 00000000000..dc57e2e0ce4 --- /dev/null +++ b/packages/auth/src/foundation/cognitoUserPoolEndpointResolver.ts @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { + EndpointResolverOptions, + getDnsSuffix, +} from '@aws-amplify/core/internals/aws-client-utils'; +import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; + +import { COGNITO_IDP_SERVICE_NAME } from './constants'; + +export const cognitoUserPoolEndpointResolver = ({ + region, +}: EndpointResolverOptions): { url: URL } => ({ + url: new AmplifyUrl( + `https://${COGNITO_IDP_SERVICE_NAME}.${region}.${getDnsSuffix(region)}`, + ), +}); diff --git a/packages/auth/src/foundation/constants.ts b/packages/auth/src/foundation/constants.ts new file mode 100644 index 00000000000..56814b3e66f --- /dev/null +++ b/packages/auth/src/foundation/constants.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +/** + * The service name used to sign requests if the API requires authentication. + */ +export const COGNITO_IDP_SERVICE_NAME = 'cognito-idp'; diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/constants.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/constants.ts new file mode 100644 index 00000000000..8898f8bc32a --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/constants.ts @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { + getRetryDecider, + jitteredBackoff, + parseJsonError, +} from '@aws-amplify/core/internals/aws-client-utils'; +import { getAmplifyUserAgent } from '@aws-amplify/core/internals/utils'; + +import { COGNITO_IDP_SERVICE_NAME } from '../../../constants'; + +export const DEFAULT_SERVICE_CLIENT_API_CONFIG = { + service: COGNITO_IDP_SERVICE_NAME, + retryDecider: getRetryDecider(parseJsonError), + computeDelay: jitteredBackoff, + userAgentValue: getAmplifyUserAgent(), + cache: 'no-store', +}; diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createAssociateSoftwareTokenClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createAssociateSoftwareTokenClient.ts new file mode 100644 index 00000000000..4fa07c8a217 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createAssociateSoftwareTokenClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + AssociateSoftwareTokenCommandInput, + AssociateSoftwareTokenCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createAssociateSoftwareTokenClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'AssociateSoftwareToken', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createChangePasswordClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createChangePasswordClient.ts new file mode 100644 index 00000000000..f8e76959850 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createChangePasswordClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { + ChangePasswordCommandInput, + ChangePasswordCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createChangePasswordClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('ChangePassword'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmDeviceClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmDeviceClient.ts new file mode 100644 index 00000000000..3d9ced2e060 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmDeviceClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { + ConfirmDeviceCommandInput, + ConfirmDeviceCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createConfirmDeviceClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('ConfirmDevice'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmForgotPasswordClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmForgotPasswordClient.ts new file mode 100644 index 00000000000..a300a4ccadb --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmForgotPasswordClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ConfirmForgotPasswordCommandInput, + ConfirmForgotPasswordCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createConfirmForgotPasswordClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'ConfirmForgotPassword', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmSignUpClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmSignUpClient.ts new file mode 100644 index 00000000000..d5a712af669 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createConfirmSignUpClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { + ConfirmSignUpCommandInput, + ConfirmSignUpCommandOutput, + ServiceClientFactoryInput, +} from './types'; + +export const createConfirmSignUpClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('ConfirmSignUp'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createDeleteUserAttributesClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createDeleteUserAttributesClient.ts new file mode 100644 index 00000000000..052ff8c9b0a --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createDeleteUserAttributesClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + DeleteUserAttributesCommandInput, + DeleteUserAttributesCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createDeleteUserAttributesClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'DeleteUserAttributes', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createDeleteUserClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createDeleteUserClient.ts new file mode 100644 index 00000000000..70cb9860ee2 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createDeleteUserClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + DeleteUserCommandInput, + DeleteUserCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createEmptyResponseDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createDeleteUserClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('DeleteUser'), + createEmptyResponseDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createForgetDeviceClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createForgetDeviceClient.ts new file mode 100644 index 00000000000..f2851a80f78 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createForgetDeviceClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createEmptyResponseDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { + ForgetDeviceCommandInput, + ForgetDeviceCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createForgetDeviceClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('ForgetDevice'), + createEmptyResponseDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createForgotPasswordClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createForgotPasswordClient.ts new file mode 100644 index 00000000000..965e8475d83 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createForgotPasswordClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ForgotPasswordCommandInput, + ForgotPasswordCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createForgotPasswordClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('ForgotPassword'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGetUserAttributeVerificationCodeClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGetUserAttributeVerificationCodeClient.ts new file mode 100644 index 00000000000..4b699383ffe --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGetUserAttributeVerificationCodeClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + GetUserAttributeVerificationCodeCommandInput, + GetUserAttributeVerificationCodeCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createGetUserAttributeVerificationCodeClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'GetUserAttributeVerificationCode', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGetUserClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGetUserClient.ts new file mode 100644 index 00000000000..0a0eed9f070 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGetUserClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + GetUserCommandInput, + GetUserCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createGetUserClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('GetUser'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGlobalSignOutClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGlobalSignOutClient.ts new file mode 100644 index 00000000000..3ef65818bbf --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createGlobalSignOutClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + GlobalSignOutCommandInput, + GlobalSignOutCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createGlobalSignOutClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('GlobalSignOut'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createInitiateAuthClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createInitiateAuthClient.ts new file mode 100644 index 00000000000..b505144933e --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createInitiateAuthClient.ts @@ -0,0 +1,27 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + InitiateAuthCommandInput, + InitiateAuthCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createInitiateAuthClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('InitiateAuth'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createListDevicesClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createListDevicesClient.ts new file mode 100644 index 00000000000..b6ec1ffd385 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createListDevicesClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ListDevicesCommandInput, + ListDevicesCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createListDevicesClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('ListDevices'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createResendConfirmationCodeClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createResendConfirmationCodeClient.ts new file mode 100644 index 00000000000..7fda8d140c5 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createResendConfirmationCodeClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ResendConfirmationCodeCommandInput, + ResendConfirmationCodeCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createResendConfirmationCodeClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'ResendConfirmationCode', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createRespondToAuthChallengeClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createRespondToAuthChallengeClient.ts new file mode 100644 index 00000000000..736fdfd0ed7 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createRespondToAuthChallengeClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + RespondToAuthChallengeCommandInput, + RespondToAuthChallengeCommandOutput, + ServiceClientFactoryInput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createRespondToAuthChallengeClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'RespondToAuthChallenge', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createRevokeTokenClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createRevokeTokenClient.ts new file mode 100644 index 00000000000..4deb8a8faf3 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createRevokeTokenClient.ts @@ -0,0 +1,29 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { ServiceClientFactoryInput } from './types'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +interface RevokeTokenInput { + Token: string; + ClientId: string; +} + +type RevokeTokenOutput = Record; + +export const createRevokeTokenClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('RevokeToken'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createSetUserMFAPreferenceClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createSetUserMFAPreferenceClient.ts new file mode 100644 index 00000000000..60b0f4bfddd --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createSetUserMFAPreferenceClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ServiceClientFactoryInput, + SetUserMFAPreferenceCommandInput, + SetUserMFAPreferenceCommandOutput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createSetUserMFAPreferenceClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'SetUserMFAPreference', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createSignUpClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createSignUpClient.ts new file mode 100644 index 00000000000..e77676bab1d --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createSignUpClient.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ServiceClientFactoryInput, + SignUpCommandInput, + SignUpCommandOutput, +} from './types'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; + +export const createSignUpClient = (config: ServiceClientFactoryInput) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer('SignUp'), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createUpdateDeviceStatusClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createUpdateDeviceStatusClient.ts new file mode 100644 index 00000000000..9e511187ba5 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createUpdateDeviceStatusClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ServiceClientFactoryInput, + UpdateDeviceStatusCommandInput, + UpdateDeviceStatusCommandOutput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createUpdateDeviceStatusClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'UpdateDeviceStatus', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createUpdateUserAttributesClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createUpdateUserAttributesClient.ts new file mode 100644 index 00000000000..5c71001c41d --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createUpdateUserAttributesClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ServiceClientFactoryInput, + UpdateUserAttributesCommandInput, + UpdateUserAttributesCommandOutput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createUpdateUserAttributesClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'UpdateUserAttributes', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createVerifySoftwareTokenClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createVerifySoftwareTokenClient.ts new file mode 100644 index 00000000000..c5b63486c42 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createVerifySoftwareTokenClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ServiceClientFactoryInput, + VerifySoftwareTokenCommandInput, + VerifySoftwareTokenCommandOutput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createVerifySoftwareTokenClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'VerifySoftwareToken', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createVerifyUserAttributeClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createVerifyUserAttributeClient.ts new file mode 100644 index 00000000000..ad24b27c97a --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/createVerifyUserAttributeClient.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; + +import { + ServiceClientFactoryInput, + VerifyUserAttributeCommandInput, + VerifyUserAttributeCommandOutput, +} from './types'; +import { cognitoUserPoolTransferHandler } from './shared/handler'; +import { + createUserPoolDeserializer, + createUserPoolSerializer, +} from './shared/serde'; +import { DEFAULT_SERVICE_CLIENT_API_CONFIG } from './constants'; + +export const createVerifyUserAttributeClient = ( + config: ServiceClientFactoryInput, +) => + composeServiceApi( + cognitoUserPoolTransferHandler, + createUserPoolSerializer( + 'VerifyUserAttribute', + ), + createUserPoolDeserializer(), + { + ...DEFAULT_SERVICE_CLIENT_API_CONFIG, + ...config, + }, + ); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/index.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/index.ts new file mode 100644 index 00000000000..2b93cd09150 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/index.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +export { createInitiateAuthClient } from './createInitiateAuthClient'; +export { createRevokeTokenClient } from './createRevokeTokenClient'; +export { createSignUpClient } from './createSignUpClient'; +export { createConfirmSignUpClient } from './createConfirmSignUpClient'; +export { createForgotPasswordClient } from './createForgotPasswordClient'; +export { createConfirmForgotPasswordClient } from './createConfirmForgotPasswordClient'; +export { createRespondToAuthChallengeClient } from './createRespondToAuthChallengeClient'; +export { createResendConfirmationCodeClient } from './createResendConfirmationCodeClient'; +export { createVerifySoftwareTokenClient } from './createVerifySoftwareTokenClient'; +export { createAssociateSoftwareTokenClient } from './createAssociateSoftwareTokenClient'; +export { createSetUserMFAPreferenceClient } from './createSetUserMFAPreferenceClient'; +export { createGetUserClient } from './createGetUserClient'; +export { createChangePasswordClient } from './createChangePasswordClient'; +export { createConfirmDeviceClient } from './createConfirmDeviceClient'; +export { createForgetDeviceClient } from './createForgetDeviceClient'; +export { createDeleteUserClient } from './createDeleteUserClient'; +export { createGetUserAttributeVerificationCodeClient } from './createGetUserAttributeVerificationCodeClient'; +export { createGlobalSignOutClient } from './createGlobalSignOutClient'; +export { createUpdateUserAttributesClient } from './createUpdateUserAttributesClient'; +export { createVerifyUserAttributeClient } from './createVerifyUserAttributeClient'; +export { createUpdateDeviceStatusClient } from './createUpdateDeviceStatusClient'; +export { createListDevicesClient } from './createListDevicesClient'; +export { createDeleteUserAttributesClient } from './createDeleteUserAttributesClient'; diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/cognitoUserPoolTransferHandler.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/cognitoUserPoolTransferHandler.ts new file mode 100644 index 00000000000..b1b917f0a08 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/cognitoUserPoolTransferHandler.ts @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; +import { + HttpRequest, + Middleware, + unauthenticatedHandler, +} from '@aws-amplify/core/internals/aws-client-utils'; +import { HttpResponse } from '@aws-amplify/core/src/clients/types'; + +/** + * A Cognito Identity-specific middleware that disables caching for all requests. + */ +const disableCacheMiddlewareFactory: Middleware< + HttpRequest, + HttpResponse, + Record +> = () => (next, _) => + async function disableCacheMiddleware(request) { + request.headers['cache-control'] = 'no-store'; + + return next(request); + }; + +/** + * A Cognito Identity-specific transfer handler that does NOT sign requests, and + * disables caching. + * + * @internal + */ +export const cognitoUserPoolTransferHandler = composeTransferHandler< + [Parameters[0]], + HttpRequest, + HttpResponse, + typeof unauthenticatedHandler +>(unauthenticatedHandler, [disableCacheMiddlewareFactory]); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/index.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/index.ts new file mode 100644 index 00000000000..c0df8483e89 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/handler/index.ts @@ -0,0 +1,4 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +export { cognitoUserPoolTransferHandler } from './cognitoUserPoolTransferHandler'; diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer.ts new file mode 100644 index 00000000000..a27f4ef0564 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createEmptyResponseDeserializer.ts @@ -0,0 +1,21 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { + HttpResponse, + parseJsonError, +} from '@aws-amplify/core/internals/aws-client-utils'; + +import { assertServiceError } from '../../../../../../errors/utils/assertServiceError'; +import { AuthError } from '../../../../../../errors/AuthError'; + +export const createEmptyResponseDeserializer = + (): ((response: HttpResponse) => Promise) => + async (response: HttpResponse): Promise => { + if (response.statusCode >= 300) { + const error = await parseJsonError(response); + assertServiceError(error); + throw new AuthError({ name: error.name, message: error.message }); + } else { + return undefined; + } + }; diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.ts new file mode 100644 index 00000000000..dc9c16d7d9f --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { + HttpResponse, + parseJsonBody, + parseJsonError, +} from '@aws-amplify/core/internals/aws-client-utils'; + +import { assertServiceError } from '../../../../../../errors/utils/assertServiceError'; +import { AuthError } from '../../../../../../errors/AuthError'; + +export const createUserPoolDeserializer = + (): ((response: HttpResponse) => Promise) => + async (response: HttpResponse): Promise => { + if (response.statusCode >= 300) { + const error = await parseJsonError(response); + assertServiceError(error); + throw new AuthError({ name: error.name, message: error.message }); + } + + return parseJsonBody(response); + }; diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer.ts new file mode 100644 index 00000000000..81f22df9312 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolSerializer.ts @@ -0,0 +1,58 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { + Endpoint, + Headers, + HttpRequest, +} from '@aws-amplify/core/internals/aws-client-utils'; + +type ClientOperation = + | 'SignUp' + | 'ConfirmSignUp' + | 'ForgotPassword' + | 'ConfirmForgotPassword' + | 'InitiateAuth' + | 'RespondToAuthChallenge' + | 'ResendConfirmationCode' + | 'VerifySoftwareToken' + | 'AssociateSoftwareToken' + | 'SetUserMFAPreference' + | 'GetUser' + | 'ChangePassword' + | 'ConfirmDevice' + | 'ForgetDevice' + | 'DeleteUser' + | 'GetUserAttributeVerificationCode' + | 'GlobalSignOut' + | 'UpdateUserAttributes' + | 'VerifyUserAttribute' + | 'DeleteUserAttributes' + | 'UpdateDeviceStatus' + | 'ListDevices' + | 'RevokeToken'; + +export const createUserPoolSerializer = + (operation: ClientOperation) => + (input: Input, endpoint: Endpoint): HttpRequest => { + const headers = getSharedHeaders(operation); + const body = JSON.stringify(input); + + return buildHttpRpcRequest(endpoint, headers, body); + }; + +const getSharedHeaders = (operation: string): Headers => ({ + 'content-type': 'application/x-amz-json-1.1', + 'x-amz-target': `AWSCognitoIdentityProviderService.${operation}`, +}); + +const buildHttpRpcRequest = ( + { url }: Endpoint, + headers: Headers, + body: string, +): HttpRequest => ({ + headers, + url, + body, + method: 'POST', +}); diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/index.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/index.ts new file mode 100644 index 00000000000..bb805866e28 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/index.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +export { createUserPoolSerializer } from './createUserPoolSerializer'; +export { createUserPoolDeserializer } from './createUserPoolDeserializer'; +export { createEmptyResponseDeserializer } from './createEmptyResponseDeserializer'; diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/index.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/index.ts new file mode 100644 index 00000000000..3374c6b6194 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/index.ts @@ -0,0 +1,4 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +export * from './sdk'; +export * from './serviceClient'; diff --git a/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/types.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/sdk.ts similarity index 100% rename from packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/types.ts rename to packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/sdk.ts diff --git a/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/serviceClient.ts b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/serviceClient.ts new file mode 100644 index 00000000000..0f358133832 --- /dev/null +++ b/packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/serviceClient.ts @@ -0,0 +1,8 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { EndpointResolverOptions } from '@aws-amplify/core/internals/aws-client-utils'; + +export interface ServiceClientFactoryInput { + endpointResolver(options: EndpointResolverOptions): { url: URL }; +} diff --git a/packages/auth/src/foundation/parsers/index.ts b/packages/auth/src/foundation/parsers/index.ts new file mode 100644 index 00000000000..901f99a010e --- /dev/null +++ b/packages/auth/src/foundation/parsers/index.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +export { + getRegionFromUserPoolId, + getRegionFromIdentityPoolId, +} from './regionParsers'; diff --git a/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/utils.ts b/packages/auth/src/foundation/parsers/regionParsers.ts similarity index 86% rename from packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/utils.ts rename to packages/auth/src/foundation/parsers/regionParsers.ts index 2202f2dcd37..193ddee374d 100644 --- a/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/utils.ts +++ b/packages/auth/src/foundation/parsers/regionParsers.ts @@ -1,9 +1,8 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { AuthError } from '../../errors/AuthError'; -import { AuthError } from '../../../../../errors/AuthError'; - -export function getRegion(userPoolId?: string): string { +export function getRegionFromUserPoolId(userPoolId?: string): string { const region = userPoolId?.split('_')[0]; if ( !userPoolId || diff --git a/packages/auth/src/providers/cognito/apis/confirmResetPassword.ts b/packages/auth/src/providers/cognito/apis/confirmResetPassword.ts index 29081093e5c..5c4edc100cf 100644 --- a/packages/auth/src/providers/cognito/apis/confirmResetPassword.ts +++ b/packages/auth/src/providers/cognito/apis/confirmResetPassword.ts @@ -10,11 +10,12 @@ import { import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { ConfirmResetPasswordInput } from '../types'; -import { confirmForgotPassword } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; import { ConfirmForgotPasswordException } from '../../cognito/types/errors'; import { getAuthUserAgentValue } from '../../../utils'; import { getUserContextData } from '../utils/userContextData'; +import { createConfirmForgotPasswordClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; /** * Confirms the new password and verification code to reset the password. * @@ -30,7 +31,7 @@ export async function confirmResetPassword( ): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - const { userPoolClientId, userPoolId } = authConfig; + const { userPoolClientId, userPoolId, userPoolEndpoint } = authConfig; const { username, newPassword } = input; assertValidationError( !!username, @@ -53,10 +54,14 @@ export async function confirmResetPassword( userPoolId, userPoolClientId, }); - + const confirmForgotPassword = createConfirmForgotPasswordClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await confirmForgotPassword( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(authConfig.userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmResetPassword), }, { diff --git a/packages/auth/src/providers/cognito/apis/confirmSignIn.ts b/packages/auth/src/providers/cognito/apis/confirmSignIn.ts index 6aad224af30..b8e8475aa42 100644 --- a/packages/auth/src/providers/cognito/apis/confirmSignIn.ts +++ b/packages/auth/src/providers/cognito/apis/confirmSignIn.ts @@ -17,7 +17,7 @@ import { } from '../utils/signInStore'; import { AuthError } from '../../../errors/AuthError'; import { - getNewDeviceMetatada, + getNewDeviceMetadata, getSignInResult, getSignInResultFromError, handleChallengeName, @@ -27,12 +27,12 @@ import { assertValidationError } from '../../../errors/utils/assertValidationErr import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { AuthErrorCodes } from '../../../common/AuthErrorStrings'; import { cacheCognitoTokens } from '../tokenProvider/cacheTokens'; +import { tokenOrchestrator } from '../tokenProvider'; +import { dispatchSignedInHubEvent } from '../utils/dispatchSignedInHubEvent'; import { ChallengeName, ChallengeParameters, -} from '../utils/clients/CognitoIdentityProvider/types'; -import { tokenOrchestrator } from '../tokenProvider'; -import { dispatchSignedInHubEvent } from '../utils/dispatchSignedInHubEvent'; +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; /** * Continues or completes the sign in process when required by the initial call to `signIn`. @@ -113,11 +113,12 @@ export async function confirmSignIn( await cacheCognitoTokens({ username, ...AuthenticationResult, - NewDeviceMetadata: await getNewDeviceMetatada( - authConfig.userPoolId, - AuthenticationResult.NewDeviceMetadata, - AuthenticationResult.AccessToken, - ), + NewDeviceMetadata: await getNewDeviceMetadata({ + userPoolId: authConfig.userPoolId, + userPoolEndpoint: authConfig.userPoolEndpoint, + newDeviceMetadata: AuthenticationResult.NewDeviceMetadata, + accessToken: AuthenticationResult.AccessToken, + }), signInDetails, }); diff --git a/packages/auth/src/providers/cognito/apis/confirmSignUp.ts b/packages/auth/src/providers/cognito/apis/confirmSignUp.ts index 62fdf93a82c..92adf180210 100644 --- a/packages/auth/src/providers/cognito/apis/confirmSignUp.ts +++ b/packages/auth/src/providers/cognito/apis/confirmSignUp.ts @@ -12,8 +12,7 @@ import { ConfirmSignUpInput, ConfirmSignUpOutput } from '../types'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { ConfirmSignUpException } from '../types/errors'; -import { confirmSignUp as confirmSignUpClient } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { AutoSignInEventData } from '../types/models'; import { isAutoSignInStarted, @@ -22,6 +21,8 @@ import { } from '../utils/signUpHelpers'; import { getAuthUserAgentValue } from '../../../utils'; import { getUserContextData } from '../utils/userContextData'; +import { createConfirmSignUpClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Confirms a new user account. @@ -41,7 +42,7 @@ export async function confirmSignUp( const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - const { userPoolId, userPoolClientId } = authConfig; + const { userPoolId, userPoolClientId, userPoolEndpoint } = authConfig; const clientMetadata = options?.clientMetadata; assertValidationError( !!username, @@ -58,9 +59,15 @@ export async function confirmSignUp( userPoolClientId, }); + const confirmSignUpClient = createConfirmSignUpClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + await confirmSignUpClient( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(authConfig.userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignUp), }, { diff --git a/packages/auth/src/providers/cognito/apis/confirmUserAttribute.ts b/packages/auth/src/providers/cognito/apis/confirmUserAttribute.ts index 951a97f2822..8c0c4dba1ad 100644 --- a/packages/auth/src/providers/cognito/apis/confirmUserAttribute.ts +++ b/packages/auth/src/providers/cognito/apis/confirmUserAttribute.ts @@ -9,12 +9,13 @@ import { import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; -import { verifyUserAttribute } from '../utils/clients/CognitoIdentityProvider'; import { VerifyUserAttributeException } from '../types/errors'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens } from '../utils/types'; import { ConfirmUserAttributeInput } from '../types'; import { getAuthUserAgentValue } from '../../../utils'; +import { createVerifyUserAttributeClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Confirms a user attribute with the confirmation code. @@ -30,6 +31,7 @@ export async function confirmUserAttribute( ): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { confirmationCode, userAttributeKey } = input; assertValidationError( !!confirmationCode, @@ -37,9 +39,14 @@ export async function confirmUserAttribute( ); const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const verifyUserAttribute = createVerifyUserAttributeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await verifyUserAttribute( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmUserAttribute), }, { diff --git a/packages/auth/src/providers/cognito/apis/deleteUser.ts b/packages/auth/src/providers/cognito/apis/deleteUser.ts index e14bde07f09..53c0c18c6dd 100644 --- a/packages/auth/src/providers/cognito/apis/deleteUser.ts +++ b/packages/auth/src/providers/cognito/apis/deleteUser.ts @@ -7,12 +7,13 @@ import { assertTokenProviderConfig, } from '@aws-amplify/core/internals/utils'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens } from '../utils/types'; -import { deleteUser as serviceDeleteUser } from '../utils/clients/CognitoIdentityProvider'; import { DeleteUserException } from '../types/errors'; import { tokenOrchestrator } from '../tokenProvider'; import { getAuthUserAgentValue } from '../../../utils'; +import { createDeleteUserClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; import { signOut } from './signOut'; @@ -25,13 +26,17 @@ import { signOut } from './signOut'; export async function deleteUser(): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession(); assertAuthTokens(tokens); - + const serviceDeleteUser = createDeleteUserClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await serviceDeleteUser( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.DeleteUser), }, { diff --git a/packages/auth/src/providers/cognito/apis/deleteUserAttributes.ts b/packages/auth/src/providers/cognito/apis/deleteUserAttributes.ts index 5812b656d60..b958dfacc1f 100644 --- a/packages/auth/src/providers/cognito/apis/deleteUserAttributes.ts +++ b/packages/auth/src/providers/cognito/apis/deleteUserAttributes.ts @@ -7,12 +7,13 @@ import { assertTokenProviderConfig, } from '@aws-amplify/core/internals/utils'; -import { deleteUserAttributes as deleteUserAttributesClient } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens } from '../utils/types'; import { DeleteUserAttributesInput } from '../types'; import { DeleteUserAttributesException } from '../types/errors'; import { getAuthUserAgentValue } from '../../../utils'; +import { createDeleteUserAttributesClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Deletes user attributes. @@ -27,11 +28,17 @@ export async function deleteUserAttributes( const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); const { userAttributeKeys } = input; + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const deleteUserAttributesClient = createDeleteUserAttributesClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await deleteUserAttributesClient( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.DeleteUserAttributes), }, { diff --git a/packages/auth/src/providers/cognito/apis/fetchDevices.ts b/packages/auth/src/providers/cognito/apis/fetchDevices.ts index 29be20e7a78..c0dc69f22f4 100644 --- a/packages/auth/src/providers/cognito/apis/fetchDevices.ts +++ b/packages/auth/src/providers/cognito/apis/fetchDevices.ts @@ -8,12 +8,13 @@ import { } from '@aws-amplify/core/internals/utils'; import { FetchDevicesOutput } from '../types'; -import { listDevices } from '../utils/clients/CognitoIdentityProvider'; -import { DeviceType } from '../utils/clients/CognitoIdentityProvider/types'; +import { DeviceType } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { assertAuthTokens } from '../utils/types'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { rememberDevice } from '..'; import { getAuthUserAgentValue } from '../../../utils'; +import { createListDevicesClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; // Cognito Documentation for max device // https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListDevices.html#API_ListDevices_RequestSyntax @@ -30,13 +31,17 @@ const MAX_DEVICES = 60; export async function fetchDevices(): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession(); assertAuthTokens(tokens); - + const listDevices = createListDevicesClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const response = await listDevices( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.FetchDevices), }, { diff --git a/packages/auth/src/providers/cognito/apis/fetchMFAPreference.ts b/packages/auth/src/providers/cognito/apis/fetchMFAPreference.ts index ef42d34f72f..e6da216ba81 100644 --- a/packages/auth/src/providers/cognito/apis/fetchMFAPreference.ts +++ b/packages/auth/src/providers/cognito/apis/fetchMFAPreference.ts @@ -10,10 +10,11 @@ import { import { FetchMFAPreferenceOutput } from '../types'; import { getMFAType, getMFATypes } from '../utils/signInHelpers'; import { GetUserException } from '../types/errors'; -import { getUser } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens } from '../utils/types'; import { getAuthUserAgentValue } from '../../../utils'; +import { createGetUserClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Fetches the preferred MFA setting and enabled MFA settings for the user. @@ -26,11 +27,17 @@ import { getAuthUserAgentValue } from '../../../utils'; export async function fetchMFAPreference(): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const getUser = createGetUserClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { PreferredMfaSetting, UserMFASettingList } = await getUser( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.FetchMFAPreference), }, { diff --git a/packages/auth/src/providers/cognito/apis/forgetDevice.ts b/packages/auth/src/providers/cognito/apis/forgetDevice.ts index 66dd3488f7b..b1ca574e1e4 100644 --- a/packages/auth/src/providers/cognito/apis/forgetDevice.ts +++ b/packages/auth/src/providers/cognito/apis/forgetDevice.ts @@ -7,13 +7,14 @@ import { assertTokenProviderConfig, } from '@aws-amplify/core/internals/utils'; -import { forgetDevice as serviceForgetDevice } from '../utils/clients/CognitoIdentityProvider'; import { assertAuthTokens, assertDeviceMetadata } from '../utils/types'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { tokenOrchestrator } from '../tokenProvider'; import { ForgetDeviceInput } from '../types'; import { ForgetDeviceException } from '../../cognito/types/errors'; import { getAuthUserAgentValue } from '../../../utils'; +import { createForgetDeviceClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Forget a remembered device while authenticated. @@ -27,17 +28,21 @@ export async function forgetDevice(input?: ForgetDeviceInput): Promise { const { device: { id: externalDeviceKey } = { id: undefined } } = input ?? {}; const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession(); assertAuthTokens(tokens); const deviceMetadata = await tokenOrchestrator.getDeviceMetadata(); const currentDeviceKey = deviceMetadata?.deviceKey; if (!externalDeviceKey) assertDeviceMetadata(deviceMetadata); - + const serviceForgetDevice = createForgetDeviceClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await serviceForgetDevice( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ForgetDevice), }, { diff --git a/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts b/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts index c1e4e9dd008..01230bf5153 100644 --- a/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts +++ b/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts @@ -8,26 +8,32 @@ import { fetchAuthSession, } from '@aws-amplify/core/internals/utils'; -import { getUser } from '../../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../../foundation/parsers'; import { assertAuthTokens } from '../../utils/types'; import { FetchUserAttributesOutput } from '../../types'; import { toAuthUserAttribute } from '../../utils/apiHelpers'; import { getAuthUserAgentValue } from '../../../../utils'; +import { createGetUserClient } from '../../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../../factories'; export const fetchUserAttributes = async ( amplify: AmplifyClassV6, ): Promise => { const authConfig = amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession(amplify, { forceRefresh: false, }); assertAuthTokens(tokens); - + const getUser = createGetUserClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { UserAttributes } = await getUser( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.FetchUserAttributes), }, { diff --git a/packages/auth/src/providers/cognito/apis/rememberDevice.ts b/packages/auth/src/providers/cognito/apis/rememberDevice.ts index 218b7b533e6..eb24022096e 100644 --- a/packages/auth/src/providers/cognito/apis/rememberDevice.ts +++ b/packages/auth/src/providers/cognito/apis/rememberDevice.ts @@ -7,12 +7,13 @@ import { assertTokenProviderConfig, } from '@aws-amplify/core/internals/utils'; -import { updateDeviceStatus } from '../utils/clients/CognitoIdentityProvider'; import { assertAuthTokens, assertDeviceMetadata } from '../utils/types'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { tokenOrchestrator } from '../tokenProvider'; import { UpdateDeviceStatusException } from '../../cognito/types/errors'; import { getAuthUserAgentValue } from '../../../utils'; +import { createUpdateDeviceStatusClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Marks device as remembered while authenticated. @@ -24,16 +25,20 @@ import { getAuthUserAgentValue } from '../../../utils'; export async function rememberDevice(): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession(); assertAuthTokens(tokens); const deviceMetadata = await tokenOrchestrator?.getDeviceMetadata(); assertDeviceMetadata(deviceMetadata); - + const updateDeviceStatus = createUpdateDeviceStatusClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await updateDeviceStatus( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.RememberDevice), }, { diff --git a/packages/auth/src/providers/cognito/apis/resendSignUpCode.ts b/packages/auth/src/providers/cognito/apis/resendSignUpCode.ts index 99ef3996f52..cdda7b980eb 100644 --- a/packages/auth/src/providers/cognito/apis/resendSignUpCode.ts +++ b/packages/auth/src/providers/cognito/apis/resendSignUpCode.ts @@ -12,11 +12,12 @@ import { AuthDeliveryMedium } from '../../../types'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { ResendSignUpCodeInput, ResendSignUpCodeOutput } from '../types'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; -import { resendConfirmationCode } from '../utils/clients/CognitoIdentityProvider'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { getAuthUserAgentValue } from '../../../utils'; import { getUserContextData } from '../utils/userContextData'; import { ResendConfirmationException } from '../types/errors'; +import { createResendConfirmationCodeClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Resend the confirmation code while signing up @@ -37,7 +38,7 @@ export async function resendSignUpCode( ); const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - const { userPoolClientId, userPoolId } = authConfig; + const { userPoolClientId, userPoolId, userPoolEndpoint } = authConfig; const clientMetadata = input.options?.clientMetadata; const UserContextData = getUserContextData({ @@ -45,10 +46,14 @@ export async function resendSignUpCode( userPoolId, userPoolClientId, }); - + const resendConfirmationCode = createResendConfirmationCodeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { CodeDeliveryDetails } = await resendConfirmationCode( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(authConfig.userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ResendSignUpCode), }, { diff --git a/packages/auth/src/providers/cognito/apis/resetPassword.ts b/packages/auth/src/providers/cognito/apis/resetPassword.ts index 273a77d413d..cd6d37a39ca 100644 --- a/packages/auth/src/providers/cognito/apis/resetPassword.ts +++ b/packages/auth/src/providers/cognito/apis/resetPassword.ts @@ -12,11 +12,12 @@ import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { AuthDeliveryMedium } from '../../../types'; import { ResetPasswordInput, ResetPasswordOutput } from '../types'; -import { forgotPassword } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { ForgotPasswordException } from '../../cognito/types/errors'; import { getAuthUserAgentValue } from '../../../utils'; import { getUserContextData } from '../utils/userContextData'; +import { createForgotPasswordClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Resets a user's password. @@ -39,7 +40,7 @@ export async function resetPassword( ); const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); - const { userPoolClientId, userPoolId } = authConfig; + const { userPoolClientId, userPoolId, userPoolEndpoint } = authConfig; const clientMetadata = input.options?.clientMetadata; const UserContextData = getUserContextData({ @@ -48,15 +49,20 @@ export async function resetPassword( userPoolClientId, }); + const forgotPassword = createForgotPasswordClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const res = await forgotPassword( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ResetPassword), }, { Username: username, ClientMetadata: clientMetadata, - ClientId: authConfig.userPoolClientId, + ClientId: userPoolClientId, UserContextData, }, ); diff --git a/packages/auth/src/providers/cognito/apis/sendUserAttributeVerificationCode.ts b/packages/auth/src/providers/cognito/apis/sendUserAttributeVerificationCode.ts index 55e5a8b5a84..4b04b2a85d1 100644 --- a/packages/auth/src/providers/cognito/apis/sendUserAttributeVerificationCode.ts +++ b/packages/auth/src/providers/cognito/apis/sendUserAttributeVerificationCode.ts @@ -13,11 +13,12 @@ import { SendUserAttributeVerificationCodeInput, SendUserAttributeVerificationCodeOutput, } from '../types'; -import { getUserAttributeVerificationCode } from '../utils/clients/CognitoIdentityProvider'; import { assertAuthTokens } from '../utils/types'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { GetUserAttributeVerificationException } from '../types/errors'; import { getAuthUserAgentValue } from '../../../utils'; +import { createGetUserAttributeVerificationCodeClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Resends user's confirmation code when updating attributes while authenticated. @@ -34,11 +35,18 @@ export const sendUserAttributeVerificationCode = async ( const authConfig = Amplify.getConfig().Auth?.Cognito; const clientMetadata = options?.clientMetadata; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const getUserAttributeVerificationCode = + createGetUserAttributeVerificationCodeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { CodeDeliveryDetails } = await getUserAttributeVerificationCode( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue( AuthAction.SendUserAttributeVerificationCode, ), diff --git a/packages/auth/src/providers/cognito/apis/setUpTOTP.ts b/packages/auth/src/providers/cognito/apis/setUpTOTP.ts index e99b8618995..43dac4c787b 100644 --- a/packages/auth/src/providers/cognito/apis/setUpTOTP.ts +++ b/packages/auth/src/providers/cognito/apis/setUpTOTP.ts @@ -14,10 +14,11 @@ import { } from '../types/errors'; import { SetUpTOTPOutput } from '../types'; import { getTOTPSetupDetails } from '../utils/signInHelpers'; -import { associateSoftwareToken } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens } from '../utils/types'; import { getAuthUserAgentValue } from '../../../utils'; +import { createAssociateSoftwareTokenClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Sets up TOTP for the user. @@ -30,12 +31,18 @@ import { getAuthUserAgentValue } from '../../../utils'; export async function setUpTOTP(): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); const username = tokens.idToken?.payload['cognito:username'] ?? ''; + const associateSoftwareToken = createAssociateSoftwareTokenClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { SecretCode } = await associateSoftwareToken( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SetUpTOTP), }, { diff --git a/packages/auth/src/providers/cognito/apis/signInWithCustomAuth.ts b/packages/auth/src/providers/cognito/apis/signInWithCustomAuth.ts index e55e3f0a50d..a666fba0acb 100644 --- a/packages/auth/src/providers/cognito/apis/signInWithCustomAuth.ts +++ b/packages/auth/src/providers/cognito/apis/signInWithCustomAuth.ts @@ -9,7 +9,7 @@ import { assertValidationError } from '../../../errors/utils/assertValidationErr import { assertServiceError } from '../../../errors/utils/assertServiceError'; import { getActiveSignInUsername, - getNewDeviceMetatada, + getNewDeviceMetadata, getSignInResult, getSignInResultFromError, handleCustomAuthFlowWithoutSRP, @@ -29,7 +29,7 @@ import { cacheCognitoTokens } from '../tokenProvider/cacheTokens'; import { ChallengeName, ChallengeParameters, -} from '../utils/clients/CognitoIdentityProvider/types'; +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { tokenOrchestrator } from '../tokenProvider'; import { dispatchSignedInHubEvent } from '../utils/dispatchSignedInHubEvent'; @@ -89,11 +89,12 @@ export async function signInWithCustomAuth( await cacheCognitoTokens({ username: activeUsername, ...AuthenticationResult, - NewDeviceMetadata: await getNewDeviceMetatada( - authConfig.userPoolId, - AuthenticationResult.NewDeviceMetadata, - AuthenticationResult.AccessToken, - ), + NewDeviceMetadata: await getNewDeviceMetadata({ + userPoolId: authConfig.userPoolId, + userPoolEndpoint: authConfig.userPoolEndpoint, + newDeviceMetadata: AuthenticationResult.NewDeviceMetadata, + accessToken: AuthenticationResult.AccessToken, + }), signInDetails, }); diff --git a/packages/auth/src/providers/cognito/apis/signInWithCustomSRPAuth.ts b/packages/auth/src/providers/cognito/apis/signInWithCustomSRPAuth.ts index a67fa9f861c..a22f98b3804 100644 --- a/packages/auth/src/providers/cognito/apis/signInWithCustomSRPAuth.ts +++ b/packages/auth/src/providers/cognito/apis/signInWithCustomSRPAuth.ts @@ -9,7 +9,7 @@ import { assertValidationError } from '../../../errors/utils/assertValidationErr import { assertServiceError } from '../../../errors/utils/assertServiceError'; import { getActiveSignInUsername, - getNewDeviceMetatada, + getNewDeviceMetadata, getSignInResult, getSignInResultFromError, handleCustomSRPAuthFlow, @@ -31,7 +31,7 @@ import { cacheCognitoTokens } from '../tokenProvider/cacheTokens'; import { ChallengeName, ChallengeParameters, -} from '../utils/clients/CognitoIdentityProvider/types'; +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { tokenOrchestrator } from '../tokenProvider'; import { dispatchSignedInHubEvent } from '../utils/dispatchSignedInHubEvent'; @@ -92,11 +92,12 @@ export async function signInWithCustomSRPAuth( await cacheCognitoTokens({ username: activeUsername, ...AuthenticationResult, - NewDeviceMetadata: await getNewDeviceMetatada( - authConfig.userPoolId, - AuthenticationResult.NewDeviceMetadata, - AuthenticationResult.AccessToken, - ), + NewDeviceMetadata: await getNewDeviceMetadata({ + userPoolId: authConfig.userPoolId, + userPoolEndpoint: authConfig.userPoolEndpoint, + newDeviceMetadata: AuthenticationResult.NewDeviceMetadata, + accessToken: AuthenticationResult.AccessToken, + }), signInDetails, }); cleanActiveSignInState(); diff --git a/packages/auth/src/providers/cognito/apis/signInWithSRP.ts b/packages/auth/src/providers/cognito/apis/signInWithSRP.ts index 32f0ca11b99..9bb8d4deca7 100644 --- a/packages/auth/src/providers/cognito/apis/signInWithSRP.ts +++ b/packages/auth/src/providers/cognito/apis/signInWithSRP.ts @@ -10,14 +10,14 @@ import { assertServiceError } from '../../../errors/utils/assertServiceError'; import { ChallengeName, ChallengeParameters, -} from '../utils/clients/CognitoIdentityProvider/types'; +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { InitiateAuthException, RespondToAuthChallengeException, } from '../types/errors'; import { getActiveSignInUsername, - getNewDeviceMetatada, + getNewDeviceMetadata, getSignInResult, getSignInResultFromError, handleUserSRPAuthFlow, @@ -93,11 +93,12 @@ export async function signInWithSRP( await cacheCognitoTokens({ username: activeUsername, ...AuthenticationResult, - NewDeviceMetadata: await getNewDeviceMetatada( - authConfig.userPoolId, - AuthenticationResult.NewDeviceMetadata, - AuthenticationResult.AccessToken, - ), + NewDeviceMetadata: await getNewDeviceMetadata({ + userPoolId: authConfig.userPoolId, + userPoolEndpoint: authConfig.userPoolEndpoint, + newDeviceMetadata: AuthenticationResult.NewDeviceMetadata, + accessToken: AuthenticationResult.AccessToken, + }), signInDetails, }); diff --git a/packages/auth/src/providers/cognito/apis/signInWithUserPassword.ts b/packages/auth/src/providers/cognito/apis/signInWithUserPassword.ts index e1de730cb1c..071f54f8313 100644 --- a/packages/auth/src/providers/cognito/apis/signInWithUserPassword.ts +++ b/packages/auth/src/providers/cognito/apis/signInWithUserPassword.ts @@ -10,10 +10,10 @@ import { assertValidationError } from '../../../errors/utils/assertValidationErr import { ChallengeName, ChallengeParameters, -} from '../utils/clients/CognitoIdentityProvider/types'; +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { getActiveSignInUsername, - getNewDeviceMetatada, + getNewDeviceMetadata, getSignInResult, getSignInResultFromError, handleUserPasswordAuthFlow, @@ -87,11 +87,12 @@ export async function signInWithUserPassword( await cacheCognitoTokens({ ...AuthenticationResult, username: activeUsername, - NewDeviceMetadata: await getNewDeviceMetatada( - authConfig.userPoolId, - AuthenticationResult.NewDeviceMetadata, - AuthenticationResult.AccessToken, - ), + NewDeviceMetadata: await getNewDeviceMetadata({ + userPoolId: authConfig.userPoolId, + userPoolEndpoint: authConfig.userPoolEndpoint, + newDeviceMetadata: AuthenticationResult.NewDeviceMetadata, + accessToken: AuthenticationResult.AccessToken, + }), signInDetails, }); cleanActiveSignInState(); diff --git a/packages/auth/src/providers/cognito/apis/signOut.ts b/packages/auth/src/providers/cognito/apis/signOut.ts index 65be0162927..2fa52b73ee4 100644 --- a/packages/auth/src/providers/cognito/apis/signOut.ts +++ b/packages/auth/src/providers/cognito/apis/signOut.ts @@ -20,11 +20,7 @@ import { import { getAuthUserAgentValue } from '../../../utils'; import { SignOutInput } from '../types'; import { tokenOrchestrator } from '../tokenProvider'; -import { - globalSignOut as globalSignOutClient, - revokeToken, -} from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens, assertAuthTokensWithRefreshToken, @@ -33,6 +29,11 @@ import { handleOAuthSignOut } from '../utils/oauth'; import { DefaultOAuthStore } from '../utils/signInWithRedirectStore'; import { AuthError } from '../../../errors/AuthError'; import { OAUTH_SIGNOUT_EXCEPTION } from '../../../errors/constants'; +import { + createGlobalSignOutClient, + createRevokeTokenClient, +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; const logger = new ConsoleLogger('Auth'); @@ -60,17 +61,20 @@ export async function signOut(input?: SignOutInput): Promise { } catch (err) { hasOAuthConfig = false; } - if (hasOAuthConfig) { const oAuthStore = new DefaultOAuthStore(defaultStorage); oAuthStore.setAuthConfig(cognitoConfig); const { type } = - (await handleOAuthSignOut(cognitoConfig, oAuthStore)) ?? {}; + (await handleOAuthSignOut( + cognitoConfig, + oAuthStore, + tokenOrchestrator, + input?.oauth?.redirectUrl, + )) ?? {}; if (type === 'error') { throw new AuthError({ name: OAUTH_SIGNOUT_EXCEPTION, - message: - 'An error occurred when attempting to log out from OAuth provider.', + message: `An error occurred when attempting to log out from OAuth provider.`, }); } } else { @@ -83,16 +87,23 @@ export async function signOut(input?: SignOutInput): Promise { async function clientSignOut(cognitoConfig: CognitoUserPoolConfig) { try { + const { userPoolEndpoint, userPoolId, userPoolClientId } = cognitoConfig; const authTokens = await tokenOrchestrator.getTokenStore().loadTokens(); assertAuthTokensWithRefreshToken(authTokens); if (isSessionRevocable(authTokens.accessToken)) { + const revokeToken = createRevokeTokenClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + await revokeToken( { - region: getRegion(cognitoConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SignOut), }, { - ClientId: cognitoConfig.userPoolClientId, + ClientId: userPoolClientId, Token: authTokens.refreshToken, }, ); @@ -107,11 +118,17 @@ async function clientSignOut(cognitoConfig: CognitoUserPoolConfig) { async function globalSignOut(cognitoConfig: CognitoUserPoolConfig) { try { + const { userPoolEndpoint, userPoolId } = cognitoConfig; const authTokens = await tokenOrchestrator.getTokenStore().loadTokens(); assertAuthTokens(authTokens); + const globalSignOutClient = createGlobalSignOutClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await globalSignOutClient( { - region: getRegion(cognitoConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SignOut), }, { diff --git a/packages/auth/src/providers/cognito/apis/signUp.ts b/packages/auth/src/providers/cognito/apis/signUp.ts index ef9aef32fa2..3ec246648f5 100644 --- a/packages/auth/src/providers/cognito/apis/signUp.ts +++ b/packages/auth/src/providers/cognito/apis/signUp.ts @@ -10,11 +10,10 @@ import { import { AuthDeliveryMedium } from '../../../types'; import { SignInInput, SignUpInput, SignUpOutput } from '../types'; -import { signUp as signUpClient } from '../utils/clients/CognitoIdentityProvider'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { SignUpException } from '../types/errors'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { toAttributeType } from '../utils/apiHelpers'; import { autoSignInUserConfirmed, @@ -27,6 +26,8 @@ import { } from '../utils/signUpHelpers'; import { getUserContextData } from '../utils/userContextData'; import { getAuthUserAgentValue } from '../../../utils'; +import { createSignUpClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; import { setAutoSignIn } from './autoSignIn'; @@ -72,11 +73,15 @@ export async function signUp(input: SignUpInput): Promise { setAutoSignInStarted(true); } - const { userPoolId, userPoolClientId } = authConfig; - + const { userPoolId, userPoolClientId, userPoolEndpoint } = authConfig; + const signUpClient = createSignUpClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const clientOutput = await signUpClient( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SignUp), }, { diff --git a/packages/auth/src/providers/cognito/apis/updateMFAPreference.ts b/packages/auth/src/providers/cognito/apis/updateMFAPreference.ts index 790cc82f8bd..5f87522af5a 100644 --- a/packages/auth/src/providers/cognito/apis/updateMFAPreference.ts +++ b/packages/auth/src/providers/cognito/apis/updateMFAPreference.ts @@ -10,11 +10,12 @@ import { import { UpdateMFAPreferenceInput } from '../types'; import { SetUserMFAPreferenceException } from '../types/errors'; import { MFAPreference } from '../types/models'; -import { setUserMFAPreference } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; -import { CognitoMFASettings } from '../utils/clients/CognitoIdentityProvider/types'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; +import { CognitoMFASettings } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { assertAuthTokens } from '../utils/types'; import { getAuthUserAgentValue } from '../../../utils'; +import { createSetUserMFAPreferenceClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Updates the MFA preference of the user. @@ -29,11 +30,17 @@ export async function updateMFAPreference( const { sms, totp } = input; const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const setUserMFAPreference = createSetUserMFAPreferenceClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await setUserMFAPreference( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.UpdateMFAPreference), }, { diff --git a/packages/auth/src/providers/cognito/apis/updatePassword.ts b/packages/auth/src/providers/cognito/apis/updatePassword.ts index 0f83fc9f1df..f8c8c4bdeae 100644 --- a/packages/auth/src/providers/cognito/apis/updatePassword.ts +++ b/packages/auth/src/providers/cognito/apis/updatePassword.ts @@ -10,11 +10,12 @@ import { import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { UpdatePasswordInput } from '../types'; -import { changePassword } from '../utils/clients/CognitoIdentityProvider'; import { ChangePasswordException } from '../../cognito/types/errors'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens } from '../utils/types'; import { getAuthUserAgentValue } from '../../../utils'; +import { createChangePasswordClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Updates user's password while authenticated. @@ -29,6 +30,7 @@ export async function updatePassword( ): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { oldPassword, newPassword } = input; assertValidationError( !!oldPassword, @@ -41,9 +43,14 @@ export async function updatePassword( ); const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const changePassword = createChangePasswordClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await changePassword( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.UpdatePassword), }, { diff --git a/packages/auth/src/providers/cognito/apis/updateUserAttributes.ts b/packages/auth/src/providers/cognito/apis/updateUserAttributes.ts index b0e6cc7f3f7..5076e3145a5 100644 --- a/packages/auth/src/providers/cognito/apis/updateUserAttributes.ts +++ b/packages/auth/src/providers/cognito/apis/updateUserAttributes.ts @@ -16,13 +16,14 @@ import { UpdateUserAttributesInput, UpdateUserAttributesOutput, } from '../types'; -import { updateUserAttributes as updateUserAttributesClient } from '../utils/clients/CognitoIdentityProvider'; import { assertAuthTokens } from '../utils/types'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { toAttributeType } from '../utils/apiHelpers'; -import { CodeDeliveryDetailsType } from '../utils/clients/CognitoIdentityProvider/types'; +import { CodeDeliveryDetailsType } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { UpdateUserAttributesException } from '../types/errors'; import { getAuthUserAgentValue } from '../../../utils'; +import { createUpdateUserAttributesClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Updates user's attributes while authenticated. @@ -39,11 +40,17 @@ export const updateUserAttributes = async ( const authConfig = Amplify.getConfig().Auth?.Cognito; const clientMetadata = options?.clientMetadata; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const updateUserAttributesClient = createUpdateUserAttributesClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { CodeDeliveryDetailsList } = await updateUserAttributesClient( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.UpdateUserAttributes), }, { diff --git a/packages/auth/src/providers/cognito/apis/verifyTOTPSetup.ts b/packages/auth/src/providers/cognito/apis/verifyTOTPSetup.ts index 66c68fe9690..c5c1212c194 100644 --- a/packages/auth/src/providers/cognito/apis/verifyTOTPSetup.ts +++ b/packages/auth/src/providers/cognito/apis/verifyTOTPSetup.ts @@ -10,11 +10,12 @@ import { import { AuthValidationErrorCode } from '../../../errors/types/validation'; import { assertValidationError } from '../../../errors/utils/assertValidationError'; import { VerifyTOTPSetupInput } from '../types'; -import { verifySoftwareToken } from '../utils/clients/CognitoIdentityProvider'; import { VerifySoftwareTokenException } from '../types/errors'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokens } from '../utils/types'; import { getAuthUserAgentValue } from '../../../utils'; +import { createVerifySoftwareTokenClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; /** * Verifies an OTP code retrieved from an associated authentication app. @@ -31,6 +32,7 @@ export async function verifyTOTPSetup( ): Promise { const authConfig = Amplify.getConfig().Auth?.Cognito; assertTokenProviderConfig(authConfig); + const { userPoolEndpoint, userPoolId } = authConfig; const { code, options } = input; assertValidationError( !!code, @@ -38,9 +40,14 @@ export async function verifyTOTPSetup( ); const { tokens } = await fetchAuthSession({ forceRefresh: false }); assertAuthTokens(tokens); + const verifySoftwareToken = createVerifySoftwareTokenClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await verifySoftwareToken( { - region: getRegion(authConfig.userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.VerifyTOTPSetup), }, { diff --git a/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdProvider.ts b/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdProvider.ts index 4a8614a3db0..b96adf08fbc 100644 --- a/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdProvider.ts +++ b/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdProvider.ts @@ -5,7 +5,7 @@ import { AuthTokens, ConsoleLogger, Identity, getId } from '@aws-amplify/core'; import { CognitoIdentityPoolConfig } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../errors/AuthError'; -import { getRegionFromIdentityPoolId } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromIdentityPoolId } from '../../../foundation/parsers'; import { GetIdException } from '../types/errors'; import { IdentityIdStore } from './types'; diff --git a/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdStore.ts b/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdStore.ts index ec4bc9ef6b4..283b0e9cd3f 100644 --- a/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdStore.ts +++ b/packages/auth/src/providers/cognito/credentialsProvider/IdentityIdStore.ts @@ -23,6 +23,8 @@ export class DefaultIdentityIdStore implements IdentityIdStore { // Used as in-memory storage _primaryIdentityId: string | undefined; _authKeys: AuthKeys = {}; + _hasGuestIdentityId = false; + setAuthConfig(authConfigParam: AuthConfig) { assertIdentityPoolIdConfig(authConfigParam.Cognito); this.authConfig = authConfigParam; @@ -48,7 +50,10 @@ export class DefaultIdentityIdStore implements IdentityIdStore { const storedIdentityId = await this.keyValueStorage.getItem( this._authKeys.identityId, ); + if (storedIdentityId) { + this._hasGuestIdentityId = true; + return { id: storedIdentityId, type: 'guest', @@ -71,10 +76,14 @@ export class DefaultIdentityIdStore implements IdentityIdStore { this.keyValueStorage.setItem(this._authKeys.identityId, identity.id); // Clear in-memory storage of primary identityId this._primaryIdentityId = undefined; + this._hasGuestIdentityId = true; } else { this._primaryIdentityId = identity.id; // Clear locally stored guest id - this.keyValueStorage.removeItem(this._authKeys.identityId); + if (this._hasGuestIdentityId) { + this.keyValueStorage.removeItem(this._authKeys.identityId); + this._hasGuestIdentityId = false; + } } } diff --git a/packages/auth/src/providers/cognito/credentialsProvider/credentialsProvider.ts b/packages/auth/src/providers/cognito/credentialsProvider/credentialsProvider.ts index fd02d349513..6356ff0fd09 100644 --- a/packages/auth/src/providers/cognito/credentialsProvider/credentialsProvider.ts +++ b/packages/auth/src/providers/cognito/credentialsProvider/credentialsProvider.ts @@ -15,7 +15,7 @@ import { } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../errors/AuthError'; -import { getRegionFromIdentityPoolId } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromIdentityPoolId } from '../../../foundation/parsers'; import { assertIdTokenInAuthTokens } from '../utils/types'; import { IdentityIdStore } from './types'; diff --git a/packages/auth/src/providers/cognito/factories/createCognitoUserPoolEndpointResolver.ts b/packages/auth/src/providers/cognito/factories/createCognitoUserPoolEndpointResolver.ts new file mode 100644 index 00000000000..42a5b979402 --- /dev/null +++ b/packages/auth/src/providers/cognito/factories/createCognitoUserPoolEndpointResolver.ts @@ -0,0 +1,16 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { EndpointResolverOptions } from '@aws-amplify/core/internals/aws-client-utils'; +import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; + +import { cognitoUserPoolEndpointResolver } from '../../../foundation/cognitoUserPoolEndpointResolver'; + +export const createCognitoUserPoolEndpointResolver = + ({ endpointOverride }: { endpointOverride: string | undefined }) => + (input: EndpointResolverOptions): { url: URL } => { + if (endpointOverride) { + return { url: new AmplifyUrl(endpointOverride) }; + } + + return cognitoUserPoolEndpointResolver(input); + }; diff --git a/packages/auth/src/providers/cognito/factories/index.ts b/packages/auth/src/providers/cognito/factories/index.ts new file mode 100644 index 00000000000..7f8050064d3 --- /dev/null +++ b/packages/auth/src/providers/cognito/factories/index.ts @@ -0,0 +1,3 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +export { createCognitoUserPoolEndpointResolver } from './createCognitoUserPoolEndpointResolver'; diff --git a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts index 0e16a021969..121875013e2 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts @@ -25,6 +25,7 @@ import { AuthTokenStore, CognitoAuthTokens, DeviceMetadata, + OAuthMetadata, TokenRefresher, } from './types'; @@ -203,4 +204,12 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { clearDeviceMetadata(username?: string): Promise { return this.getTokenStore().clearDeviceMetadata(username); } + + setOAuthMetadata(metadata: OAuthMetadata): Promise { + return this.getTokenStore().setOAuthMetadata(metadata); + } + + getOAuthMetadata(): Promise { + return this.getTokenStore().getOAuthMetadata(); + } } diff --git a/packages/auth/src/providers/cognito/tokenProvider/TokenStore.ts b/packages/auth/src/providers/cognito/tokenProvider/TokenStore.ts index 53ac3228d85..74d6b9400c6 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/TokenStore.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/TokenStore.ts @@ -14,6 +14,7 @@ import { AuthTokenStore, CognitoAuthTokens, DeviceMetadata, + OAuthMetadata, } from './types'; import { TokenProviderErrorCode, assert } from './errorHelpers'; @@ -163,6 +164,7 @@ export class DefaultTokenStore implements AuthTokenStore { this.getKeyValueStorage().removeItem(authKeys.refreshToken), this.getKeyValueStorage().removeItem(authKeys.signInDetails), this.getKeyValueStorage().removeItem(this.getLastAuthUserKey()), + this.getKeyValueStorage().removeItem(authKeys.oauthMetadata), ]); } @@ -222,6 +224,22 @@ export class DefaultTokenStore implements AuthTokenStore { return lastAuthUser; } + + async setOAuthMetadata(metadata: OAuthMetadata): Promise { + const { oauthMetadata: oauthMetadataKey } = await this.getAuthKeys(); + await this.getKeyValueStorage().setItem( + oauthMetadataKey, + JSON.stringify(metadata), + ); + } + + async getOAuthMetadata(): Promise { + const { oauthMetadata: oauthMetadataKey } = await this.getAuthKeys(); + const oauthMetadata = + await this.getKeyValueStorage().getItem(oauthMetadataKey); + + return oauthMetadata && JSON.parse(oauthMetadata); + } } export const createKeysForAuthStorage = ( diff --git a/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts b/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts index 198ec6c4283..0be44aeb697 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts @@ -3,7 +3,7 @@ import { AmplifyError, decodeJWT } from '@aws-amplify/core/internals/utils'; import { CognitoAuthSignInDetails } from '../types'; -import { AuthenticationResultType } from '../utils/clients/CognitoIdentityProvider/types'; +import { AuthenticationResultType } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; import { tokenOrchestrator } from './tokenProvider'; import { CognitoAuthTokens, DeviceMetadata } from './types'; diff --git a/packages/auth/src/providers/cognito/tokenProvider/types.ts b/packages/auth/src/providers/cognito/tokenProvider/types.ts index f58483a334b..5db7c62f012 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/types.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/types.ts @@ -34,6 +34,7 @@ export const AuthTokenStorageKeys = { randomPasswordKey: 'randomPasswordKey', deviceGroupKey: 'deviceGroupKey', signInDetails: 'signInDetails', + oauthMetadata: 'oauthMetadata', }; export interface AuthTokenStore { @@ -44,6 +45,8 @@ export interface AuthTokenStore { setKeyValueStorage(keyValueStorage: KeyValueStorageInterface): void; getDeviceMetadata(username?: string): Promise; clearDeviceMetadata(username?: string): Promise; + setOAuthMetadata(metadata: OAuthMetadata): Promise; + getOAuthMetadata(): Promise; } export interface AuthTokenOrchestrator { @@ -58,6 +61,8 @@ export interface AuthTokenOrchestrator { clearTokens(): Promise; getDeviceMetadata(username?: string): Promise; clearDeviceMetadata(username?: string): Promise; + setOAuthMetadata(metadata: OAuthMetadata): Promise; + getOAuthMetadata(): Promise; } export interface CognitoUserPoolTokenProviderType extends TokenProvider { @@ -78,3 +83,7 @@ export interface DeviceMetadata { deviceGroupKey?: string; randomPassword: string; } + +export interface OAuthMetadata { + oauthSignIn: boolean; +} diff --git a/packages/auth/src/providers/cognito/utils/apiHelpers.ts b/packages/auth/src/providers/cognito/utils/apiHelpers.ts index 5ddd544513c..70da22165a5 100644 --- a/packages/auth/src/providers/cognito/utils/apiHelpers.ts +++ b/packages/auth/src/providers/cognito/utils/apiHelpers.ts @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { AuthUserAttributes } from '../../../types'; - -import { AttributeType } from './clients/CognitoIdentityProvider/types'; +import { AttributeType } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; /** * Transforms a user attributes object into an array of AttributeType objects. diff --git a/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/base.ts b/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/base.ts deleted file mode 100644 index cff58009b87..00000000000 --- a/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/base.ts +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import { Amplify } from '@aws-amplify/core'; -import { - Endpoint, - EndpointResolverOptions, - Headers, - HttpRequest, - HttpResponse, - Middleware, - getDnsSuffix, - getRetryDecider, - jitteredBackoff, - parseJsonError, - unauthenticatedHandler, -} from '@aws-amplify/core/internals/aws-client-utils'; -import { - AmplifyUrl, - getAmplifyUserAgent, -} from '@aws-amplify/core/internals/utils'; -import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; - -/** - * The service name used to sign requests if the API requires authentication. - */ -const SERVICE_NAME = 'cognito-idp'; - -/** - * The endpoint resolver function that returns the endpoint URL for a given region. - */ -const endpointResolver = ({ region }: EndpointResolverOptions) => { - const authConfig = Amplify.getConfig().Auth?.Cognito; - const customURL = authConfig?.userPoolEndpoint; - const defaultURL = new AmplifyUrl( - `https://${SERVICE_NAME}.${region}.${getDnsSuffix(region)}`, - ); - - return { - url: customURL ? new AmplifyUrl(customURL) : defaultURL, - }; -}; - -/** - * A Cognito Identity-specific middleware that disables caching for all requests. - */ -const disableCacheMiddlewareFactory: Middleware< - HttpRequest, - HttpResponse, - Record -> = () => (next, _) => - async function disableCacheMiddleware(request) { - request.headers['cache-control'] = 'no-store'; - - return next(request); - }; - -/** - * A Cognito Identity-specific transfer handler that does NOT sign requests, and - * disables caching. - * - * @internal - */ -export const cognitoUserPoolTransferHandler = composeTransferHandler< - [Parameters[0]], - HttpRequest, - HttpResponse, - typeof unauthenticatedHandler ->(unauthenticatedHandler, [disableCacheMiddlewareFactory]); - -/** - * @internal - */ -export const defaultConfig = { - service: SERVICE_NAME, - endpointResolver, - retryDecider: getRetryDecider(parseJsonError), - computeDelay: jitteredBackoff, - userAgentValue: getAmplifyUserAgent(), - cache: 'no-store', -}; - -/** - * @internal - */ -export const getSharedHeaders = (operation: string): Headers => ({ - 'content-type': 'application/x-amz-json-1.1', - 'x-amz-target': `AWSCognitoIdentityProviderService.${operation}`, -}); - -/** - * @internal - */ -export const buildHttpRpcRequest = ( - { url }: Endpoint, - headers: Headers, - body: string, -): HttpRequest => ({ - headers, - url, - body, - method: 'POST', -}); diff --git a/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/index.ts b/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/index.ts deleted file mode 100644 index 4ea8c01b599..00000000000 --- a/packages/auth/src/providers/cognito/utils/clients/CognitoIdentityProvider/index.ts +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; -import { - Endpoint, - HttpRequest, - HttpResponse, - parseJsonBody, - parseJsonError, -} from '@aws-amplify/core/internals/aws-client-utils'; - -import { assertServiceError } from '../../../../../errors/utils/assertServiceError'; -import { AuthError } from '../../../../../errors/AuthError'; - -import { - buildHttpRpcRequest, - cognitoUserPoolTransferHandler, - defaultConfig, - getSharedHeaders, -} from './base'; -import type { - AssociateSoftwareTokenCommandInput as AssociateSoftwareTokenInput, - AssociateSoftwareTokenCommandOutput as AssociateSoftwareTokenOutput, - ChangePasswordCommandInput as ChangePasswordInput, - ChangePasswordCommandOutput as ChangePasswordOutput, - ConfirmDeviceCommandInput as ConfirmDeviceInput, - ConfirmDeviceCommandOutput as ConfirmDeviceOutput, - ConfirmForgotPasswordCommandInput as ConfirmForgotPasswordInput, - ConfirmForgotPasswordCommandOutput as ConfirmForgotPasswordOutput, - ConfirmSignUpCommandInput as ConfirmSignUpInput, - ConfirmSignUpCommandOutput as ConfirmSignUpOutput, - DeleteUserAttributesCommandInput as DeleteUserAttributesInput, - DeleteUserAttributesCommandOutput as DeleteUserAttributesOutput, - DeleteUserCommandInput as DeleteUserInput, - DeleteUserCommandOutput as DeleteUserOutput, - ForgetDeviceCommandInput as ForgetDeviceInput, - ForgetDeviceCommandOutput as ForgetDeviceOutput, - ForgotPasswordCommandInput as ForgotPasswordInput, - ForgotPasswordCommandOutput as ForgotPasswordOutput, - GetUserAttributeVerificationCodeCommandInput as GetUserAttributeVerificationCodeInput, - GetUserAttributeVerificationCodeCommandOutput as GetUserAttributeVerificationCodeOutput, - GetUserCommandInput as GetUserInput, - GetUserCommandOutput as GetUserOutput, - GlobalSignOutCommandInput as GlobalSignOutInput, - GlobalSignOutCommandOutput as GlobalSignOutOutput, - InitiateAuthCommandInput as InitiateAuthInput, - InitiateAuthCommandOutput as InitiateAuthOutput, - ListDevicesCommandInput as ListDevicesInput, - ListDevicesCommandOutput as ListDevicesOutput, - ResendConfirmationCodeCommandInput as ResendConfirmationCodeInput, - ResendConfirmationCodeCommandOutput as ResendConfirmationCodeOutput, - RespondToAuthChallengeCommandInput as RespondToAuthChallengeInput, - RespondToAuthChallengeCommandOutput as RespondToAuthChallengeOutput, - SetUserMFAPreferenceCommandInput as SetUserMFAPreferenceInput, - SetUserMFAPreferenceCommandOutput as SetUserMFAPreferenceOutput, - SignUpCommandInput as SignUpInput, - SignUpCommandOutput as SignUpOutput, - UpdateDeviceStatusCommandInput as UpdateDeviceStatusInput, - UpdateDeviceStatusCommandOutput as UpdateDeviceStatusOutput, - UpdateUserAttributesCommandInput as UpdateUserAttributesInput, - UpdateUserAttributesCommandOutput as UpdateUserAttributesOutput, - VerifySoftwareTokenCommandInput as VerifySoftwareTokenInput, - VerifySoftwareTokenCommandOutput as VerifySoftwareTokenOutput, - VerifyUserAttributeCommandInput as VerifyUserAttributeInput, - VerifyUserAttributeCommandOutput as VerifyUserAttributeOutput, -} from './types'; - -interface RevokeTokenInput { - Token: string; - ClientId: string; -} - -type RevokeTokenOutput = Record; - -type ClientOperation = - | 'SignUp' - | 'ConfirmSignUp' - | 'ForgotPassword' - | 'ConfirmForgotPassword' - | 'InitiateAuth' - | 'RespondToAuthChallenge' - | 'ResendConfirmationCode' - | 'VerifySoftwareToken' - | 'AssociateSoftwareToken' - | 'SetUserMFAPreference' - | 'GetUser' - | 'ChangePassword' - | 'ConfirmDevice' - | 'ForgetDevice' - | 'DeleteUser' - | 'GetUserAttributeVerificationCode' - | 'GlobalSignOut' - | 'UpdateUserAttributes' - | 'VerifyUserAttribute' - | 'DeleteUserAttributes' - | 'UpdateDeviceStatus' - | 'ListDevices' - | 'RevokeToken'; - -const buildUserPoolSerializer = - (operation: ClientOperation) => - (input: Input, endpoint: Endpoint): HttpRequest => { - const headers = getSharedHeaders(operation); - const body = JSON.stringify(input); - - return buildHttpRpcRequest(endpoint, headers, body); - }; - -const buildUserPoolDeserializer = (): (( - response: HttpResponse, -) => Promise) => { - return async (response: HttpResponse): Promise => { - if (response.statusCode >= 300) { - const error = await parseJsonError(response); - assertServiceError(error); - throw new AuthError({ name: error.name, message: error.message }); - } else { - const body = await parseJsonBody(response); - - return body; - } - }; -}; - -const handleEmptyResponseDeserializer = (): (( - response: HttpResponse, -) => Promise) => { - return async (response: HttpResponse): Promise => { - if (response.statusCode >= 300) { - const error = await parseJsonError(response); - assertServiceError(error); - throw new AuthError({ name: error.name, message: error.message }); - } else { - return undefined as any; - } - }; -}; - -export const initiateAuth = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('InitiateAuth'), - buildUserPoolDeserializer(), - defaultConfig, -); - -export const revokeToken = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('RevokeToken'), - buildUserPoolDeserializer(), - defaultConfig, -); - -export const signUp = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('SignUp'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const confirmSignUp = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('ConfirmSignUp'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const forgotPassword = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('ForgotPassword'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const confirmForgotPassword = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('ConfirmForgotPassword'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const respondToAuthChallenge = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer( - 'RespondToAuthChallenge', - ), - buildUserPoolDeserializer(), - defaultConfig, -); -export const resendConfirmationCode = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer( - 'ResendConfirmationCode', - ), - buildUserPoolDeserializer(), - defaultConfig, -); -export const verifySoftwareToken = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('VerifySoftwareToken'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const associateSoftwareToken = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer( - 'AssociateSoftwareToken', - ), - buildUserPoolDeserializer(), - defaultConfig, -); -export const setUserMFAPreference = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('SetUserMFAPreference'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const getUser = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('GetUser'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const changePassword = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('ChangePassword'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const confirmDevice = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('ConfirmDevice'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const forgetDevice = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('ForgetDevice'), - handleEmptyResponseDeserializer(), - defaultConfig, -); -export const deleteUser = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('DeleteUser'), - handleEmptyResponseDeserializer(), - defaultConfig, -); -export const getUserAttributeVerificationCode = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer( - 'GetUserAttributeVerificationCode', - ), - buildUserPoolDeserializer(), - defaultConfig, -); -export const globalSignOut = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('GlobalSignOut'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const updateUserAttributes = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('UpdateUserAttributes'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const verifyUserAttribute = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('VerifyUserAttribute'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const updateDeviceStatus = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('UpdateDeviceStatus'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const listDevices = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('ListDevices'), - buildUserPoolDeserializer(), - defaultConfig, -); -export const deleteUserAttributes = composeServiceApi( - cognitoUserPoolTransferHandler, - buildUserPoolSerializer('DeleteUserAttributes'), - buildUserPoolDeserializer(), - defaultConfig, -); diff --git a/packages/auth/src/providers/cognito/utils/clients/base.ts b/packages/auth/src/providers/cognito/utils/clients/base.ts deleted file mode 100644 index a6a5fb6aca0..00000000000 --- a/packages/auth/src/providers/cognito/utils/clients/base.ts +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import { - Endpoint, - EndpointResolverOptions, - Headers, - HttpRequest, - HttpResponse, - Middleware, - getDnsSuffix, - getRetryDecider, - jitteredBackoff, - parseJsonError, - unauthenticatedHandler, -} from '@aws-amplify/core/internals/aws-client-utils'; -import { - AmplifyUrl, - getAmplifyUserAgent, -} from '@aws-amplify/core/internals/utils'; -import { composeTransferHandler } from '@aws-amplify/core/internals/aws-client-utils/composers'; - -/** - * The service name used to sign requests if the API requires authentication. - */ -const SERVICE_NAME = 'cognito-idp'; - -/** - * The endpoint resolver function that returns the endpoint URL for a given region. - */ -const endpointResolver = ({ region }: EndpointResolverOptions) => ({ - url: new AmplifyUrl( - `https://${SERVICE_NAME}.${region}.${getDnsSuffix(region)}`, - ), -}); - -/** - * A Cognito Identity-specific middleware that disables caching for all requests. - */ -const disableCacheMiddlewareFactory: Middleware< - HttpRequest, - HttpResponse, - Record -> = () => (next, _) => - async function disableCacheMiddleware(request) { - request.headers['cache-control'] = 'no-store'; - - return next(request); - }; - -/** - * A Cognito Identity-specific transfer handler that does NOT sign requests, and - * disables caching. - * - * @internal - */ -export const cognitoUserPoolTransferHandler = composeTransferHandler< - [Parameters[0]], - HttpRequest, - HttpResponse, - typeof unauthenticatedHandler ->(unauthenticatedHandler, [disableCacheMiddlewareFactory]); - -/** - * @internal - */ -export const defaultConfig = { - service: SERVICE_NAME, - endpointResolver, - retryDecider: getRetryDecider(parseJsonError), - computeDelay: jitteredBackoff, - userAgentValue: getAmplifyUserAgent(), -}; - -/** - * @internal - */ -export const getSharedHeaders = (operation: string): Headers => ({ - 'content-type': 'application/x-amz-json-1.1', - 'x-amz-target': `AWSCognitoIdentityProviderService.${operation}`, -}); - -/** - * @internal - */ -export const buildHttpRpcRequest = ( - { url }: Endpoint, - headers: Headers, - body: any, -): HttpRequest => ({ - headers, - url, - body, - method: 'POST', -}); diff --git a/packages/auth/src/providers/cognito/utils/oauth/completeOAuthFlow.ts b/packages/auth/src/providers/cognito/utils/oauth/completeOAuthFlow.ts index d9ebc5976a8..f374ed98156 100644 --- a/packages/auth/src/providers/cognito/utils/oauth/completeOAuthFlow.ts +++ b/packages/auth/src/providers/cognito/utils/oauth/completeOAuthFlow.ts @@ -11,6 +11,7 @@ import { Hub, decodeJWT } from '@aws-amplify/core'; import { cacheCognitoTokens } from '../../tokenProvider/cacheTokens'; import { dispatchSignedInHubEvent } from '../dispatchSignedInHubEvent'; +import { tokenOrchestrator } from '../../tokenProvider'; import { createOAuthError } from './createOAuthError'; import { resolveAndClearInflightPromises } from './inflightPromise'; @@ -227,6 +228,9 @@ const completeFlow = async ({ redirectUri: string; state: string; }) => { + await tokenOrchestrator.setOAuthMetadata({ + oauthSignIn: true, + }); await oAuthStore.clearOAuthData(); await oAuthStore.storeOAuthSignIn(true, preferPrivateSession); diff --git a/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.native.ts b/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.native.ts index 315074aa69d..9719b5071cd 100644 --- a/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.native.ts +++ b/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.native.ts @@ -1,17 +1,34 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { invalidRedirectException } from '../../../../errors/constants'; +import { + invalidAppSchemeException, + invalidPreferredRedirectUrlException, +} from '../../../../errors/constants'; -/** @internal */ -export function getRedirectUrl(redirects: string[]): string { - const redirectUrl = redirects?.find( +/** +* - Validate there is always an appScheme (required), if not throw invalidAppSchemeException. +* - If a preferredRedirectUrl is given, validate it's in the configured list, if not throw invalidPreferredRedirectUrlException. +* - If preferredRedirectUrl is not given, use the appScheme which is present in the configured list. +@internal */ +export function getRedirectUrl( + redirects: string[], + preferredRedirectUrl?: string, +): string { + // iOS always requires a non http/s url (appScheme) to be registered so we validate it's existence here. + const appSchemeRedirectUrl = redirects?.find( redirect => !redirect.startsWith('http://') && !redirect.startsWith('https://'), ); - if (!redirectUrl) { - throw invalidRedirectException; + if (!appSchemeRedirectUrl) { + throw invalidAppSchemeException; + } + if (preferredRedirectUrl) { + if (redirects?.includes(preferredRedirectUrl)) { + return preferredRedirectUrl; + } + throw invalidPreferredRedirectUrlException; } - return redirectUrl; + return appSchemeRedirectUrl; } diff --git a/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.ts b/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.ts index 63c343b0e00..6becf884230 100644 --- a/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.ts +++ b/packages/auth/src/providers/cognito/utils/oauth/getRedirectUrl.ts @@ -2,22 +2,38 @@ // SPDX-License-Identifier: Apache-2.0 import { invalidOriginException, + invalidPreferredRedirectUrlException, invalidRedirectException, } from '../../../../errors/constants'; /** @internal */ -export function getRedirectUrl(redirects: string[]): string { - const redirectUrlFromTheSameOrigin = - redirects?.find(isSameOriginAndPathName) ?? - redirects?.find(isTheSameDomain); - const redirectUrlFromDifferentOrigin = - redirects?.find(isHttps) ?? redirects?.find(isHttp); - if (redirectUrlFromTheSameOrigin) { - return redirectUrlFromTheSameOrigin; - } else if (redirectUrlFromDifferentOrigin) { - throw invalidOriginException; +export function getRedirectUrl( + redirects: string[], + preferredRedirectUrl?: string, +): string { + if (preferredRedirectUrl) { + const redirectUrl = redirects?.find( + redirect => redirect === preferredRedirectUrl, + ); + if (!redirectUrl) { + throw invalidPreferredRedirectUrlException; + } + + return redirectUrl; + } else { + const redirectUrlFromTheSameOrigin = + redirects?.find(isSameOriginAndPathName) ?? + redirects?.find(isTheSameDomain); + const redirectUrlFromDifferentOrigin = + redirects?.find(isHttps) ?? redirects?.find(isHttp); + + if (redirectUrlFromTheSameOrigin) { + return redirectUrlFromTheSameOrigin; + } else if (redirectUrlFromDifferentOrigin) { + throw invalidOriginException; + } + throw invalidRedirectException; } - throw invalidRedirectException; } // origin + pathname => https://example.com/app diff --git a/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.native.ts b/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.native.ts index bd9c8416b55..e67c8a255ef 100644 --- a/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.native.ts +++ b/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.native.ts @@ -5,6 +5,7 @@ import { CognitoUserPoolConfig } from '@aws-amplify/core'; import { OpenAuthSessionResult } from '../../../../utils/types'; import { DefaultOAuthStore } from '../../utils/signInWithRedirectStore'; +import { TokenOrchestrator } from '../../tokenProvider'; import { completeOAuthSignOut } from './completeOAuthSignOut'; import { oAuthSignOutRedirect } from './oAuthSignOutRedirect'; @@ -12,13 +13,16 @@ import { oAuthSignOutRedirect } from './oAuthSignOutRedirect'; export const handleOAuthSignOut = async ( cognitoConfig: CognitoUserPoolConfig, store: DefaultOAuthStore, + // No-op here as it's only used in the non-native implementation + tokenOrchestrator: TokenOrchestrator, + redirectUrl: string | undefined, ): Promise => { const { isOAuthSignIn, preferPrivateSession } = await store.loadOAuthSignIn(); - if (isOAuthSignIn) { const result = await oAuthSignOutRedirect( cognitoConfig, preferPrivateSession, + redirectUrl, ); // If this was a private session, clear data and tokens regardless of what happened with logout // endpoint. Otherwise, only do so if the logout endpoint was succesfully visited. diff --git a/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.ts b/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.ts index 0e16008e752..da4f7eb380a 100644 --- a/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.ts +++ b/packages/auth/src/providers/cognito/utils/oauth/handleOAuthSignOut.ts @@ -5,6 +5,7 @@ import { CognitoUserPoolConfig } from '@aws-amplify/core'; import { OpenAuthSessionResult } from '../../../../utils/types'; import { DefaultOAuthStore } from '../../utils/signInWithRedirectStore'; +import { TokenOrchestrator } from '../../tokenProvider'; import { completeOAuthSignOut } from './completeOAuthSignOut'; import { oAuthSignOutRedirect } from './oAuthSignOutRedirect'; @@ -12,15 +13,24 @@ import { oAuthSignOutRedirect } from './oAuthSignOutRedirect'; export const handleOAuthSignOut = async ( cognitoConfig: CognitoUserPoolConfig, store: DefaultOAuthStore, + tokenOrchestrator: TokenOrchestrator, + redirectUrl: string | undefined, ): Promise => { const { isOAuthSignIn } = await store.loadOAuthSignIn(); + const oauthMetadata = await tokenOrchestrator.getOAuthMetadata(); // Clear everything before attempting to visted logout endpoint since the current application // state could be wiped away on redirect await completeOAuthSignOut(store); - if (isOAuthSignIn) { + // The isOAuthSignIn flag is propagated by the oAuthToken store which manages oauth keys in local storage only. + // These keys are used to determine if a user is in an inflight or signedIn oauth states. + // However, this behavior represents an issue when 2 apps share the same set of tokens in Cookie storage because the app that didn't + // start the OAuth will not have access to the oauth keys. + // A heuristic solution is to add oauth metadata to the tokenOrchestrator which will have access to the underlying + // storage mechanism that is used by Amplify. + if (isOAuthSignIn || oauthMetadata?.oauthSignIn) { // On web, this will always end up being a void action - return oAuthSignOutRedirect(cognitoConfig); + return oAuthSignOutRedirect(cognitoConfig, false, redirectUrl); } }; diff --git a/packages/auth/src/providers/cognito/utils/oauth/oAuthSignOutRedirect.ts b/packages/auth/src/providers/cognito/utils/oauth/oAuthSignOutRedirect.ts index 2dd1eda520a..f86c0686df6 100644 --- a/packages/auth/src/providers/cognito/utils/oauth/oAuthSignOutRedirect.ts +++ b/packages/auth/src/providers/cognito/utils/oauth/oAuthSignOutRedirect.ts @@ -12,11 +12,12 @@ import { getRedirectUrl } from './getRedirectUrl'; export const oAuthSignOutRedirect = async ( authConfig: CognitoUserPoolConfig, preferPrivateSession = false, + redirectUrl?: string, ): Promise => { assertOAuthConfig(authConfig); const { loginWith, userPoolClientId } = authConfig; const { domain, redirectSignOut } = loginWith.oauth; - const signoutUri = getRedirectUrl(redirectSignOut); + const signoutUri = getRedirectUrl(redirectSignOut, redirectUrl); const oAuthLogoutEndpoint = `https://${domain}/logout?${Object.entries({ client_id: userPoolClientId, logout_uri: encodeURIComponent(signoutUri), diff --git a/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts b/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts index 6c3df620492..01f35a40b2b 100644 --- a/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts +++ b/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts @@ -9,10 +9,11 @@ import { } from '@aws-amplify/core/internals/utils'; import { CognitoAuthTokens, TokenRefresher } from '../tokenProvider/types'; -import { initiateAuth } from '../utils/clients/CognitoIdentityProvider'; -import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; import { assertAuthTokensWithRefreshToken } from '../utils/types'; import { AuthError } from '../../../errors/AuthError'; +import { createInitiateAuthClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; import { getUserContextData } from './userContextData'; @@ -26,7 +27,8 @@ const refreshAuthTokensFunction: TokenRefresher = async ({ username: string; }): Promise => { assertTokenProviderConfig(authConfig?.Cognito); - const region = getRegion(authConfig.Cognito.userPoolId); + const { userPoolId, userPoolClientId, userPoolEndpoint } = authConfig.Cognito; + const region = getRegionFromUserPoolId(userPoolId); assertAuthTokensWithRefreshToken(tokens); const refreshTokenString = tokens.refreshToken; @@ -39,14 +41,20 @@ const refreshAuthTokensFunction: TokenRefresher = async ({ const UserContextData = getUserContextData({ username, - userPoolId: authConfig.Cognito.userPoolId, - userPoolClientId: authConfig.Cognito.userPoolClientId, + userPoolId, + userPoolClientId, + }); + + const initiateAuth = createInitiateAuthClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), }); const { AuthenticationResult } = await initiateAuth( { region }, { - ClientId: authConfig?.Cognito?.userPoolClientId, + ClientId: userPoolClientId, AuthFlow: 'REFRESH_TOKEN_AUTH', AuthParameters, UserContextData, diff --git a/packages/auth/src/providers/cognito/utils/signInHelpers.ts b/packages/auth/src/providers/cognito/utils/signInHelpers.ts index 13edcd84e62..ef4c1422bf3 100644 --- a/packages/auth/src/providers/cognito/utils/signInHelpers.ts +++ b/packages/auth/src/providers/cognito/utils/signInHelpers.ts @@ -31,15 +31,14 @@ import { USER_ALREADY_AUTHENTICATED_EXCEPTION } from '../../../errors/constants' import { getCurrentUser } from '../apis/getCurrentUser'; import { AuthTokenOrchestrator, DeviceMetadata } from '../tokenProvider/types'; import { getAuthUserAgentValue } from '../../../utils'; - -import { signInStore } from './signInStore'; import { - associateSoftwareToken, - confirmDevice, - initiateAuth, - respondToAuthChallenge, - verifySoftwareToken, -} from './clients/CognitoIdentityProvider'; + createAssociateSoftwareTokenClient, + createConfirmDeviceClient, + createInitiateAuthClient, + createRespondToAuthChallengeClient, + createVerifySoftwareTokenClient, +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { createCognitoUserPoolEndpointResolver } from '../factories'; import { ChallengeName, ChallengeParameters, @@ -49,8 +48,10 @@ import { NewDeviceMetadataType, RespondToAuthChallengeCommandInput, RespondToAuthChallengeCommandOutput, -} from './clients/CognitoIdentityProvider/types'; -import { getRegion } from './clients/CognitoIdentityProvider/utils'; +} from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; +import { getRegionFromUserPoolId } from '../../../foundation/parsers'; + +import { signInStore } from './signInStore'; import { assertDeviceMetadata } from './types'; import { getAuthenticationHelper, @@ -92,7 +93,7 @@ export async function handleCustomChallenge({ }: HandleAuthChallengeRequest & { tokenOrchestrator: AuthTokenOrchestrator; }): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const challengeResponses: Record = { USERNAME: username, ANSWER: challengeResponse, @@ -118,9 +119,14 @@ export async function handleCustomChallenge({ UserContextData, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const response = await respondToAuthChallenge( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn), }, jsonReq, @@ -147,14 +153,18 @@ export async function handleMFASetupChallenge({ deviceName, config, }: HandleAuthChallengeRequest): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const challengeResponses = { USERNAME: username, }; - + const verifySoftwareToken = createVerifySoftwareTokenClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { Session } = await verifySoftwareToken( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn), }, { @@ -177,7 +187,16 @@ export async function handleMFASetupChallenge({ ClientId: userPoolClientId, }; - return respondToAuthChallenge({ region: getRegion(userPoolId) }, jsonReq); + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + + return respondToAuthChallenge( + { region: getRegionFromUserPoolId(userPoolId) }, + jsonReq, + ); } export async function handleSelectMFATypeChallenge({ @@ -187,7 +206,7 @@ export async function handleSelectMFATypeChallenge({ session, config, }: HandleAuthChallengeRequest): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; assertValidationError( challengeResponse === 'TOTP' || challengeResponse === 'SMS', AuthValidationErrorCode.IncorrectMFAMethod, @@ -213,9 +232,15 @@ export async function handleSelectMFATypeChallenge({ UserContextData, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + return respondToAuthChallenge( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn), }, jsonReq, @@ -229,7 +254,7 @@ export async function handleSMSMFAChallenge({ username, config, }: HandleAuthChallengeRequest): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const challengeResponses = { USERNAME: username, SMS_MFA_CODE: challengeResponse, @@ -248,9 +273,15 @@ export async function handleSMSMFAChallenge({ UserContextData, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + return respondToAuthChallenge( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn), }, jsonReq, @@ -263,7 +294,7 @@ export async function handleSoftwareTokenMFAChallenge({ username, config, }: HandleAuthChallengeRequest): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const challengeResponses = { USERNAME: username, SOFTWARE_TOKEN_MFA_CODE: challengeResponse, @@ -284,9 +315,15 @@ export async function handleSoftwareTokenMFAChallenge({ UserContextData, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + return respondToAuthChallenge( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn), }, jsonReq, @@ -300,7 +337,7 @@ export async function handleCompleteNewPasswordChallenge({ requiredAttributes, config, }: HandleAuthChallengeRequest): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const challengeResponses = { ...createAttributes(requiredAttributes), NEW_PASSWORD: challengeResponse, @@ -322,9 +359,15 @@ export async function handleCompleteNewPasswordChallenge({ UserContextData, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + return respondToAuthChallenge( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn), }, jsonReq, @@ -338,7 +381,7 @@ export async function handleUserPasswordAuthFlow( config: CognitoUserPoolConfig, tokenOrchestrator: AuthTokenOrchestrator, ): Promise { - const { userPoolClientId, userPoolId } = config; + const { userPoolClientId, userPoolId, userPoolEndpoint } = config; const authParameters: Record = { USERNAME: username, PASSWORD: password, @@ -363,9 +406,15 @@ export async function handleUserPasswordAuthFlow( UserContextData, }; + const initiateAuth = createInitiateAuthClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + const response = await initiateAuth( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SignIn), }, jsonReq, @@ -397,7 +446,7 @@ export async function handleUserSRPAuthFlow( config: CognitoUserPoolConfig, tokenOrchestrator: AuthTokenOrchestrator, ): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const userPoolName = userPoolId?.split('_')[1] || ''; const authenticationHelper = await getAuthenticationHelper(userPoolName); @@ -420,9 +469,15 @@ export async function handleUserSRPAuthFlow( UserContextData, }; + const initiateAuth = createInitiateAuthClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + const resp = await initiateAuth( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SignIn), }, jsonReq, @@ -453,7 +508,7 @@ export async function handleCustomAuthFlowWithoutSRP( config: CognitoUserPoolConfig, tokenOrchestrator: AuthTokenOrchestrator, ): Promise { - const { userPoolClientId, userPoolId } = config; + const { userPoolClientId, userPoolId, userPoolEndpoint } = config; const authParameters: Record = { USERNAME: username, }; @@ -477,9 +532,15 @@ export async function handleCustomAuthFlowWithoutSRP( UserContextData, }; + const initiateAuth = createInitiateAuthClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + const response = await initiateAuth( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SignIn), }, jsonReq, @@ -506,7 +567,7 @@ export async function handleCustomSRPAuthFlow( tokenOrchestrator: AuthTokenOrchestrator, ) { assertTokenProviderConfig(config); - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const userPoolName = userPoolId?.split('_')[1] || ''; const authenticationHelper = await getAuthenticationHelper(userPoolName); @@ -531,10 +592,16 @@ export async function handleCustomSRPAuthFlow( UserContextData, }; + const initiateAuth = createInitiateAuthClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + const { ChallengeParameters: challengeParameters, Session: session } = await initiateAuth( { - region: getRegion(userPoolId), + region: getRegionFromUserPoolId(userPoolId), userAgentValue: getAuthUserAgentValue(AuthAction.SignIn), }, jsonReq, @@ -565,7 +632,7 @@ async function handleDeviceSRPAuth({ session, tokenOrchestrator, }: HandleDeviceSRPInput): Promise { - const { userPoolId } = config; + const { userPoolId, userPoolEndpoint } = config; const clientId = config.userPoolClientId; const deviceMetadata = await tokenOrchestrator?.getDeviceMetadata(username); assertDeviceMetadata(deviceMetadata); @@ -585,9 +652,14 @@ async function handleDeviceSRPAuth({ ClientMetadata: clientMetadata, Session: session, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); const { ChallengeParameters: respondedChallengeParameters, Session } = await respondToAuthChallenge( - { region: getRegion(userPoolId) }, + { region: getRegionFromUserPoolId(userPoolId) }, jsonReqResponseChallenge, ); @@ -608,7 +680,7 @@ async function handleDevicePasswordVerifier( clientMetadata: ClientMetadata | undefined, session: string | undefined, authenticationHelper: AuthenticationHelper, - { userPoolId, userPoolClientId }: CognitoUserPoolConfig, + { userPoolId, userPoolClientId, userPoolEndpoint }: CognitoUserPoolConfig, tokenOrchestrator?: AuthTokenOrchestrator, ): Promise { const deviceMetadata = await tokenOrchestrator?.getDeviceMetadata(username); @@ -654,9 +726,14 @@ async function handleDevicePasswordVerifier( ClientMetadata: clientMetadata, UserContextData, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); return respondToAuthChallenge( - { region: getRegion(userPoolId) }, + { region: getRegionFromUserPoolId(userPoolId) }, jsonReqResponseChallenge, ); } @@ -670,7 +747,7 @@ export async function handlePasswordVerifierChallenge( config: CognitoUserPoolConfig, tokenOrchestrator: AuthTokenOrchestrator, ): Promise { - const { userPoolId, userPoolClientId } = config; + const { userPoolId, userPoolClientId, userPoolEndpoint } = config; const userPoolName = userPoolId?.split('_')[1] || ''; const serverBValue = new (BigInteger as any)(challengeParameters?.SRP_B, 16); const salt = new (BigInteger as any)(challengeParameters?.SALT, 16); @@ -722,8 +799,14 @@ export async function handlePasswordVerifierChallenge( UserContextData, }; + const respondToAuthChallenge = createRespondToAuthChallengeClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); + const response = await respondToAuthChallenge( - { region: getRegion(userPoolId) }, + { region: getRegionFromUserPoolId(userPoolId) }, jsonReqResponseChallenge, ); @@ -766,8 +849,14 @@ export async function getSignInResult(params: { parseMFATypes(challengeParameters.MFAS_CAN_SETUP), )}`, }); + + const associateSoftwareToken = createAssociateSoftwareTokenClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: authConfig.userPoolEndpoint, + }), + }); const { Session, SecretCode: secretCode } = await associateSoftwareToken( - { region: getRegion(authConfig.userPoolId) }, + { region: getRegionFromUserPoolId(authConfig.userPoolId) }, { Session: signInSession, }, @@ -1037,11 +1126,17 @@ export async function assertUserNotAuthenticated() { * * @returns DeviceMetadata | undefined */ -export async function getNewDeviceMetatada( - userPoolId: string, - newDeviceMetadata?: NewDeviceMetadataType, - accessToken?: string, -): Promise { +export async function getNewDeviceMetadata({ + userPoolId, + userPoolEndpoint, + newDeviceMetadata, + accessToken, +}: { + userPoolId: string; + userPoolEndpoint: string | undefined; + newDeviceMetadata?: NewDeviceMetadataType; + accessToken?: string; +}): Promise { if (!newDeviceMetadata) return undefined; const userPoolName = userPoolId.split('_')[1] || ''; const authenticationHelper = await getAuthenticationHelper(userPoolName); @@ -1069,8 +1164,13 @@ export async function getNewDeviceMetatada( const randomPassword = authenticationHelper.getRandomPassword(); try { + const confirmDevice = createConfirmDeviceClient({ + endpointResolver: createCognitoUserPoolEndpointResolver({ + endpointOverride: userPoolEndpoint, + }), + }); await confirmDevice( - { region: getRegion(userPoolId) }, + { region: getRegionFromUserPoolId(userPoolId) }, { AccessToken: accessToken, DeviceName: await getDeviceName(), diff --git a/packages/auth/src/providers/cognito/utils/signInStore.ts b/packages/auth/src/providers/cognito/utils/signInStore.ts index 0028ab71067..fd07cb15e6d 100644 --- a/packages/auth/src/providers/cognito/utils/signInStore.ts +++ b/packages/auth/src/providers/cognito/utils/signInStore.ts @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { CognitoAuthSignInDetails } from '../types'; - -import { ChallengeName } from './clients/CognitoIdentityProvider/types'; +import { ChallengeName } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; // TODO: replace all of this implementation with state machines interface SignInState { diff --git a/packages/auth/src/providers/cognito/utils/signUpHelpers.ts b/packages/auth/src/providers/cognito/utils/signUpHelpers.ts index 73e59c78406..8ab2943ce2a 100644 --- a/packages/auth/src/providers/cognito/utils/signUpHelpers.ts +++ b/packages/auth/src/providers/cognito/utils/signUpHelpers.ts @@ -10,8 +10,7 @@ import { AutoSignInCallback } from '../../../types/models'; import { AuthError } from '../../../errors/AuthError'; import { resetAutoSignIn, setAutoSignIn } from '../apis/autoSignIn'; import { AUTO_SIGN_IN_EXCEPTION } from '../../../errors/constants'; - -import { SignUpCommandOutput } from './clients/CognitoIdentityProvider/types'; +import { SignUpCommandOutput } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider/types'; const MAX_AUTOSIGNIN_POLLING_MS = 3 * 60 * 1000; diff --git a/packages/auth/src/types/inputs.ts b/packages/auth/src/types/inputs.ts index 437f5e398f4..6e152cdc1e5 100644 --- a/packages/auth/src/types/inputs.ts +++ b/packages/auth/src/types/inputs.ts @@ -47,6 +47,9 @@ export interface AuthSignInInput< } export interface AuthSignOutInput { global: boolean; + oauth?: { + redirectUrl?: string; + }; } export type AuthProvider = 'Amazon' | 'Apple' | 'Facebook' | 'Google'; diff --git a/packages/aws-amplify/CHANGELOG.md b/packages/aws-amplify/CHANGELOG.md index b12e99b983b..815d5baa26a 100644 --- a/packages/aws-amplify/CHANGELOG.md +++ b/packages/aws-amplify/CHANGELOG.md @@ -3,6 +3,33 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.6.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@6.6.1...aws-amplify@6.6.2) (2024-09-17) + +**Note:** Version bump only for package aws-amplify + +## [6.6.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@6.6.0...aws-amplify@6.6.1) (2024-09-16) + +**Note:** Version bump only for package aws-amplify + +# [6.6.0](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@6.5.4...aws-amplify@6.6.0) (2024-09-04) + +### Features + +- **api-graphql:** pass authToken via subprotocol ([#13727](https://github.com/aws-amplify/amplify-js/issues/13727)) ([ced891c](https://github.com/aws-amplify/amplify-js/commit/ced891c2e4f6b0f1fdeaf44ab80cae9d585b6d15)) +- **auth:** HostedUI oidc signout ([#13512](https://github.com/aws-amplify/amplify-js/issues/13512)) ([e8fb997](https://github.com/aws-amplify/amplify-js/commit/e8fb9973f8e3e3490619416a778ec1460cafaf9a)), closes [#13712](https://github.com/aws-amplify/amplify-js/issues/13712) [#13736](https://github.com/aws-amplify/amplify-js/issues/13736) + +## [6.5.4](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@6.5.3...aws-amplify@6.5.4) (2024-09-03) + +**Note:** Version bump only for package aws-amplify + +## [6.5.3](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@6.5.2...aws-amplify@6.5.3) (2024-08-26) + +**Note:** Version bump only for package aws-amplify + +## [6.5.2](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@6.5.1...aws-amplify@6.5.2) (2024-08-21) + +**Note:** Version bump only for package aws-amplify + ## [6.5.1](https://github.com/aws-amplify/amplify-js/compare/aws-amplify@6.5.0...aws-amplify@6.5.1) (2024-08-15) **Note:** Version bump only for package aws-amplify diff --git a/packages/aws-amplify/package.json b/packages/aws-amplify/package.json index 41e506e36f0..1cede57f7ad 100644 --- a/packages/aws-amplify/package.json +++ b/packages/aws-amplify/package.json @@ -1,6 +1,6 @@ { "name": "aws-amplify", - "version": "6.5.1", + "version": "6.6.2", "description": "AWS Amplify is a JavaScript library for Frontend and mobile developers building cloud-enabled applications.", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -276,13 +276,13 @@ "utils" ], "dependencies": { - "@aws-amplify/analytics": "7.0.43", - "@aws-amplify/api": "6.0.45", - "@aws-amplify/auth": "6.3.14", - "@aws-amplify/core": "6.3.10", - "@aws-amplify/datastore": "5.0.45", - "@aws-amplify/notifications": "2.0.43", - "@aws-amplify/storage": "6.6.1", + "@aws-amplify/analytics": "7.0.49", + "@aws-amplify/api": "6.0.51", + "@aws-amplify/auth": "6.4.2", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/datastore": "5.0.51", + "@aws-amplify/notifications": "2.0.49", + "@aws-amplify/storage": "6.6.7", "tslib": "^2.5.0" }, "devDependencies": { @@ -293,7 +293,7 @@ "name": "[Analytics] record (Pinpoint)", "path": "./dist/esm/analytics/index.mjs", "import": "{ record }", - "limit": "17.28 kB" + "limit": "17.34 kB" }, { "name": "[Analytics] record (Kinesis)", @@ -317,7 +317,7 @@ "name": "[Analytics] identifyUser (Pinpoint)", "path": "./dist/esm/analytics/index.mjs", "import": "{ identifyUser }", - "limit": "15.79 kB" + "limit": "15.84 kB" }, { "name": "[Analytics] enable", @@ -335,7 +335,7 @@ "name": "[API] generateClient (AppSync)", "path": "./dist/esm/api/index.mjs", "import": "{ generateClient }", - "limit": "41 kB" + "limit": "43.17 kB" }, { "name": "[API] REST API handlers", @@ -353,13 +353,13 @@ "name": "[Auth] resetPassword (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ resetPassword }", - "limit": "12.62 kB" + "limit": "12.66 kB" }, { "name": "[Auth] confirmResetPassword (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ confirmResetPassword }", - "limit": "12.56 kB" + "limit": "12.60 kB" }, { "name": "[Auth] signIn (Cognito)", @@ -371,7 +371,7 @@ "name": "[Auth] resendSignUpCode (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ resendSignUpCode }", - "limit": "12.57 kB" + "limit": "12.61 kB" }, { "name": "[Auth] confirmSignUp (Cognito)", @@ -389,25 +389,25 @@ "name": "[Auth] updateMFAPreference (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ updateMFAPreference }", - "limit": "11.92 kB" + "limit": "12.07 kB" }, { "name": "[Auth] fetchMFAPreference (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ fetchMFAPreference }", - "limit": "11.94 kB" + "limit": "12.1 kB" }, { "name": "[Auth] verifyTOTPSetup (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ verifyTOTPSetup }", - "limit": "12.78 kB" + "limit": "12.94 kB" }, { "name": "[Auth] updatePassword (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ updatePassword }", - "limit": "12.80 kB" + "limit": "12.96 kB" }, { "name": "[Auth] setUpTOTP (Cognito)", @@ -419,19 +419,19 @@ "name": "[Auth] updateUserAttributes (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ updateUserAttributes }", - "limit": "12.03 kB" + "limit": "12.19 kB" }, { "name": "[Auth] getCurrentUser (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ getCurrentUser }", - "limit": "7.86 kB" + "limit": "7.99 kB" }, { "name": "[Auth] confirmUserAttribute (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ confirmUserAttribute }", - "limit": "12.79 kB" + "limit": "12.93 kB" }, { "name": "[Auth] signInWithRedirect (Cognito)", @@ -443,7 +443,7 @@ "name": "[Auth] fetchUserAttributes (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ fetchUserAttributes }", - "limit": "11.86 kB" + "limit": "12.01 kB" }, { "name": "[Auth] Basic Auth Flow (Cognito)", @@ -461,43 +461,43 @@ "name": "[Storage] copy (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ copy }", - "limit": "15.75 kB" + "limit": "15.80 kB" }, { "name": "[Storage] downloadData (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ downloadData }", - "limit": "16.1 kB" + "limit": "16.18 kB" }, { "name": "[Storage] getProperties (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ getProperties }", - "limit": "15.35 kB" + "limit": "15.41 kB" }, { "name": "[Storage] getUrl (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ getUrl }", - "limit": "16.55 kB" + "limit": "16.64 kB" }, { "name": "[Storage] list (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ list }", - "limit": "16.10 kB" + "limit": "16.16 kB" }, { "name": "[Storage] remove (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ remove }", - "limit": "15.20 kB" + "limit": "15.28 kB" }, { "name": "[Storage] uploadData (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ uploadData }", - "limit": "22.01 kB" + "limit": "22.07 kB" } ] } diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 5a670ccd726..9cb66e815c7 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.4.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@6.4.1...@aws-amplify/core@6.4.2) (2024-09-17) + +### Reverts + +- Revert "Reapply "feat(core): resolve webcrypto from node:crypto for Node18 (#13599)" (#13775)" ([953d578](https://github.com/aws-amplify/amplify-js/commit/953d578fabd69ab8eb7bf494a50c5a15ebf0b74c)), closes [#13599](https://github.com/aws-amplify/amplify-js/issues/13599) [#13775](https://github.com/aws-amplify/amplify-js/issues/13775) + +## [6.4.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@6.4.0...@aws-amplify/core@6.4.1) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/core + +# [6.4.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@6.3.13...@aws-amplify/core@6.4.0) (2024-09-04) + +### Features + +- **api-graphql:** pass authToken via subprotocol ([#13727](https://github.com/aws-amplify/amplify-js/issues/13727)) ([ced891c](https://github.com/aws-amplify/amplify-js/commit/ced891c2e4f6b0f1fdeaf44ab80cae9d585b6d15)) + +## [6.3.13](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@6.3.12...@aws-amplify/core@6.3.13) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/core + +## [6.3.12](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@6.3.11...@aws-amplify/core@6.3.12) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/core + +## [6.3.11](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@6.3.10...@aws-amplify/core@6.3.11) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/core + ## [6.3.10](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/core@6.3.9...@aws-amplify/core@6.3.10) (2024-08-15) **Note:** Version bump only for package @aws-amplify/core diff --git a/packages/core/__tests__/utils/convert/base64Encoder.test.ts b/packages/core/__tests__/utils/convert/base64Encoder.test.ts index 14ffb0064b0..c1d1aeb203a 100644 --- a/packages/core/__tests__/utils/convert/base64Encoder.test.ts +++ b/packages/core/__tests__/utils/convert/base64Encoder.test.ts @@ -43,4 +43,12 @@ describe('base64Encoder (non-native)', () => { 'test-test_test', ); }); + + it('makes the result a base64url string with no padding chars', () => { + const mockResult = 'test+test/test=='; // = is the base64 padding char + mockBtoa.mockReturnValue(mockResult); + expect( + base64Encoder.convert('test', { urlSafe: true, skipPadding: true }), + ).toBe('test-test_test'); + }); }); diff --git a/packages/core/metadata b/packages/core/metadata index 041bf1756dc..5a9cb296e96 100644 --- a/packages/core/metadata +++ b/packages/core/metadata @@ -1 +1 @@ -2258de69f +3ef5df5f7 diff --git a/packages/core/package.json b/packages/core/package.json index 4fdbe7c02df..453774ab5ea 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/core", - "version": "6.3.10", + "version": "6.4.2", "description": "Core category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -60,7 +60,7 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@aws-amplify/react-native": "1.1.4", + "@aws-amplify/react-native": "1.1.5", "@types/js-cookie": "3.0.2", "genversion": "^2.2.0", "typescript": "5.0.2" @@ -82,13 +82,13 @@ "name": "Custom clients (fetch handler)", "path": "./dist/esm/clients/handlers/fetch.mjs", "import": "{ fetchTransferHandler }", - "limit": "500 B" + "limit": "575 B" }, { "name": "Custom clients (unauthenticated handler)", "path": "./dist/esm/clients/handlers/unauthenticated.mjs", "import": "{ unauthenticatedHandler }", - "limit": "1 kB" + "limit": "1.15 kB" }, { "name": "Custom clients (request signer)", diff --git a/packages/core/src/clients/handlers/fetch.ts b/packages/core/src/clients/handlers/fetch.ts index be8e5ac9520..30a37f210e2 100644 --- a/packages/core/src/clients/handlers/fetch.ts +++ b/packages/core/src/clients/handlers/fetch.ts @@ -3,7 +3,9 @@ import { HttpRequest, HttpResponse, HttpTransferOptions } from '../types/http'; import { TransferHandler } from '../types/core'; +import { AmplifyError } from '../../errors'; import { withMemoization } from '../utils/memoization'; +import { AmplifyErrorCode } from '../../types'; const shouldSendBody = (method: string) => !['HEAD', 'GET', 'DELETE'].includes(method.toUpperCase()); @@ -28,11 +30,12 @@ export const fetchTransferHandler: TransferHandler< credentials: withCrossDomainCredentials ? 'include' : 'same-origin', }); } catch (e) { - // TODO: needs to revise error handling in v6 - // For now this is a thin wrapper over original fetch error similar to cognito-identity-js package. - // Ref: https://github.com/aws-amplify/amplify-js/blob/4fbc8c0a2be7526aab723579b4c95b552195a80b/packages/amazon-cognito-identity-js/src/Client.js#L103-L108 if (e instanceof TypeError) { - throw new Error('Network error'); + throw new AmplifyError({ + name: AmplifyErrorCode.NetworkError, + message: 'A network error has occurred.', + underlyingError: e, + }); } throw e; } diff --git a/packages/core/src/errors/errorHelpers.ts b/packages/core/src/errors/errorHelpers.ts index a343c51f3f2..cb78f5534c9 100644 --- a/packages/core/src/errors/errorHelpers.ts +++ b/packages/core/src/errors/errorHelpers.ts @@ -15,6 +15,9 @@ const amplifyErrorMap: AmplifyErrorMap = { [AmplifyErrorCode.Unknown]: { message: 'An unknown error occurred.', }, + [AmplifyErrorCode.NetworkError]: { + message: 'A network error has occurred.', + }, }; export const assert: AssertionFunction = diff --git a/packages/core/src/singleton/API/types.ts b/packages/core/src/singleton/API/types.ts index 20dd5bd3dfc..3909d264180 100644 --- a/packages/core/src/singleton/API/types.ts +++ b/packages/core/src/singleton/API/types.ts @@ -111,6 +111,8 @@ export interface ModelIntrospectionSchema { queries?: CustomOperations; mutations?: CustomOperations; subscriptions?: CustomOperations; + conversations?: SchemaConversationRoutes; + generations?: SchemaGenerationRoutes; } /** @@ -120,6 +122,27 @@ export type SchemaModels = Record; export type SchemaNonModels = Record; export type SchemaEnums = Record; export type CustomOperations = Record; +type SchemaConversationRoutes = Record; +type SchemaGenerationRoutes = Record; + +interface SchemaConversationRoute { + name: string; + models: SchemaModels; + nonModels: SchemaNonModels; + enums: SchemaEnums; + conversation: SchemaConversation; + message: SchemaConversationMessage; +} + +interface SchemaConversation { + modelName: string; +} + +interface SchemaConversationMessage { + modelName: string; + subscribe: CustomOperation; + send: CustomOperation; +} export interface SchemaModel { name: string; @@ -164,7 +187,7 @@ export type CustomOperationArguments = Record; export interface CustomOperationArgument { name: string; - type: FieldType; + type: InputFieldType; isArray: boolean; isRequired: boolean; isArrayNullable?: boolean; @@ -192,7 +215,15 @@ export interface NonModelFieldType { nonModel: string; } -export type FieldType = +interface EnumType { + enum: string; +} + +interface InputType { + input: string; +} + +type ScalarType = | 'ID' | 'String' | 'Int' @@ -206,10 +237,12 @@ export type FieldType = | 'AWSIPAddress' | 'Boolean' | 'AWSJSON' - | 'AWSPhone' - | { enum: string } - | ModelFieldType - | NonModelFieldType; + | 'AWSPhone'; + +type FieldType = ScalarType | EnumType | ModelFieldType | NonModelFieldType; + +type InputFieldType = ScalarType | EnumType | InputType; + export type FieldAttribute = ModelAttribute; /** diff --git a/packages/core/src/singleton/Auth/utils/index.ts b/packages/core/src/singleton/Auth/utils/index.ts index c710e64a1ee..496d28db68d 100644 --- a/packages/core/src/singleton/Auth/utils/index.ts +++ b/packages/core/src/singleton/Auth/utils/index.ts @@ -66,6 +66,12 @@ export function assertIdentityPoolIdConfig( ); } +/** + * Decodes payload of JWT token + * + * @param {String} token A string representing a token to be decoded + * @throws {@link Error} - Throws error when token is invalid or payload malformed. + */ export function decodeJWT(token: string): JWT { const tokenParts = token.split('.'); diff --git a/packages/core/src/singleton/apis/fetchAuthSession.ts b/packages/core/src/singleton/apis/fetchAuthSession.ts index f7e1248ae54..1e7d4aa5f04 100644 --- a/packages/core/src/singleton/apis/fetchAuthSession.ts +++ b/packages/core/src/singleton/apis/fetchAuthSession.ts @@ -6,6 +6,15 @@ import { AuthSession, FetchAuthSessionOptions } from '../Auth/types'; import { fetchAuthSession as fetchAuthSessionInternal } from './internal/fetchAuthSession'; +/** + * Fetch the auth session including the tokens and credentials if they are available. By default it + * does not refresh the auth tokens or credentials if they are loaded in storage already. You can force a refresh + * with `{ forceRefresh: true }` input. + * + * @param options - Options configuring the fetch behavior. + * @throws {@link AuthError} - Throws error when session information cannot be refreshed. + * @returns Promise + */ export const fetchAuthSession = ( options?: FetchAuthSessionOptions, ): Promise => { diff --git a/packages/core/src/types/errors.ts b/packages/core/src/types/errors.ts index 19ecec76935..3401616074f 100644 --- a/packages/core/src/types/errors.ts +++ b/packages/core/src/types/errors.ts @@ -5,6 +5,7 @@ export enum AmplifyErrorCode { NoEndpointId = 'NoEndpointId', PlatformNotSupported = 'PlatformNotSupported', Unknown = 'Unknown', + NetworkError = 'NetworkError', } export interface AmplifyErrorParams { diff --git a/packages/core/src/utils/convert/base64/base64Encoder.ts b/packages/core/src/utils/convert/base64/base64Encoder.ts index 05f01ab1a95..43184997819 100644 --- a/packages/core/src/utils/convert/base64/base64Encoder.ts +++ b/packages/core/src/utils/convert/base64/base64Encoder.ts @@ -2,18 +2,37 @@ // SPDX-License-Identifier: Apache-2.0 import { getBtoa } from '../../globalHelpers'; -import { Base64Encoder } from '../types'; +import type { Base64Encoder, Base64EncoderConvertOptions } from '../types'; import { bytesToString } from './bytesToString'; export const base64Encoder: Base64Encoder = { - convert(input, { urlSafe } = { urlSafe: false }) { + /** + * Convert input to base64-encoded string + * @param input - string to convert to base64 + * @param options - encoding options that can optionally produce a base64url string + * @returns base64-encoded string + */ + convert( + input, + options: Base64EncoderConvertOptions = { + urlSafe: false, + skipPadding: false, + }, + ) { const inputStr = typeof input === 'string' ? input : bytesToString(input); - const encodedStr = getBtoa()(inputStr); + let encodedStr = getBtoa()(inputStr); - // see details about the char replacing at https://datatracker.ietf.org/doc/html/rfc4648#section-5 - return urlSafe - ? encodedStr.replace(/\+/g, '-').replace(/\//g, '_') - : encodedStr; + // urlSafe char replacement and skipPadding options conform to the base64url spec + // https://datatracker.ietf.org/doc/html/rfc4648#section-5 + if (options.urlSafe) { + encodedStr = encodedStr.replace(/\+/g, '-').replace(/\//g, '_'); + } + + if (options.skipPadding) { + encodedStr = encodedStr.replace(/=/g, ''); + } + + return encodedStr; }, }; diff --git a/packages/core/src/utils/convert/types.ts b/packages/core/src/utils/convert/types.ts index ed53d507b81..7a1c4d4d86d 100644 --- a/packages/core/src/utils/convert/types.ts +++ b/packages/core/src/utils/convert/types.ts @@ -3,6 +3,7 @@ export interface Base64EncoderConvertOptions { urlSafe: boolean; + skipPadding?: boolean; } export interface Base64Encoder { diff --git a/packages/datastore-storage-adapter/CHANGELOG.md b/packages/datastore-storage-adapter/CHANGELOG.md index 40b028d9a50..70ea3a88d99 100644 --- a/packages/datastore-storage-adapter/CHANGELOG.md +++ b/packages/datastore-storage-adapter/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.1.51](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@2.1.50...@aws-amplify/datastore-storage-adapter@2.1.51) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + +## [2.1.50](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@2.1.49...@aws-amplify/datastore-storage-adapter@2.1.50) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + +## [2.1.49](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@2.1.48...@aws-amplify/datastore-storage-adapter@2.1.49) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + +## [2.1.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@2.1.47...@aws-amplify/datastore-storage-adapter@2.1.48) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + +## [2.1.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@2.1.46...@aws-amplify/datastore-storage-adapter@2.1.47) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + +## [2.1.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@2.1.45...@aws-amplify/datastore-storage-adapter@2.1.46) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/datastore-storage-adapter + ## [2.1.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore-storage-adapter@2.1.44...@aws-amplify/datastore-storage-adapter@2.1.45) (2024-08-15) **Note:** Version bump only for package @aws-amplify/datastore-storage-adapter diff --git a/packages/datastore-storage-adapter/package.json b/packages/datastore-storage-adapter/package.json index 7f89c7c56a7..2df8924bcd0 100644 --- a/packages/datastore-storage-adapter/package.json +++ b/packages/datastore-storage-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/datastore-storage-adapter", - "version": "2.1.45", + "version": "2.1.51", "description": "SQLite storage adapter for Amplify DataStore ", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -36,8 +36,8 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", - "@aws-amplify/datastore": "5.0.45", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/datastore": "5.0.51", "@types/react-native-sqlite-storage": "5.0.1", "expo-file-system": "13.1.4", "expo-sqlite": "10.1.0", diff --git a/packages/datastore/CHANGELOG.md b/packages/datastore/CHANGELOG.md index a0e827ac973..33ddbed03e7 100644 --- a/packages/datastore/CHANGELOG.md +++ b/packages/datastore/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [5.0.51](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@5.0.50...@aws-amplify/datastore@5.0.51) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/datastore + +## [5.0.50](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@5.0.49...@aws-amplify/datastore@5.0.50) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/datastore + +## [5.0.49](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@5.0.48...@aws-amplify/datastore@5.0.49) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/datastore + +## [5.0.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@5.0.47...@aws-amplify/datastore@5.0.48) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/datastore + +## [5.0.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@5.0.46...@aws-amplify/datastore@5.0.47) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/datastore + +## [5.0.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@5.0.45...@aws-amplify/datastore@5.0.46) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/datastore + ## [5.0.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/datastore@5.0.44...@aws-amplify/datastore@5.0.45) (2024-08-15) **Note:** Version bump only for package @aws-amplify/datastore diff --git a/packages/datastore/package.json b/packages/datastore/package.json index 86b1328a942..266a67ab709 100644 --- a/packages/datastore/package.json +++ b/packages/datastore/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/datastore", - "version": "5.0.45", + "version": "5.0.51", "description": "AppSyncLocal support for aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -44,7 +44,7 @@ "src" ], "dependencies": { - "@aws-amplify/api": "6.0.45", + "@aws-amplify/api": "6.0.51", "buffer": "4.9.2", "idb": "5.0.6", "immer": "9.0.6", @@ -55,8 +55,8 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", - "@aws-amplify/react-native": "1.1.4", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/react-native": "1.1.5", "@types/uuid-validate": "^0.0.1", "dexie": "3.2.2", "dexie-export-import": "1.0.3", diff --git a/packages/datastore/src/types.ts b/packages/datastore/src/types.ts index 75e0b9ff27e..5cd8c6085c0 100644 --- a/packages/datastore/src/types.ts +++ b/packages/datastore/src/types.ts @@ -71,10 +71,20 @@ export interface SchemaModel { syncable?: boolean; } +/** + * @private + * @param obj + * @returns `true` if the given object likely represents a model in a schema. + */ export function isSchemaModel(obj: any): obj is SchemaModel { return obj && (obj as SchemaModel).pluralName !== undefined; } +/** + * @private + * @param m + * @returns `true` if the given schema entry defines Schema Model attributes. + */ export function isSchemaModelWithAttributes( m: SchemaModel | SchemaNonModel, ): m is SchemaModel { @@ -104,6 +114,11 @@ interface AssociatedWith { targetNames?: string[]; } +/** + * @private + * @param obj + * @returns `true` if the object is an `AssociatedWith` definition. + */ export function isAssociatedWith(obj: any): obj is AssociatedWith { return obj && obj.associatedWith; } @@ -114,6 +129,11 @@ interface TargetNameAssociation { targetNames?: string[]; } +/** + * @private + * @param obj + * @returns `true` if the given object specifies either `targetName` or `targetNames`. + */ export function isTargetNameAssociation( obj: any, ): obj is TargetNameAssociation { @@ -123,6 +143,13 @@ export function isTargetNameAssociation( interface FieldAssociation { connectionType: 'HAS_ONE' | 'BELONGS_TO' | 'HAS_MANY'; } + +/** + * @private + * @param obj + * @param fieldName + * @returns Truthy if the object has a `FieldAssociation` for the given `fieldName`. + */ export function isFieldAssociation( obj: any, fieldName: string, @@ -154,6 +181,11 @@ export interface ModelAttributeAuth { }; } +/** + * @private + * @param attr + * @returns `true` if the given attribute is an auth attribute with rules. + */ export function isModelAttributeAuth( attr: ModelAttribute, ): attr is ModelAttributeAuth { @@ -189,6 +221,11 @@ interface ModelAttributeCompositeKey { }; } +/** + * @private + * @param attr + * @returns `true` if the given attribute is a key field. + */ export function isModelAttributeKey( attr: ModelAttribute, ): attr is ModelAttributeKey { @@ -200,12 +237,22 @@ export function isModelAttributeKey( ); } +/** + * @private + * @param attr + * @returns `true` if the given attribute is a primary key, indicated by the key being unnamed. + */ export function isModelAttributePrimaryKey( attr: ModelAttribute, ): attr is ModelAttributePrimaryKey { return isModelAttributeKey(attr) && attr.properties.name === undefined; } +/** + * @private + * @param attr + * @returns `true` if the given attribute represents a composite key with multiple fields. + */ export function isModelAttributeCompositeKey( attr: ModelAttribute, ): attr is ModelAttributeCompositeKey { @@ -334,6 +381,10 @@ export interface AuthorizationRule { areSubscriptionsPublic: boolean; } +/** + * @private + * @returns `true` if the given field specifies a scalar type. + */ export function isGraphQLScalarType( obj: any, ): obj is keyof Omit< @@ -347,6 +398,12 @@ export interface ModelFieldType { model: string; modelConstructor?: ModelMeta; } + +/** + * @private + * @param obj + * @returns `true` if the given field specifies a Model. + */ export function isModelFieldType<_ extends PersistentModel>( obj: any, ): obj is ModelFieldType { @@ -359,6 +416,12 @@ export function isModelFieldType<_ extends PersistentModel>( export interface NonModelFieldType { nonModel: string; } + +/** + * @private + * @param obj + * @returns `true` if the given field specifies a custom non-model type. + */ export function isNonModelFieldType(obj: any): obj is NonModelFieldType { const typeField: keyof NonModelFieldType = 'nonModel'; if (obj && obj[typeField]) return true; @@ -369,6 +432,12 @@ export function isNonModelFieldType(obj: any): obj is NonModelFieldType { interface EnumFieldType { enum: string; } + +/** + * @private + * @param obj + * @returns `true` if the object is an `EnumFieldType`. + */ export function isEnumFieldType(obj: any): obj is EnumFieldType { const modelField: keyof EnumFieldType = 'enum'; if (obj && obj[modelField]) return true; @@ -648,6 +717,12 @@ export type IdentifierFieldOrIdentifierObject< M extends PersistentModelMetaData, > = Pick> | IdentifierFieldValue; +/** + * @private + * @param obj + * @param modelDefinition + * @returns `true` if the given item is an object that has all identifier fields populated. + */ export function isIdentifierObject( obj: any, modelDefinition: SchemaModel, @@ -772,12 +847,22 @@ export interface PredicatesGroup { predicates: (PredicateObject | PredicatesGroup)[]; } +/** + * @private + * @param obj + * @returns `true` if the given predicate field object, specifying an [in-]equality test against a field. + */ export function isPredicateObj( obj: any, ): obj is PredicateObject { return obj && (obj as PredicateObject).field !== undefined; } +/** + * @private + * @param obj + * @returns `true` if the given predicate object is a "group" like "and", "or", or "not". + */ export function isPredicateGroup( obj: any, ): obj is PredicatesGroup { @@ -1032,6 +1117,34 @@ type ConditionProducer> = ( ...args: A ) => A['length'] extends keyof Lookup ? Lookup[A['length']] : never; +/** + * Build an expression that can be used to filter which items of a given Model + * are synchronized down from the GraphQL service. E.g., + * + * ```ts + * import { DataStore, syncExpression } from 'aws-amplify/datastore'; + * import { Post, Comment } from './models'; + * + * + * DataStore.configure({ + * syncExpressions: [ + * syncExpression(Post, () => { + * return (post) => post.rating.gt(5); + * }), + * syncExpression(Comment, () => { + * return (comment) => comment.status.eq('active'); + * }) + * ] + * }); + * ``` + * + * When DataStore starts syncing, only Posts with `rating > 5` and Comments with + * `status === 'active'` will be synced down to the user's local store. + * + * @param modelConstructor The Model from the schema. + * @param conditionProducer A function that builds a condition object that can describe how to filter the model. + * @returns An sync expression object that can be attached to the DataStore `syncExpressions` configuration property. + */ export async function syncExpression< T extends PersistentModel, A extends Option, diff --git a/packages/geo/CHANGELOG.md b/packages/geo/CHANGELOG.md index fa91c8a9580..274012c9430 100644 --- a/packages/geo/CHANGELOG.md +++ b/packages/geo/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.0.49](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/geo@3.0.48...@aws-amplify/geo@3.0.49) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/geo + +## [3.0.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/geo@3.0.47...@aws-amplify/geo@3.0.48) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/geo + +## [3.0.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/geo@3.0.46...@aws-amplify/geo@3.0.47) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/geo + +## [3.0.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/geo@3.0.45...@aws-amplify/geo@3.0.46) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/geo + +## [3.0.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/geo@3.0.44...@aws-amplify/geo@3.0.45) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/geo + +## [3.0.44](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/geo@3.0.43...@aws-amplify/geo@3.0.44) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/geo + ## [3.0.43](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/geo@3.0.42...@aws-amplify/geo@3.0.43) (2024-08-15) **Note:** Version bump only for package @aws-amplify/geo diff --git a/packages/geo/package.json b/packages/geo/package.json index 8381d2fcde9..d0a2ef0bfe6 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/geo", - "version": "3.0.43", + "version": "3.0.49", "description": "Geo category for aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -76,7 +76,7 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", + "@aws-amplify/core": "6.4.2", "typescript": "5.0.2" }, "size-limit": [ diff --git a/packages/interactions/CHANGELOG.md b/packages/interactions/CHANGELOG.md index feff5def1a3..bba981b2cb8 100644 --- a/packages/interactions/CHANGELOG.md +++ b/packages/interactions/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.0.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@6.0.47...@aws-amplify/interactions@6.0.48) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/interactions + +## [6.0.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@6.0.46...@aws-amplify/interactions@6.0.47) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/interactions + +## [6.0.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@6.0.45...@aws-amplify/interactions@6.0.46) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/interactions + +## [6.0.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@6.0.44...@aws-amplify/interactions@6.0.45) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/interactions + +## [6.0.44](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@6.0.43...@aws-amplify/interactions@6.0.44) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/interactions + +## [6.0.43](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@6.0.42...@aws-amplify/interactions@6.0.43) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/interactions + ## [6.0.42](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/interactions@6.0.41...@aws-amplify/interactions@6.0.42) (2024-08-15) **Note:** Version bump only for package @aws-amplify/interactions diff --git a/packages/interactions/package.json b/packages/interactions/package.json index 0627e71722c..2cba2e3b832 100644 --- a/packages/interactions/package.json +++ b/packages/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/interactions", - "version": "6.0.42", + "version": "6.0.48", "description": "Interactions category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -81,7 +81,7 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", + "@aws-amplify/core": "6.4.2", "typescript": "^5.0.2" }, "size-limit": [ diff --git a/packages/notifications/CHANGELOG.md b/packages/notifications/CHANGELOG.md index 5d799ca9684..c53699d38b7 100644 --- a/packages/notifications/CHANGELOG.md +++ b/packages/notifications/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.0.49](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/notifications@2.0.48...@aws-amplify/notifications@2.0.49) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/notifications + +## [2.0.48](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/notifications@2.0.47...@aws-amplify/notifications@2.0.48) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/notifications + +## [2.0.47](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/notifications@2.0.46...@aws-amplify/notifications@2.0.47) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/notifications + +## [2.0.46](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/notifications@2.0.45...@aws-amplify/notifications@2.0.46) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/notifications + +## [2.0.45](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/notifications@2.0.44...@aws-amplify/notifications@2.0.45) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/notifications + +## [2.0.44](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/notifications@2.0.43...@aws-amplify/notifications@2.0.44) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/notifications + ## [2.0.43](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/notifications@2.0.42...@aws-amplify/notifications@2.0.43) (2024-08-15) **Note:** Version bump only for package @aws-amplify/notifications diff --git a/packages/notifications/package.json b/packages/notifications/package.json index 27cc8e3b67b..b5165be75f9 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/notifications", - "version": "2.0.43", + "version": "2.0.49", "description": "Notifications category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -98,8 +98,8 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", - "@aws-amplify/react-native": "1.1.4", + "@aws-amplify/core": "6.4.2", + "@aws-amplify/react-native": "1.1.5", "typescript": "5.0.2" } } diff --git a/packages/predictions/CHANGELOG.md b/packages/predictions/CHANGELOG.md index c3223244fc4..3779351617a 100644 --- a/packages/predictions/CHANGELOG.md +++ b/packages/predictions/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.1.24](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@6.1.23...@aws-amplify/predictions@6.1.24) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/predictions + +## [6.1.23](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@6.1.22...@aws-amplify/predictions@6.1.23) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/predictions + +## [6.1.22](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@6.1.21...@aws-amplify/predictions@6.1.22) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/predictions + +## [6.1.21](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@6.1.20...@aws-amplify/predictions@6.1.21) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/predictions + +## [6.1.20](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@6.1.19...@aws-amplify/predictions@6.1.20) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/predictions + +## [6.1.19](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@6.1.18...@aws-amplify/predictions@6.1.19) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/predictions + ## [6.1.18](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/predictions@6.1.17...@aws-amplify/predictions@6.1.18) (2024-08-15) **Note:** Version bump only for package @aws-amplify/predictions diff --git a/packages/predictions/package.json b/packages/predictions/package.json index 6746909e1ef..69904a9fd29 100644 --- a/packages/predictions/package.json +++ b/packages/predictions/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/predictions", - "version": "6.1.18", + "version": "6.1.24", "description": "Machine learning category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -43,7 +43,7 @@ "src" ], "dependencies": { - "@aws-amplify/storage": "6.6.1", + "@aws-amplify/storage": "6.6.7", "@aws-sdk/client-comprehend": "3.621.0", "@aws-sdk/client-polly": "3.621.0", "@aws-sdk/client-rekognition": "3.621.0", @@ -59,7 +59,7 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", + "@aws-amplify/core": "6.4.2", "typescript": "5.0.2" }, "size-limit": [ diff --git a/packages/pubsub/CHANGELOG.md b/packages/pubsub/CHANGELOG.md index 3898302af49..bb73137f569 100644 --- a/packages/pubsub/CHANGELOG.md +++ b/packages/pubsub/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.1.24](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@6.1.23...@aws-amplify/pubsub@6.1.24) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/pubsub + +## [6.1.23](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@6.1.22...@aws-amplify/pubsub@6.1.23) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/pubsub + +## [6.1.22](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@6.1.21...@aws-amplify/pubsub@6.1.22) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/pubsub + +## [6.1.21](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@6.1.20...@aws-amplify/pubsub@6.1.21) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/pubsub + +## [6.1.20](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@6.1.19...@aws-amplify/pubsub@6.1.20) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/pubsub + +## [6.1.19](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@6.1.18...@aws-amplify/pubsub@6.1.19) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/pubsub + ## [6.1.18](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/pubsub@6.1.17...@aws-amplify/pubsub@6.1.18) (2024-08-15) **Note:** Version bump only for package @aws-amplify/pubsub diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index 476d00daa09..76d5f6997cd 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/pubsub", - "version": "6.1.18", + "version": "6.1.24", "description": "Pubsub category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -73,7 +73,7 @@ "mqtt" ], "dependencies": { - "@aws-amplify/auth": "6.3.14", + "@aws-amplify/auth": "6.4.2", "buffer": "4.9.2", "graphql": "15.8.0", "rxjs": "^7.8.1", @@ -84,7 +84,7 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@aws-amplify/core": "6.3.10", + "@aws-amplify/core": "6.4.2", "typescript": "5.0.2" }, "size-limit": [ diff --git a/packages/react-native/CHANGELOG.md b/packages/react-native/CHANGELOG.md index 9798ff01dbc..b0781ff55cd 100644 --- a/packages/react-native/CHANGELOG.md +++ b/packages/react-native/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.1.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/react-native@1.1.4...@aws-amplify/react-native@1.1.5) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/react-native + ## [1.1.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/react-native@1.1.3...@aws-amplify/react-native@1.1.4) (2024-07-23) **Note:** Version bump only for package @aws-amplify/react-native diff --git a/packages/react-native/package.json b/packages/react-native/package.json index b347135b43a..a8f470b33e1 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/react-native", - "version": "1.1.4", + "version": "1.1.5", "description": "React Native core module for aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -34,7 +34,7 @@ }, "devDependencies": { "@aws-amplify/rtn-push-notification": "1.2.31", - "@aws-amplify/rtn-web-browser": "1.0.31", + "@aws-amplify/rtn-web-browser": "1.1.0", "@react-native-async-storage/async-storage": "^1.17.12", "@react-native-community/netinfo": "4.7.0", "@types/base-64": "1.0.0", diff --git a/packages/rtn-web-browser/CHANGELOG.md b/packages/rtn-web-browser/CHANGELOG.md index 22f6623f5a2..468990e929c 100644 --- a/packages/rtn-web-browser/CHANGELOG.md +++ b/packages/rtn-web-browser/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.1.0](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/rtn-web-browser@1.0.31...@aws-amplify/rtn-web-browser@1.1.0) (2024-09-04) + +### Features + +- **auth:** HostedUI oidc signout ([#13512](https://github.com/aws-amplify/amplify-js/issues/13512)) ([e8fb997](https://github.com/aws-amplify/amplify-js/commit/e8fb9973f8e3e3490619416a778ec1460cafaf9a)), closes [#13712](https://github.com/aws-amplify/amplify-js/issues/13712) [#13736](https://github.com/aws-amplify/amplify-js/issues/13736) + ## [1.0.31](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/rtn-web-browser@1.0.30...@aws-amplify/rtn-web-browser@1.0.31) (2024-07-23) ### Bug Fixes diff --git a/packages/rtn-web-browser/android/src/main/kotlin/com/amazonaws/amplify/rtnwebbrowser/WebBrowserModule.kt b/packages/rtn-web-browser/android/src/main/kotlin/com/amazonaws/amplify/rtnwebbrowser/WebBrowserModule.kt index eaa7fe5eaba..e883b90a20b 100644 --- a/packages/rtn-web-browser/android/src/main/kotlin/com/amazonaws/amplify/rtnwebbrowser/WebBrowserModule.kt +++ b/packages/rtn-web-browser/android/src/main/kotlin/com/amazonaws/amplify/rtnwebbrowser/WebBrowserModule.kt @@ -44,6 +44,7 @@ class WebBrowserModule( getCustomTabsPackageName(reactApplicationContext)?.let { val customTabsIntent = CustomTabsIntent.Builder(connection?.getSession()).build() customTabsIntent.intent.setPackage(it).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + customTabsIntent.intent.setPackage(it).addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) customTabsIntent.launchUrl(reactApplicationContext, Uri.parse(uriStr)) } ?: run { promise.reject(Throwable("No eligible browser found on device")) diff --git a/packages/rtn-web-browser/package.json b/packages/rtn-web-browser/package.json index e1b0366cef3..f9230a22232 100644 --- a/packages/rtn-web-browser/package.json +++ b/packages/rtn-web-browser/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/rtn-web-browser", - "version": "1.0.31", + "version": "1.1.0", "description": "React Native module for aws-amplify web browser", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -25,7 +25,7 @@ }, "devDependencies": { "@types/react-native": "0.70.0", - "react-native": "0.72.3", + "react-native": "0.72.15", "typescript": "5.1.6" }, "repository": { diff --git a/packages/storage/CHANGELOG.md b/packages/storage/CHANGELOG.md index 64563604a5e..1e3f7c7d995 100644 --- a/packages/storage/CHANGELOG.md +++ b/packages/storage/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.6.7](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@6.6.6...@aws-amplify/storage@6.6.7) (2024-09-17) + +**Note:** Version bump only for package @aws-amplify/storage + +## [6.6.6](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@6.6.5...@aws-amplify/storage@6.6.6) (2024-09-16) + +**Note:** Version bump only for package @aws-amplify/storage + +## [6.6.5](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@6.6.4...@aws-amplify/storage@6.6.5) (2024-09-04) + +**Note:** Version bump only for package @aws-amplify/storage + +## [6.6.4](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@6.6.3...@aws-amplify/storage@6.6.4) (2024-09-03) + +**Note:** Version bump only for package @aws-amplify/storage + +## [6.6.3](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@6.6.2...@aws-amplify/storage@6.6.3) (2024-08-26) + +**Note:** Version bump only for package @aws-amplify/storage + +## [6.6.2](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@6.6.1...@aws-amplify/storage@6.6.2) (2024-08-21) + +**Note:** Version bump only for package @aws-amplify/storage + ## [6.6.1](https://github.com/aws-amplify/amplify-js/compare/@aws-amplify/storage@6.6.0...@aws-amplify/storage@6.6.1) (2024-08-15) **Note:** Version bump only for package @aws-amplify/storage diff --git a/packages/storage/__tests__/providers/s3/apis/uploadData/byteLength.test.ts b/packages/storage/__tests__/providers/s3/apis/uploadData/byteLength.test.ts new file mode 100644 index 00000000000..24b46ac4f0d --- /dev/null +++ b/packages/storage/__tests__/providers/s3/apis/uploadData/byteLength.test.ts @@ -0,0 +1,39 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { byteLength } from '../../../../../src/providers/s3/apis/uploadData/byteLength'; + +describe('byteLength', () => { + it('returns 0 for null or undefined', () => { + expect(byteLength(undefined)).toBe(0); + expect(byteLength(null)).toBe(0); + }); + + it('calculates byte length correctly for ASCII strings', () => { + expect(byteLength('hello')).toBe(5); + }); + + it('calculates byte length correctly for multi-byte characters', () => { + expect(byteLength('èちは')).toBe(8); + }); + + it('handles Uint8Array correctly', () => { + const input = new Uint8Array([1, 2, 3]); + expect(byteLength(input)).toBe(3); + }); + + it('handles ArrayBuffer correctly', () => { + const buffer = new ArrayBuffer(8); + expect(byteLength(buffer)).toBe(8); + }); + + it('handles File object correctly', () => { + const file = new Blob(['hello']); + expect(byteLength(file)).toBe(5); + }); + + it('returns undefined for unsupported types', () => { + const input = { unsupportedType: true }; + expect(byteLength(input)).toBeUndefined(); + }); +}); diff --git a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getDataAccess.ts b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getDataAccess.ts index b0a0d174a7a..851bc993a7c 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getDataAccess.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getDataAccess.ts @@ -83,12 +83,14 @@ const getDataAccessErrorCase: ApiFunctionalTestCase = [ headers: DEFAULT_RESPONSE_HEADERS, body: ` - - AccessDenied - Access Denied + + + AccessDenied + Access Denied + 656c76696e6727732072657175657374 Uuag1LuByRx9e6j5Onimru9pO4ZVKnJ2Qz7/C1NPcfTWAtRPfTaOFg== - + `, }, { diff --git a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listCallerAccessGrants.ts b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listCallerAccessGrants.ts index f63c80bf4bc..961ef27b3bf 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listCallerAccessGrants.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listCallerAccessGrants.ts @@ -149,12 +149,14 @@ const listCallerAccessGrantsErrorCase: ApiFunctionalTestCase< headers: DEFAULT_RESPONSE_HEADERS, body: ` - - AccessDenied - Access Denied + + + AccessDenied + Access Denied + 656c76696e6727732072657175657374 Uuag1LuByRx9e6j5Onimru9pO4ZVKnJ2Qz7/C1NPcfTWAtRPfTaOFg== - + `, }, { diff --git a/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts b/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts index b47d2ec7695..a3754b41707 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts @@ -3,7 +3,7 @@ import { HttpRequest } from '@aws-amplify/core/internals/aws-client-utils'; -interface MockFetchResponse { +export interface MockFetchResponse { body: BodyInit; headers: HeadersInit; status: number; diff --git a/packages/storage/__tests__/providers/s3/utils/client/utils/retryDecider.test.ts b/packages/storage/__tests__/providers/s3/utils/client/utils/createRetryDecider.test.ts similarity index 86% rename from packages/storage/__tests__/providers/s3/utils/client/utils/retryDecider.test.ts rename to packages/storage/__tests__/providers/s3/utils/client/utils/createRetryDecider.test.ts index 018a8deb4e7..935ec823794 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/utils/retryDecider.test.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/utils/createRetryDecider.test.ts @@ -5,15 +5,13 @@ import { getRetryDecider as getDefaultRetryDecider, } from '@aws-amplify/core/internals/aws-client-utils'; -import { retryDecider } from '../../../../../../src/providers/s3/utils/client/utils'; -import { parseXmlError } from '../../../../../../src/providers/s3/utils/client/utils/parsePayload'; +import { createRetryDecider } from '../../../../../../src/providers/s3/utils/client/utils'; -jest.mock('../../../../../../src/providers/s3/utils/client/utils/parsePayload'); jest.mock('@aws-amplify/core/internals/aws-client-utils'); -const mockErrorParser = jest.mocked(parseXmlError); +const mockErrorParser = jest.fn(); -describe('retryDecider', () => { +describe('createRetryDecider', () => { const mockHttpResponse: HttpResponse = { statusCode: 200, headers: {}, @@ -32,6 +30,7 @@ describe('retryDecider', () => { it('should invoke the default retry decider', async () => { expect.assertions(3); + const retryDecider = createRetryDecider(mockErrorParser); const { retryable, isCredentialsExpiredError } = await retryDecider( mockHttpResponse, undefined, @@ -54,6 +53,7 @@ describe('retryDecider', () => { $metadata: {}, }; mockErrorParser.mockResolvedValue(parsedError); + const retryDecider = createRetryDecider(mockErrorParser); const { retryable, isCredentialsExpiredError } = await retryDecider( { ...mockHttpResponse, statusCode: 400 }, undefined, @@ -72,6 +72,7 @@ describe('retryDecider', () => { $metadata: {}, }; mockErrorParser.mockResolvedValue(parsedError); + const retryDecider = createRetryDecider(mockErrorParser); const { retryable, isCredentialsExpiredError } = await retryDecider( { ...mockHttpResponse, statusCode: 400 }, undefined, @@ -89,6 +90,7 @@ describe('retryDecider', () => { $metadata: {}, }; mockErrorParser.mockResolvedValue(parsedError); + const retryDecider = createRetryDecider(mockErrorParser); const { retryable, isCredentialsExpiredError } = await retryDecider( { ...mockHttpResponse, statusCode: 400 }, undefined, diff --git a/packages/storage/__tests__/providers/s3/utils/md5.native.test.ts b/packages/storage/__tests__/providers/s3/utils/md5.native.test.ts index aea1eab7743..ec70d0a8e14 100644 --- a/packages/storage/__tests__/providers/s3/utils/md5.native.test.ts +++ b/packages/storage/__tests__/providers/s3/utils/md5.native.test.ts @@ -69,23 +69,23 @@ describe('calculateContentMd5 (native)', () => { mockMd5.mockReset(); }); - it('calculates MD5 for content type: string', async () => { - await calculateContentMd5(stringContent); - const [mockMd5Instance] = mockMd5.mock.instances; - expect(mockMd5Instance.update.mock.calls[0][0]).toBe(stringContent); - expect(mockToBase64).toHaveBeenCalled(); - }); - it.each([ + { type: 'string', content: stringContent }, { type: 'ArrayBuffer view', content: new Uint8Array() }, { type: 'ArrayBuffer', content: new ArrayBuffer(8) }, - { type: 'Blob', content: new Blob([stringContent]) }, ])('calculates MD5 for content type: $type', async ({ content }) => { + await calculateContentMd5(content); + const [mockMd5Instance] = mockMd5.mock.instances; + expect(mockMd5Instance.update.mock.calls[0][0]).toBe(content); + expect(mockToBase64).toHaveBeenCalled(); + }); + + it('calculates MD5 for content type: blob', async () => { Object.defineProperty(global, 'FileReader', { writable: true, value: jest.fn(() => mockSuccessfulFileReader), }); - await calculateContentMd5(content); + await calculateContentMd5(new Blob([stringContent])); const [mockMd5Instance] = mockMd5.mock.instances; expect(mockMd5Instance.update.mock.calls[0][0]).toBe(fileReaderResult); expect(mockSuccessfulFileReader.readAsArrayBuffer).toHaveBeenCalled(); diff --git a/packages/storage/__tests__/providers/s3/utils/md5.test.ts b/packages/storage/__tests__/providers/s3/utils/md5.test.ts index 2de7f7dfd0e..7412d58e571 100644 --- a/packages/storage/__tests__/providers/s3/utils/md5.test.ts +++ b/packages/storage/__tests__/providers/s3/utils/md5.test.ts @@ -46,23 +46,23 @@ describe('calculateContentMd5', () => { mockMd5.mockReset(); }); - it('calculates MD5 for content type: string', async () => { - await calculateContentMd5(stringContent); - const [mockMd5Instance] = mockMd5.mock.instances; - expect(mockMd5Instance.update.mock.calls[0][0]).toBe(stringContent); - expect(mockToBase64).toHaveBeenCalled(); - }); - it.each([ + { type: 'string', content: stringContent }, { type: 'ArrayBuffer view', content: new Uint8Array() }, { type: 'ArrayBuffer', content: new ArrayBuffer(8) }, - { type: 'Blob', content: new Blob([stringContent]) }, ])('calculates MD5 for content type: $type', async ({ content }) => { + await calculateContentMd5(content); + const [mockMd5Instance] = mockMd5.mock.instances; + expect(mockMd5Instance.update.mock.calls[0][0]).toBe(content); + expect(mockToBase64).toHaveBeenCalled(); + }); + + it('calculates MD5 for content type: blob', async () => { Object.defineProperty(global, 'FileReader', { writable: true, value: jest.fn(() => mockSuccessfulFileReader), }); - await calculateContentMd5(content); + await calculateContentMd5(new Blob([stringContent])); const [mockMd5Instance] = mockMd5.mock.instances; expect(mockMd5Instance.update.mock.calls[0][0]).toBe(fileReaderResult); expect(mockSuccessfulFileReader.readAsArrayBuffer).toHaveBeenCalled(); diff --git a/packages/storage/package.json b/packages/storage/package.json index cede9aae2f7..7e9fa894ac3 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/storage", - "version": "6.6.1", + "version": "6.6.7", "description": "Storage category of aws-amplify", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.mjs", @@ -73,7 +73,7 @@ "@aws-sdk/types": "3.398.0", "@smithy/md5-js": "2.0.7", "buffer": "4.9.2", - "crc-32": "^1.2.2", + "crc-32": "1.2.2", "fast-xml-parser": "^4.4.1", "tslib": "^2.5.0" }, @@ -111,9 +111,9 @@ "@aws-amplify/core": "^6.1.0" }, "devDependencies": { - "@types/node": "20.14.12", - "@aws-amplify/core": "6.3.10", - "@aws-amplify/react-native": "1.1.4", + "@aws-amplify/core": "6.4.2", + "@types/node": "20.14.12", + "@aws-amplify/react-native": "1.1.5", "typescript": "5.0.2" } } diff --git a/packages/storage/src/errors/CanceledError.ts b/packages/storage/src/errors/CanceledError.ts index 9388653432a..da069ab1f13 100644 --- a/packages/storage/src/errors/CanceledError.ts +++ b/packages/storage/src/errors/CanceledError.ts @@ -28,6 +28,8 @@ export class CanceledError extends StorageError { /** * Check if an error is caused by user calling `cancel()` on a upload/download task. If an overwriting error is * supplied to `task.cancel(errorOverwrite)`, this function will return `false`. + * @param {unknown} error The unknown exception to be checked. + * @returns - A boolean indicating if the error was from an upload cancellation */ export const isCancelError = (error: unknown): error is CanceledError => !!error && error instanceof CanceledError; diff --git a/packages/storage/src/providers/s3/apis/internal/list.ts b/packages/storage/src/providers/s3/apis/internal/list.ts index 041efda1d9e..49b1ee93df8 100644 --- a/packages/storage/src/providers/s3/apis/internal/list.ts +++ b/packages/storage/src/providers/s3/apis/internal/list.ts @@ -21,8 +21,8 @@ import { validateStorageOperationInputWithPrefix, } from '../../utils'; import { - ListAllOptionsWithPath, - ListPaginateOptionsWithPath, + ListAllWithPathOptions, + ListPaginateWithPathOptions, ResolvedS3Config, } from '../../types/options'; import { @@ -274,7 +274,7 @@ const mapCommonPrefixesToExcludedSubpaths = ( }; const getDelimiter = ( - options?: ListAllOptionsWithPath | ListPaginateOptionsWithPath, + options?: ListAllWithPathOptions | ListPaginateWithPathOptions, ): string | undefined => { if (options?.subpathStrategy?.strategy === 'exclude') { return options?.subpathStrategy?.delimiter ?? DEFAULT_DELIMITER; diff --git a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts index 0c3379d04d2..f1869ac618a 100644 --- a/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts +++ b/packages/storage/src/providers/s3/apis/uploadData/multipart/uploadHandlers.ts @@ -17,7 +17,7 @@ import { } from '../../../utils/constants'; import { ResolvedS3Config, - UploadDataOptionsWithKey, + UploadDataWithKeyOptions, } from '../../../types/options'; import { StorageError } from '../../../../../errors/StorageError'; import { CanceledError } from '../../../../../errors/CanceledError'; @@ -102,7 +102,7 @@ export const getMultipartUploadHandlers = ( // Resolve "key" specific options if (inputType === STORAGE_INPUT_KEY) { - const accessLevel = (uploadDataOptions as UploadDataOptionsWithKey) + const accessLevel = (uploadDataOptions as UploadDataWithKeyOptions) ?.accessLevel; resolvedKeyPrefix = resolvedS3Options.keyPrefix; diff --git a/packages/storage/src/providers/s3/types/errors.ts b/packages/storage/src/providers/s3/types/errors.ts deleted file mode 100644 index 9d757af7b6f..00000000000 --- a/packages/storage/src/providers/s3/types/errors.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -export enum S3Exception { - NotFoundException = 'NotFoundException', - ForbiddenException = 'ForbiddenException', - BadRequestException = 'BadRequestException', -} diff --git a/packages/storage/src/providers/s3/types/index.ts b/packages/storage/src/providers/s3/types/index.ts index 4efd666fb33..d38e3b8b523 100644 --- a/packages/storage/src/providers/s3/types/index.ts +++ b/packages/storage/src/providers/s3/types/index.ts @@ -2,23 +2,21 @@ // SPDX-License-Identifier: Apache-2.0 export { - GetUrlOptionsWithKey, - GetUrlOptionsWithPath, - UploadDataOptionsWithPath, - UploadDataOptionsWithKey, - GetPropertiesOptionsWithKey, - GetPropertiesOptionsWithPath, - ListAllOptionsWithPrefix, - ListPaginateOptionsWithPrefix, - ListAllOptionsWithPath, - ListPaginateOptionsWithPath, + GetUrlWithKeyOptions, + GetUrlWithPathOptions, + UploadDataWithPathOptions, + UploadDataWithKeyOptions, + GetPropertiesWithKeyOptions, + GetPropertiesWithPathOptions, + ListAllWithPrefixOptions, + ListPaginateWithPrefixOptions, + ListAllWithPathOptions, + ListPaginateWithPathOptions, RemoveOptions, - DownloadDataOptionsWithPath, - DownloadDataOptionsWithKey, - CopyDestinationOptionsWithKey, - CopySourceOptionsWithKey, - CopyWithPathSourceOptions, - CopyWithPathDestinationOptions, + DownloadDataWithPathOptions, + DownloadDataWithKeyOptions, + CopyDestinationWithKeyOptions, + CopySourceWithKeyOptions, } from './options'; export { UploadDataOutput, @@ -58,4 +56,3 @@ export { ListAllWithPathInput, ListPaginateWithPathInput, } from './inputs'; -export { S3Exception } from './errors'; diff --git a/packages/storage/src/providers/s3/types/inputs.ts b/packages/storage/src/providers/s3/types/inputs.ts index 98d978d9539..041451fbfd5 100644 --- a/packages/storage/src/providers/s3/types/inputs.ts +++ b/packages/storage/src/providers/s3/types/inputs.ts @@ -19,21 +19,21 @@ import { } from '../../../types'; import { StorageOperationOptionsInput } from '../../../types/inputs'; import { - CopyDestinationOptionsWithKey, - CopySourceOptionsWithKey, - DownloadDataOptionsWithKey, - DownloadDataOptionsWithPath, - GetPropertiesOptionsWithKey, - GetPropertiesOptionsWithPath, - GetUrlOptionsWithKey, - GetUrlOptionsWithPath, - ListAllOptionsWithPath, - ListAllOptionsWithPrefix, - ListPaginateOptionsWithPath, - ListPaginateOptionsWithPrefix, + CopyDestinationWithKeyOptions, + CopySourceWithKeyOptions, + DownloadDataWithKeyOptions, + DownloadDataWithPathOptions, + GetPropertiesWithKeyOptions, + GetPropertiesWithPathOptions, + GetUrlWithKeyOptions, + GetUrlWithPathOptions, + ListAllWithPathOptions, + ListAllWithPrefixOptions, + ListPaginateWithPathOptions, + ListPaginateWithPrefixOptions, RemoveOptions, - UploadDataOptionsWithKey, - UploadDataOptionsWithPath, + UploadDataWithKeyOptions, + UploadDataWithPathOptions, } from '../types'; import { LocationCredentialsProvider } from './options'; @@ -44,8 +44,8 @@ import { LocationCredentialsProvider } from './options'; * Input type for S3 copy API. */ export type CopyInput = StorageCopyInputWithKey< - CopySourceOptionsWithKey, - CopyDestinationOptionsWithKey + CopySourceWithKeyOptions, + CopyDestinationWithKeyOptions >; /** * Input type with path for S3 copy API. @@ -60,48 +60,48 @@ export type CopyWithPathInput = StorageCopyInputWithPath & * Input type for S3 getProperties API. */ export type GetPropertiesInput = - StorageGetPropertiesInputWithKey; + StorageGetPropertiesInputWithKey; /** * Input type with for S3 getProperties API. */ export type GetPropertiesWithPathInput = - StorageGetPropertiesInputWithPath; + StorageGetPropertiesInputWithPath; /** * @deprecated Use {@link GetUrlWithPathInput} instead. * Input type for S3 getUrl API. */ -export type GetUrlInput = StorageGetUrlInputWithKey; +export type GetUrlInput = StorageGetUrlInputWithKey; /** * Input type with path for S3 getUrl API. */ export type GetUrlWithPathInput = - StorageGetUrlInputWithPath; + StorageGetUrlInputWithPath; /** * Input type with path for S3 list API. Lists all bucket objects. */ export type ListAllWithPathInput = - StorageListInputWithPath; + StorageListInputWithPath; /** * Input type with path for S3 list API. Lists bucket objects with pagination. */ export type ListPaginateWithPathInput = - StorageListInputWithPath; + StorageListInputWithPath; /** * @deprecated Use {@link ListAllWithPathInput} instead. * Input type for S3 list API. Lists all bucket objects. */ -export type ListAllInput = StorageListInputWithPrefix; +export type ListAllInput = StorageListInputWithPrefix; /** * @deprecated Use {@link ListPaginateWithPathInput} instead. * Input type for S3 list API. Lists bucket objects with pagination. */ export type ListPaginateInput = - StorageListInputWithPrefix; + StorageListInputWithPrefix; /** * @deprecated Use {@link RemoveWithPathInput} instead. @@ -121,23 +121,23 @@ export type RemoveWithPathInput = StorageRemoveInputWithPath< * Input type for S3 downloadData API. */ export type DownloadDataInput = - StorageDownloadDataInputWithKey; + StorageDownloadDataInputWithKey; /** * Input type with path for S3 downloadData API. */ export type DownloadDataWithPathInput = - StorageDownloadDataInputWithPath; + StorageDownloadDataInputWithPath; /** * @deprecated Use {@link UploadDataWithPathInput} instead. * Input type for S3 uploadData API. */ export type UploadDataInput = - StorageUploadDataInputWithKey; + StorageUploadDataInputWithKey; /** * Input type with path for S3 uploadData API. */ export type UploadDataWithPathInput = - StorageUploadDataInputWithPath; + StorageUploadDataInputWithPath; diff --git a/packages/storage/src/providers/s3/types/options.ts b/packages/storage/src/providers/s3/types/options.ts index 33e3b8e1c14..f181800408c 100644 --- a/packages/storage/src/providers/s3/types/options.ts +++ b/packages/storage/src/providers/s3/types/options.ts @@ -103,9 +103,9 @@ interface TransferOptions { /** * Input options type for S3 getProperties API. */ -/** @deprecated Use {@link GetPropertiesOptionsWithPath} instead. */ -export type GetPropertiesOptionsWithKey = ReadOptions & CommonOptions; -export type GetPropertiesOptionsWithPath = CommonOptions; +/** @deprecated Use {@link GetPropertiesWithPathOptions} instead. */ +export type GetPropertiesWithKeyOptions = ReadOptions & CommonOptions; +export type GetPropertiesWithPathOptions = CommonOptions; /** * Input options type for S3 getProperties API. @@ -113,25 +113,25 @@ export type GetPropertiesOptionsWithPath = CommonOptions; export type RemoveOptions = WriteOptions & CommonOptions; /** - * @deprecated Use {@link ListAllOptionsWithPath} instead. + * @deprecated Use {@link ListAllWithPathOptions} instead. * Input options type with prefix for S3 list all API. */ -export type ListAllOptionsWithPrefix = StorageListAllOptions & +export type ListAllWithPrefixOptions = StorageListAllOptions & ReadOptions & CommonOptions; /** - * @deprecated Use {@link ListPaginateOptionsWithPath} instead. + * @deprecated Use {@link ListPaginateWithPathOptions} instead. * Input options type with prefix for S3 list API to paginate items. */ -export type ListPaginateOptionsWithPrefix = StorageListPaginateOptions & +export type ListPaginateWithPrefixOptions = StorageListPaginateOptions & ReadOptions & CommonOptions; /** * Input options type with path for S3 list all API. */ -export type ListAllOptionsWithPath = Omit< +export type ListAllWithPathOptions = Omit< StorageListAllOptions, 'accessLevel' > & @@ -142,7 +142,7 @@ export type ListAllOptionsWithPath = Omit< /** * Input options type with path for S3 list API to paginate items. */ -export type ListPaginateOptionsWithPath = Omit< +export type ListPaginateWithPathOptions = Omit< StorageListPaginateOptions, 'accessLevel' > & @@ -179,9 +179,9 @@ export type GetUrlOptions = CommonOptions & { contentType?: string; }; -/** @deprecated Use {@link GetUrlOptionsWithPath} instead. */ -export type GetUrlOptionsWithKey = ReadOptions & GetUrlOptions; -export type GetUrlOptionsWithPath = GetUrlOptions; +/** @deprecated Use {@link GetUrlWithPathOptions} instead. */ +export type GetUrlWithKeyOptions = ReadOptions & GetUrlOptions; +export type GetUrlWithPathOptions = GetUrlOptions; /** * Input options type for S3 downloadData API. @@ -190,9 +190,9 @@ export type DownloadDataOptions = CommonOptions & TransferOptions & BytesRangeOptions; -/** @deprecated Use {@link DownloadDataOptionsWithPath} instead. */ -export type DownloadDataOptionsWithKey = ReadOptions & DownloadDataOptions; -export type DownloadDataOptionsWithPath = DownloadDataOptions; +/** @deprecated Use {@link DownloadDataWithPathOptions} instead. */ +export type DownloadDataWithKeyOptions = ReadOptions & DownloadDataOptions; +export type DownloadDataWithPathOptions = DownloadDataOptions; export type UploadDataOptions = CommonOptions & TransferOptions & { @@ -226,12 +226,12 @@ export type UploadDataOptions = CommonOptions & preventOverwrite?: boolean; }; -/** @deprecated Use {@link UploadDataOptionsWithPath} instead. */ -export type UploadDataOptionsWithKey = WriteOptions & UploadDataOptions; -export type UploadDataOptionsWithPath = UploadDataOptions; +/** @deprecated Use {@link UploadDataWithPathOptions} instead. */ +export type UploadDataWithKeyOptions = WriteOptions & UploadDataOptions; +export type UploadDataWithPathOptions = UploadDataOptions; /** @deprecated This may be removed in the next major version. */ -export type CopySourceOptionsWithKey = ReadOptions & { +export type CopySourceWithKeyOptions = ReadOptions & { /** @deprecated This may be removed in the next major version. */ key: string; bucket?: StorageBucket; @@ -240,7 +240,7 @@ export type CopySourceOptionsWithKey = ReadOptions & { }; /** @deprecated This may be removed in the next major version. */ -export type CopyDestinationOptionsWithKey = WriteOptions & { +export type CopyDestinationWithKeyOptions = WriteOptions & { /** @deprecated This may be removed in the next major version. */ key: string; bucket?: StorageBucket; diff --git a/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts b/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts index 371b4d8efa6..eabb0865e04 100644 --- a/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts +++ b/packages/storage/src/providers/s3/utils/client/runtime/xhrTransferHandler.ts @@ -12,6 +12,7 @@ import { ConsoleLogger } from '@aws-amplify/core'; import { TransferProgressEvent } from '../../../../../types/common'; import { CanceledError } from '../../../../../errors/CanceledError'; +import { StorageError } from '../../../../../errors/StorageError'; import { ABORT_ERROR_CODE, @@ -80,10 +81,10 @@ export const xhrTransferHandler: TransferHandler< } xhr.addEventListener('error', () => { - const networkError = buildHandlerError( - NETWORK_ERROR_MESSAGE, - NETWORK_ERROR_CODE, - ); + const networkError = new StorageError({ + message: NETWORK_ERROR_MESSAGE, + name: NETWORK_ERROR_CODE, + }); logger.error(NETWORK_ERROR_MESSAGE); reject(networkError); xhr = null; // clean up request diff --git a/packages/storage/src/providers/s3/utils/client/s3control/base.ts b/packages/storage/src/providers/s3/utils/client/s3control/base.ts index a40f9f6a5dd..590f2b26120 100644 --- a/packages/storage/src/providers/s3/utils/client/s3control/base.ts +++ b/packages/storage/src/providers/s3/utils/client/s3control/base.ts @@ -11,7 +11,7 @@ import { jitteredBackoff, } from '@aws-amplify/core/internals/aws-client-utils'; -import { retryDecider } from '../utils'; +import { createRetryDecider, createXmlErrorParser } from '../utils'; /** * The service name used to sign requests if the API requires authentication. @@ -57,6 +57,33 @@ const endpointResolver = ( return { url: endpoint }; }; +/** + * Error parser for the XML payload of S3 control plane error response. The + * error's `Code` and `Message` locates at the nested `Error` element instead of + * the XML root element. + * + * @example + * ``` + * + * + * + * AccessDenied + * Access Denied + * + * 656c76696e6727732072657175657374 + * Uuag1LuByRx9e6j5Onimru9pO4ZVKnJ2Qz7/C1NPcfTWAtRPfTaOFg== + * + * ``` + * + * @internal + */ +export const parseXmlError = createXmlErrorParser(); + +/** + * @internal + */ +export const retryDecider = createRetryDecider(parseXmlError); + /** * @internal */ diff --git a/packages/storage/src/providers/s3/utils/client/s3control/getDataAccess.ts b/packages/storage/src/providers/s3/utils/client/s3control/getDataAccess.ts index f1053d8ddd7..84adb14e8aa 100644 --- a/packages/storage/src/providers/s3/utils/client/s3control/getDataAccess.ts +++ b/packages/storage/src/providers/s3/utils/client/s3control/getDataAccess.ts @@ -7,11 +7,11 @@ import { HttpResponse, parseMetadata, } from '@aws-amplify/core/internals/aws-client-utils'; +import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; import { AmplifyUrl, AmplifyUrlSearchParams, } from '@aws-amplify/core/internals/utils'; -import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; import { assignStringVariables, @@ -19,7 +19,6 @@ import { deserializeTimestamp, map, parseXmlBody, - parseXmlError, s3TransferHandler, } from '../utils'; @@ -27,7 +26,7 @@ import type { GetDataAccessCommandInput, GetDataAccessCommandOutput, } from './types'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type GetDataAccessInput = GetDataAccessCommandInput; diff --git a/packages/storage/src/providers/s3/utils/client/s3control/listCallerAccessGrants.ts b/packages/storage/src/providers/s3/utils/client/s3control/listCallerAccessGrants.ts index a1e7038749d..81b0e62a9c8 100644 --- a/packages/storage/src/providers/s3/utils/client/s3control/listCallerAccessGrants.ts +++ b/packages/storage/src/providers/s3/utils/client/s3control/listCallerAccessGrants.ts @@ -19,7 +19,6 @@ import { emptyArrayGuard, map, parseXmlBody, - parseXmlError, s3TransferHandler, } from '../utils'; import { createStringEnumDeserializer } from '../utils/deserializeHelpers'; @@ -28,7 +27,7 @@ import type { ListCallerAccessGrantsCommandInput, ListCallerAccessGrantsCommandOutput, } from './types'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type ListCallerAccessGrantsInput = ListCallerAccessGrantsCommandInput; diff --git a/packages/storage/src/providers/s3/utils/client/s3data/abortMultipartUpload.ts b/packages/storage/src/providers/s3/utils/client/s3data/abortMultipartUpload.ts index c3bea1e1d7f..eb8036da645 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/abortMultipartUpload.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/abortMultipartUpload.ts @@ -16,7 +16,6 @@ import { MetadataBearer } from '@aws-sdk/types'; import { buildStorageServiceError, - parseXmlError, s3TransferHandler, serializePathnameObjectKey, validateS3RequiredParameter, @@ -24,7 +23,7 @@ import { import { validateObjectUrl } from '../../validateObjectUrl'; import type { AbortMultipartUploadCommandInput } from './types'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type AbortMultipartUploadInput = Pick< AbortMultipartUploadCommandInput, diff --git a/packages/storage/src/providers/s3/utils/client/s3data/base.ts b/packages/storage/src/providers/s3/utils/client/s3data/base.ts index d51c3a18a11..c7aef5c033c 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/base.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/base.ts @@ -11,7 +11,7 @@ import { jitteredBackoff, } from '@aws-amplify/core/internals/aws-client-utils'; -import { retryDecider } from '../utils'; +import { createRetryDecider, createXmlErrorParser } from '../utils'; const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/; const IP_ADDRESS_PATTERN = /(\d+\.){3}\d+/; @@ -99,6 +99,30 @@ export const isDnsCompatibleBucketName = (bucketName: string): boolean => !IP_ADDRESS_PATTERN.test(bucketName) && !DOTS_PATTERN.test(bucketName); +/** + * Error parser for the XML payload of S3 data plane error response. The error's + * `Code` and `Message` locates directly at the XML root element. + * + * @example + * ``` + * + * + * NoSuchKey + * The resource you requested does not exist + * /mybucket/myfoto.jpg + * 4442587FB7D0A2F9 + * + * ``` + * + * @internal + */ +export const parseXmlError = createXmlErrorParser({ noErrorWrapping: true }); + +/** + * @internal + */ +export const retryDecider = createRetryDecider(parseXmlError); + /** * @internal */ diff --git a/packages/storage/src/providers/s3/utils/client/s3data/completeMultipartUpload.ts b/packages/storage/src/providers/s3/utils/client/s3data/completeMultipartUpload.ts index ff813d3a326..e9f810d76ed 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/completeMultipartUpload.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/completeMultipartUpload.ts @@ -20,8 +20,6 @@ import { buildStorageServiceError, map, parseXmlBody, - parseXmlError, - retryDecider, s3TransferHandler, serializePathnameObjectKey, validateS3RequiredParameter, @@ -29,7 +27,7 @@ import { import { validateObjectUrl } from '../../validateObjectUrl'; import { validateMultipartUploadXML } from '../../validateMultipartUploadXML'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError, retryDecider } from './base'; import type { CompleteMultipartUploadCommandInput, CompleteMultipartUploadCommandOutput, diff --git a/packages/storage/src/providers/s3/utils/client/s3data/copyObject.ts b/packages/storage/src/providers/s3/utils/client/s3data/copyObject.ts index 222e96bc5bd..e88d4b24594 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/copyObject.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/copyObject.ts @@ -15,7 +15,6 @@ import { bothNilOrEqual, buildStorageServiceError, parseXmlBody, - parseXmlError, s3TransferHandler, serializeObjectConfigsToHeaders, serializePathnameObjectKey, @@ -25,7 +24,7 @@ import { IntegrityError } from '../../../../../errors/IntegrityError'; import { validateObjectUrl } from '../../validateObjectUrl'; import type { CopyObjectCommandInput, CopyObjectCommandOutput } from './types'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type CopyObjectInput = Pick< CopyObjectCommandInput, diff --git a/packages/storage/src/providers/s3/utils/client/s3data/createMultipartUpload.ts b/packages/storage/src/providers/s3/utils/client/s3data/createMultipartUpload.ts index 01a59ba8525..90ce7329dc3 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/createMultipartUpload.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/createMultipartUpload.ts @@ -15,7 +15,6 @@ import { buildStorageServiceError, map, parseXmlBody, - parseXmlError, s3TransferHandler, serializeObjectConfigsToHeaders, serializePathnameObjectKey, @@ -28,7 +27,7 @@ import type { CreateMultipartUploadCommandOutput, } from './types'; import type { PutObjectInput } from './putObject'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type CreateMultipartUploadInput = Extract< CreateMultipartUploadCommandInput, diff --git a/packages/storage/src/providers/s3/utils/client/s3data/deleteObject.ts b/packages/storage/src/providers/s3/utils/client/s3data/deleteObject.ts index b0b19fbe51a..ad56619ac25 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/deleteObject.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/deleteObject.ts @@ -14,7 +14,6 @@ import { buildStorageServiceError, deserializeBoolean, map, - parseXmlError, s3TransferHandler, serializePathnameObjectKey, validateS3RequiredParameter, @@ -25,7 +24,7 @@ import type { DeleteObjectCommandInput, DeleteObjectCommandOutput, } from './types'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type DeleteObjectInput = Pick< DeleteObjectCommandInput, diff --git a/packages/storage/src/providers/s3/utils/client/s3data/getObject.ts b/packages/storage/src/providers/s3/utils/client/s3data/getObject.ts index 19906c9ae70..7be47c20ebe 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/getObject.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/getObject.ts @@ -11,8 +11,8 @@ import { parseMetadata, presignUrl, } from '@aws-amplify/core/internals/aws-client-utils'; -import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; import { composeServiceApi } from '@aws-amplify/core/internals/aws-client-utils/composers'; +import { AmplifyUrl } from '@aws-amplify/core/internals/utils'; import { CONTENT_SHA256_HEADER, @@ -22,14 +22,17 @@ import { deserializeNumber, deserializeTimestamp, map, - parseXmlError, s3TransferHandler, serializePathnameObjectKey, validateS3RequiredParameter, } from '../utils'; import { validateObjectUrl } from '../../validateObjectUrl'; -import { S3EndpointResolverOptions, defaultConfig } from './base'; +import { + S3EndpointResolverOptions, + defaultConfig, + parseXmlError, +} from './base'; import type { CompatibleHttpResponse, GetObjectCommandInput, diff --git a/packages/storage/src/providers/s3/utils/client/s3data/headObject.ts b/packages/storage/src/providers/s3/utils/client/s3data/headObject.ts index 87610f2892f..4a1e5f3e22b 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/headObject.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/headObject.ts @@ -16,14 +16,13 @@ import { deserializeNumber, deserializeTimestamp, map, - parseXmlError, s3TransferHandler, serializePathnameObjectKey, validateS3RequiredParameter, } from '../utils'; import { validateObjectUrl } from '../../validateObjectUrl'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; import type { HeadObjectCommandInput, HeadObjectCommandOutput } from './types'; export type HeadObjectInput = Pick; diff --git a/packages/storage/src/providers/s3/utils/client/s3data/listObjectsV2.ts b/packages/storage/src/providers/s3/utils/client/s3data/listObjectsV2.ts index fbb8ce6d1e9..664a8c7e273 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/listObjectsV2.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/listObjectsV2.ts @@ -22,7 +22,6 @@ import { emptyArrayGuard, map, parseXmlBody, - parseXmlError, s3TransferHandler, } from '../utils'; import { IntegrityError } from '../../../../../errors/IntegrityError'; @@ -31,7 +30,7 @@ import type { ListObjectsV2CommandInput, ListObjectsV2CommandOutput, } from './types'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type ListObjectsV2Input = ListObjectsV2CommandInput; diff --git a/packages/storage/src/providers/s3/utils/client/s3data/listParts.ts b/packages/storage/src/providers/s3/utils/client/s3data/listParts.ts index e7ffe5c58f2..0affbf7a5f5 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/listParts.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/listParts.ts @@ -19,14 +19,13 @@ import { emptyArrayGuard, map, parseXmlBody, - parseXmlError, s3TransferHandler, serializePathnameObjectKey, validateS3RequiredParameter, } from '../utils'; import type { ListPartsCommandInput, ListPartsCommandOutput } from './types'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; export type ListPartsInput = Pick< ListPartsCommandInput, diff --git a/packages/storage/src/providers/s3/utils/client/s3data/putObject.ts b/packages/storage/src/providers/s3/utils/client/s3data/putObject.ts index 1a68062185a..8b2f56d0e78 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/putObject.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/putObject.ts @@ -14,7 +14,6 @@ import { assignStringVariables, buildStorageServiceError, map, - parseXmlError, s3TransferHandler, serializeObjectConfigsToHeaders, serializePathnameObjectKey, @@ -22,7 +21,7 @@ import { } from '../utils'; import { validateObjectUrl } from '../../validateObjectUrl'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; import type { PutObjectCommandInput, PutObjectCommandOutput } from './types'; export type PutObjectInput = Pick< diff --git a/packages/storage/src/providers/s3/utils/client/s3data/uploadPart.ts b/packages/storage/src/providers/s3/utils/client/s3data/uploadPart.ts index 09e7e9e1f88..c34e1abc9c7 100644 --- a/packages/storage/src/providers/s3/utils/client/s3data/uploadPart.ts +++ b/packages/storage/src/providers/s3/utils/client/s3data/uploadPart.ts @@ -17,14 +17,13 @@ import { assignStringVariables, buildStorageServiceError, map, - parseXmlError, s3TransferHandler, serializePathnameObjectKey, validateS3RequiredParameter, } from '../utils'; import { validateObjectUrl } from '../../validateObjectUrl'; -import { defaultConfig } from './base'; +import { defaultConfig, parseXmlError } from './base'; import type { UploadPartCommandInput, UploadPartCommandOutput } from './types'; // Content-length is ignored here because it's forbidden header diff --git a/packages/storage/src/providers/s3/utils/client/utils/retryDecider.ts b/packages/storage/src/providers/s3/utils/client/utils/createRetryDecider.ts similarity index 60% rename from packages/storage/src/providers/s3/utils/client/utils/retryDecider.ts rename to packages/storage/src/providers/s3/utils/client/utils/createRetryDecider.ts index 3e1e0fcc3da..0cfbc0eacde 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/retryDecider.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/createRetryDecider.ts @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { + ErrorParser, HttpResponse, MiddlewareContext, RetryDeciderOutput, @@ -9,8 +10,6 @@ import { import { LocationCredentialsProvider } from '../../../types/options'; -import { parseXmlError } from './parsePayload'; - /** * Function to decide if the S3 request should be retried. For S3 APIs, we support forceRefresh option * for {@link LocationCredentialsProvider | LocationCredentialsProvider } option. It's set when S3 returns @@ -22,33 +21,49 @@ import { parseXmlError } from './parsePayload'; * @param middlewareContext Optional context object to store data between retries. * @returns True if the request should be retried. */ -export const retryDecider = async ( +export type RetryDecider = ( response?: HttpResponse, error?: unknown, middlewareContext?: MiddlewareContext, -): Promise => { - const defaultRetryDecider = getRetryDecider(parseXmlError); - const defaultRetryDecision = await defaultRetryDecider(response, error); - if (!response || response.statusCode < 300) { - return { retryable: false }; - } - const parsedError = await parseXmlError(response); - const errorCode = parsedError?.name; - const errorMessage = parsedError?.message; - const isCredentialsExpired = isCredentialsExpiredError( - errorCode, - errorMessage, - ); +) => Promise; + +/** + * Factory of a {@link RetryDecider} function. + * + * @param errorParser function to parse HTTP response wth XML payload to JS + * Error instance. + * @returns A structure indicating if the response is retryable; And if it is a + * CredentialsExpiredError + */ +export const createRetryDecider = + (errorParser: ErrorParser): RetryDecider => + async ( + response?: HttpResponse, + error?: unknown, + middlewareContext?: MiddlewareContext, + ): Promise => { + const defaultRetryDecider = getRetryDecider(errorParser); + const defaultRetryDecision = await defaultRetryDecider(response, error); + if (!response || response.statusCode < 300) { + return { retryable: false }; + } + const parsedError = await errorParser(response); + const errorCode = parsedError?.name; + const errorMessage = parsedError?.message; + const isCredentialsExpired = isCredentialsExpiredError( + errorCode, + errorMessage, + ); - return { - retryable: - defaultRetryDecision.retryable || - // If we know the previous retry attempt sets isCredentialsExpired in the - // middleware context, we don't want to retry anymore. - !!(isCredentialsExpired && !middlewareContext?.isCredentialsExpired), - isCredentialsExpiredError: isCredentialsExpired, + return { + retryable: + defaultRetryDecision.retryable || + // If we know the previous retry attempt sets isCredentialsExpired in the + // middleware context, we don't want to retry anymore. + !!(isCredentialsExpired && !middlewareContext?.isCredentialsExpired), + isCredentialsExpiredError: isCredentialsExpired, + }; }; -}; // Ref: https://github.com/aws/aws-sdk-js/blob/54829e341181b41573c419bd870dd0e0f8f10632/lib/event_listeners.js#L522-L541 const INVALID_TOKEN_ERROR_CODES = [ diff --git a/packages/storage/src/providers/s3/utils/client/utils/index.ts b/packages/storage/src/providers/s3/utils/client/utils/index.ts index f25cc45ecb0..1dbf1b54d9d 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/index.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/index.ts @@ -1,7 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -export { parseXmlBody, parseXmlError } from './parsePayload'; +export { parseXmlBody, createXmlErrorParser } from './parsePayload'; export { SEND_DOWNLOAD_PROGRESS_EVENT, SEND_UPLOAD_PROGRESS_EVENT, @@ -26,5 +26,5 @@ export { serializePathnameObjectKey, validateS3RequiredParameter, } from './serializeHelpers'; -export { retryDecider } from './retryDecider'; +export { createRetryDecider } from './createRetryDecider'; export { bothNilOrEqual } from './integrityHelpers'; diff --git a/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts b/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts index 9da44dcbdd0..f0284d573d2 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts @@ -9,25 +9,43 @@ import { import { parser } from '../runtime'; -export const parseXmlError: ErrorParser = async (response?: HttpResponse) => { - if (!response || response.statusCode < 300) { - return; - } - const { statusCode } = response; - const body = await parseXmlBody(response); - const code = body?.Code - ? (body.Code as string) - : statusCode === 404 - ? 'NotFound' - : statusCode.toString(); - const message = body?.message ?? body?.Message ?? code; - const error = new Error(message); +/** + * Factory creating a parser that parses the JS Error object from the XML + * response payload. + * + * @param input Input object + * @param input.noErrorWrapping Whether the error code and message are located + * directly in the root XML element, or in a nested `` element. + * See: https://smithy.io/2.0/aws/protocols/aws-restxml-protocol.html#restxml-errors + * + * Default to false. + * + * @internal + */ +export const createXmlErrorParser = + ({ + noErrorWrapping = false, + }: { noErrorWrapping?: boolean } = {}): ErrorParser => + async (response?: HttpResponse) => { + if (!response || response.statusCode < 300) { + return; + } + const { statusCode } = response; + const body = await parseXmlBody(response); + const errorLocation = noErrorWrapping ? body : body.Error; + const code = errorLocation?.Code + ? (errorLocation.Code as string) + : statusCode === 404 + ? 'NotFound' + : statusCode.toString(); + const message = errorLocation?.message ?? errorLocation?.Message ?? code; + const error = new Error(message); - return Object.assign(error, { - name: code, - $metadata: parseMetadata(response), - }); -}; + return Object.assign(error, { + name: code, + $metadata: parseMetadata(response), + }); + }; export const parseXmlBody = async (response: HttpResponse): Promise => { if (!response.body) { diff --git a/packages/storage/src/providers/s3/utils/md5.native.ts b/packages/storage/src/providers/s3/utils/md5.native.ts index 6c43cad24b0..a0c5a2365d8 100644 --- a/packages/storage/src/providers/s3/utils/md5.native.ts +++ b/packages/storage/src/providers/s3/utils/md5.native.ts @@ -14,16 +14,8 @@ export const calculateContentMd5 = async ( content: Blob | string | ArrayBuffer | ArrayBufferView, ): Promise => { const hasher = new Md5(); - if (typeof content === 'string') { - hasher.update(content); - } else if (ArrayBuffer.isView(content) || content instanceof ArrayBuffer) { - const blob = new Blob([content]); - const buffer = await readFile(blob); - hasher.update(buffer); - } else { - const buffer = await readFile(content); - hasher.update(buffer); - } + const buffer = content instanceof Blob ? await readFile(content) : content; + hasher.update(buffer); const digest = await hasher.digest(); return toBase64(digest); diff --git a/packages/storage/src/providers/s3/utils/md5.ts b/packages/storage/src/providers/s3/utils/md5.ts index 80292d95eea..98e04fdaf99 100644 --- a/packages/storage/src/providers/s3/utils/md5.ts +++ b/packages/storage/src/providers/s3/utils/md5.ts @@ -9,16 +9,8 @@ export const calculateContentMd5 = async ( content: Blob | string | ArrayBuffer | ArrayBufferView, ): Promise => { const hasher = new Md5(); - if (typeof content === 'string') { - hasher.update(content); - } else if (ArrayBuffer.isView(content) || content instanceof ArrayBuffer) { - const blob = new Blob([content]); - const buffer = await readFile(blob); - hasher.update(buffer); - } else { - const buffer = await readFile(content); - hasher.update(buffer); - } + const buffer = content instanceof Blob ? await readFile(content) : content; + hasher.update(buffer); const digest = await hasher.digest(); return toBase64(digest); diff --git a/scripts/dts-bundler/dts-bundler.config.js b/scripts/dts-bundler/dts-bundler.config.js index b72769224d2..9c1cb91b5ad 100644 --- a/scripts/dts-bundler/dts-bundler.config.js +++ b/scripts/dts-bundler/dts-bundler.config.js @@ -44,12 +44,15 @@ const authPackageSrcClientsPath = join( 'packages', 'auth', 'src', - 'providers', - 'cognito', - 'utils', - 'clients', + 'foundation', + 'factories', + 'serviceClients', + 'cognitoIdentityProvider', + 'types', ); +// packages/auth/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/Sdk.ts + /** @type import('dts-bundle-generator/config-schema').BundlerConfig */ const config = { compilationOptions: { @@ -84,8 +87,7 @@ const config = { filePath: './cognito-identity-provider.d.ts', outFile: join( authPackageSrcClientsPath, - 'CognitoIdentityProvider', - 'types.ts', + 'Sdk.ts', ), libraries: { inlinedLibraries: ['@aws-sdk/client-cognito-identity-provider'], diff --git a/scripts/tsc-compliance-test/CHANGELOG.md b/scripts/tsc-compliance-test/CHANGELOG.md index 322093bb2e0..781daba852a 100644 --- a/scripts/tsc-compliance-test/CHANGELOG.md +++ b/scripts/tsc-compliance-test/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.1.54](https://github.com/aws-amplify/amplify-js/compare/tsc-compliance-test@0.1.53...tsc-compliance-test@0.1.54) (2024-09-17) + +**Note:** Version bump only for package tsc-compliance-test + +## [0.1.53](https://github.com/aws-amplify/amplify-js/compare/tsc-compliance-test@0.1.52...tsc-compliance-test@0.1.53) (2024-09-16) + +**Note:** Version bump only for package tsc-compliance-test + +## [0.1.52](https://github.com/aws-amplify/amplify-js/compare/tsc-compliance-test@0.1.51...tsc-compliance-test@0.1.52) (2024-09-04) + +**Note:** Version bump only for package tsc-compliance-test + +## [0.1.51](https://github.com/aws-amplify/amplify-js/compare/tsc-compliance-test@0.1.50...tsc-compliance-test@0.1.51) (2024-09-03) + +**Note:** Version bump only for package tsc-compliance-test + +## [0.1.50](https://github.com/aws-amplify/amplify-js/compare/tsc-compliance-test@0.1.49...tsc-compliance-test@0.1.50) (2024-08-26) + +**Note:** Version bump only for package tsc-compliance-test + +## [0.1.49](https://github.com/aws-amplify/amplify-js/compare/tsc-compliance-test@0.1.48...tsc-compliance-test@0.1.49) (2024-08-21) + +**Note:** Version bump only for package tsc-compliance-test + ## [0.1.48](https://github.com/aws-amplify/amplify-js/compare/tsc-compliance-test@0.1.47...tsc-compliance-test@0.1.48) (2024-08-15) **Note:** Version bump only for package tsc-compliance-test diff --git a/scripts/tsc-compliance-test/package.json b/scripts/tsc-compliance-test/package.json index 276ad674243..6ba25acf486 100644 --- a/scripts/tsc-compliance-test/package.json +++ b/scripts/tsc-compliance-test/package.json @@ -1,11 +1,11 @@ { "name": "tsc-compliance-test", - "version": "0.1.48", + "version": "0.1.54", "license": "MIT", "private": true, "devDependencies": { "@types/node": "16.18.82", - "aws-amplify": "6.5.1", + "aws-amplify": "6.6.2", "typescript": "4.2.x" }, "scripts": { diff --git a/yarn.lock b/yarn.lock index 0fb5ad99009..d7164b02f2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,13 +18,15 @@ graphql "15.8.0" rxjs "^7.8.1" -"@aws-amplify/data-schema@^1.0.0": - version "1.3.10" - resolved "https://registry.yarnpkg.com/@aws-amplify/data-schema/-/data-schema-1.3.10.tgz#e83ef1d8d11efb821b282e499c373f64f3bf60ae" - integrity sha512-rUo6wb+DO6aGCSeSiB8wb92O4cEuN4sZBXn7TgqaYc8Bv4HutrLaIlptgXCYJMkaAp/h9rxyi6wIFJ7bEyD/6g== +"@aws-amplify/data-schema@^1.5.0": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@aws-amplify/data-schema/-/data-schema-1.5.1.tgz#d9f2e263e10f7bd8dc9c1908a4ac0e795e581b7c" + integrity sha512-hFDqqwHqdoFazmvGOApCX8kqrdoum9YJikmAQN5tP2sgnCT++lqznFw2F4PPqDJRxhQP1AYuwhbbRBvGLMbs/w== dependencies: "@aws-amplify/data-schema-types" "*" + "@smithy/util-base64" "^3.0.0" "@types/aws-lambda" "^8.10.134" + "@types/json-schema" "^7.0.15" rxjs "^7.8.1" "@aws-crypto/crc32@3.0.0": @@ -1066,10 +1068,10 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.2.tgz#e41928bd33475305c586f6acbbb7e3ade7a6f7f5" - integrity sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ== +"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.2", "@babel/compat-data@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== "@babel/core@7.17.2": version "7.17.2" @@ -1113,12 +1115,12 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.17.0", "@babel/generator@^7.20.0", "@babel/generator@^7.25.0", "@babel/generator@^7.7.2": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e" - integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw== +"@babel/generator@^7.17.0", "@babel/generator@^7.20.0", "@babel/generator@^7.25.0", "@babel/generator@^7.25.4", "@babel/generator@^7.7.2": + version "7.25.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.5.tgz#b31cf05b3fe8c32d206b6dad03bb0aacbde73450" + integrity sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w== dependencies: - "@babel/types" "^7.25.0" + "@babel/types" "^7.25.4" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" @@ -1149,20 +1151,20 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.24.7", "@babel/helper-create-class-features-plugin@^7.25.0": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz#a109bf9c3d58dfed83aaf42e85633c89f43a6253" - integrity sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ== +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.24.7", "@babel/helper-create-class-features-plugin@^7.25.0", "@babel/helper-create-class-features-plugin@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz#57eaf1af38be4224a9d9dd01ddde05b741f50e14" + integrity sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ== dependencies: "@babel/helper-annotate-as-pure" "^7.24.7" "@babel/helper-member-expression-to-functions" "^7.24.8" "@babel/helper-optimise-call-expression" "^7.24.7" "@babel/helper-replace-supers" "^7.25.0" "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" - "@babel/traverse" "^7.25.0" + "@babel/traverse" "^7.25.4" semver "^6.3.1" -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0": +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.24.7", "@babel/helper-create-regexp-features-plugin@^7.25.0", "@babel/helper-create-regexp-features-plugin@^7.25.2": version "7.25.2" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz#24c75974ed74183797ffd5f134169316cd1808d9" integrity sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g== @@ -1171,7 +1173,7 @@ regexpu-core "^5.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.6.1", "@babel/helper-define-polyfill-provider@^0.6.2": +"@babel/helper-define-polyfill-provider@^0.6.2": version "0.6.2" resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== @@ -1303,12 +1305,12 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.17.0", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.3": - version "7.25.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065" - integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw== +"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.17.0", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.4.tgz#af4f2df7d02440286b7de57b1c21acfb2a6f257a" + integrity sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA== dependencies: - "@babel/types" "^7.25.2" + "@babel/types" "^7.25.4" "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.3": version "7.25.3" @@ -1375,14 +1377,6 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-export-default-from" "^7.24.7" -"@babel/plugin-proposal-logical-assignment-operators@^7.18.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83" - integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-proposal-nullish-coalescing-operator@^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.0": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" @@ -1446,7 +1440,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -1502,7 +1496,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -1523,7 +1517,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -1537,7 +1531,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -1572,7 +1566,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== @@ -1580,11 +1574,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.24.7", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c" - integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA== + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff" + integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg== dependencies: - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.8" "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" @@ -1601,15 +1595,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-async-generator-functions@^7.25.0": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz#b785cf35d73437f6276b1e30439a57a50747bddf" - integrity sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q== +"@babel/plugin-transform-async-generator-functions@^7.24.3", "@babel/plugin-transform-async-generator-functions@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz#2afd4e639e2d055776c9f091b6c0c180ed8cf083" + integrity sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg== dependencies: "@babel/helper-plugin-utils" "^7.24.8" "@babel/helper-remap-async-to-generator" "^7.25.0" "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/traverse" "^7.25.0" + "@babel/traverse" "^7.25.4" "@babel/plugin-transform-async-to-generator@^7.0.0", "@babel/plugin-transform-async-to-generator@^7.20.0", "@babel/plugin-transform-async-to-generator@^7.24.7": version "7.24.7" @@ -1634,13 +1628,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-class-properties@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz#256879467b57b0b68c7ddfc5b76584f398cd6834" - integrity sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w== +"@babel/plugin-transform-class-properties@^7.24.1", "@babel/plugin-transform-class-properties@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz#bae7dbfcdcc2e8667355cd1fb5eda298f05189fd" + integrity sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.7" - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.25.4" + "@babel/helper-plugin-utils" "^7.24.8" "@babel/plugin-transform-class-static-block@^7.24.7": version "7.24.7" @@ -1651,16 +1645,16 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-transform-classes@^7.0.0", "@babel/plugin-transform-classes@^7.25.0": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz#63122366527d88e0ef61b612554fe3f8c793991e" - integrity sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw== +"@babel/plugin-transform-classes@^7.0.0", "@babel/plugin-transform-classes@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz#d29dbb6a72d79f359952ad0b66d88518d65ef89a" + integrity sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg== dependencies: "@babel/helper-annotate-as-pure" "^7.24.7" - "@babel/helper-compilation-targets" "^7.24.8" + "@babel/helper-compilation-targets" "^7.25.2" "@babel/helper-plugin-utils" "^7.24.8" "@babel/helper-replace-supers" "^7.25.0" - "@babel/traverse" "^7.25.0" + "@babel/traverse" "^7.25.4" globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.0.0", "@babel/plugin-transform-computed-properties@^7.24.7": @@ -1765,7 +1759,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.8" -"@babel/plugin-transform-logical-assignment-operators@^7.24.7": +"@babel/plugin-transform-logical-assignment-operators@^7.24.1", "@babel/plugin-transform-logical-assignment-operators@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz#a58fb6eda16c9dc8f9ff1c7b1ba6deb7f4694cb0" integrity sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw== @@ -1830,7 +1824,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-nullish-coalescing-operator@^7.24.7": +"@babel/plugin-transform-nullish-coalescing-operator@^7.24.1", "@babel/plugin-transform-nullish-coalescing-operator@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz#1de4534c590af9596f53d67f52a92f12db984120" integrity sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ== @@ -1838,7 +1832,7 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-transform-numeric-separator@^7.24.7": +"@babel/plugin-transform-numeric-separator@^7.24.1", "@babel/plugin-transform-numeric-separator@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz#bea62b538c80605d8a0fac9b40f48e97efa7de63" integrity sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA== @@ -1846,7 +1840,7 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-transform-object-rest-spread@^7.24.7": +"@babel/plugin-transform-object-rest-spread@^7.24.5", "@babel/plugin-transform-object-rest-spread@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz#d13a2b93435aeb8a197e115221cab266ba6e55d6" integrity sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q== @@ -1864,7 +1858,7 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/helper-replace-supers" "^7.24.7" -"@babel/plugin-transform-optional-catch-binding@^7.24.7": +"@babel/plugin-transform-optional-catch-binding@^7.24.1", "@babel/plugin-transform-optional-catch-binding@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz#00eabd883d0dd6a60c1c557548785919b6e717b4" integrity sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA== @@ -1872,7 +1866,7 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.24.7", "@babel/plugin-transform-optional-chaining@^7.24.8": +"@babel/plugin-transform-optional-chaining@^7.24.5", "@babel/plugin-transform-optional-chaining@^7.24.7", "@babel/plugin-transform-optional-chaining@^7.24.8": version "7.24.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz#bb02a67b60ff0406085c13d104c99a835cdf365d" integrity sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw== @@ -1888,13 +1882,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-private-methods@^7.22.5", "@babel/plugin-transform-private-methods@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz#e6318746b2ae70a59d023d5cc1344a2ba7a75f5e" - integrity sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ== +"@babel/plugin-transform-private-methods@^7.22.5", "@babel/plugin-transform-private-methods@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz#9bbefbe3649f470d681997e0b64a4b254d877242" + integrity sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.7" - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.25.4" + "@babel/helper-plugin-utils" "^7.24.8" "@babel/plugin-transform-private-property-in-object@^7.22.11", "@babel/plugin-transform-private-property-in-object@^7.24.7": version "7.24.7" @@ -1960,7 +1954,7 @@ "@babel/helper-annotate-as-pure" "^7.24.7" "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-regenerator@^7.24.7": +"@babel/plugin-transform-regenerator@^7.20.0", "@babel/plugin-transform-regenerator@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz#021562de4534d8b4b1851759fd7af4e05d2c47f8" integrity sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA== @@ -1976,14 +1970,14 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-transform-runtime@^7.0.0": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.7.tgz#00a5bfaf8c43cf5c8703a8a6e82b59d9c58f38ca" - integrity sha512-YqXjrk4C+a1kZjewqt+Mmu2UuV1s07y8kqcUf4qYLnoqemhR4gRQikhdAhSVJioMjVTu6Mo6pAbaypEA3jY6fw== + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.4.tgz#96e4ad7bfbbe0b4a7b7e6f2a533ca326cf204963" + integrity sha512-8hsyG+KUYGY0coX6KUCDancA0Vw225KJ2HJO0yCNr1vq5r+lJTleDaJf0K7iOhjw4SWhu03TMBzYTJ9krmzULQ== dependencies: "@babel/helper-module-imports" "^7.24.7" - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.8" babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.1" + babel-plugin-polyfill-corejs3 "^0.10.6" babel-plugin-polyfill-regenerator "^0.6.1" semver "^6.3.1" @@ -2057,20 +2051,20 @@ "@babel/helper-create-regexp-features-plugin" "^7.24.7" "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-transform-unicode-sets-regex@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz#d40705d67523803a576e29c63cef6e516b858ed9" - integrity sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg== +"@babel/plugin-transform-unicode-sets-regex@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz#be664c2a0697ffacd3423595d5edef6049e8946c" + integrity sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.24.7" - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-create-regexp-features-plugin" "^7.25.2" + "@babel/helper-plugin-utils" "^7.24.8" "@babel/preset-env@^7.0.0", "@babel/preset-env@^7.20.0": - version "7.25.3" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.3.tgz#0bf4769d84ac51d1073ab4a86f00f30a3a83c67c" - integrity sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g== + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.4.tgz#be23043d43a34a2721cd0f676c7ba6f1481f6af6" + integrity sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw== dependencies: - "@babel/compat-data" "^7.25.2" + "@babel/compat-data" "^7.25.4" "@babel/helper-compilation-targets" "^7.25.2" "@babel/helper-plugin-utils" "^7.24.8" "@babel/helper-validator-option" "^7.24.8" @@ -2099,13 +2093,13 @@ "@babel/plugin-syntax-top-level-await" "^7.14.5" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" "@babel/plugin-transform-arrow-functions" "^7.24.7" - "@babel/plugin-transform-async-generator-functions" "^7.25.0" + "@babel/plugin-transform-async-generator-functions" "^7.25.4" "@babel/plugin-transform-async-to-generator" "^7.24.7" "@babel/plugin-transform-block-scoped-functions" "^7.24.7" "@babel/plugin-transform-block-scoping" "^7.25.0" - "@babel/plugin-transform-class-properties" "^7.24.7" + "@babel/plugin-transform-class-properties" "^7.25.4" "@babel/plugin-transform-class-static-block" "^7.24.7" - "@babel/plugin-transform-classes" "^7.25.0" + "@babel/plugin-transform-classes" "^7.25.4" "@babel/plugin-transform-computed-properties" "^7.24.7" "@babel/plugin-transform-destructuring" "^7.24.8" "@babel/plugin-transform-dotall-regex" "^7.24.7" @@ -2133,7 +2127,7 @@ "@babel/plugin-transform-optional-catch-binding" "^7.24.7" "@babel/plugin-transform-optional-chaining" "^7.24.8" "@babel/plugin-transform-parameters" "^7.24.7" - "@babel/plugin-transform-private-methods" "^7.24.7" + "@babel/plugin-transform-private-methods" "^7.25.4" "@babel/plugin-transform-private-property-in-object" "^7.24.7" "@babel/plugin-transform-property-literals" "^7.24.7" "@babel/plugin-transform-regenerator" "^7.24.7" @@ -2146,10 +2140,10 @@ "@babel/plugin-transform-unicode-escapes" "^7.24.7" "@babel/plugin-transform-unicode-property-regex" "^7.24.7" "@babel/plugin-transform-unicode-regex" "^7.24.7" - "@babel/plugin-transform-unicode-sets-regex" "^7.24.7" + "@babel/plugin-transform-unicode-sets-regex" "^7.25.4" "@babel/preset-modules" "0.1.6-no-external-plugins" babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.4" + babel-plugin-polyfill-corejs3 "^0.10.6" babel-plugin-polyfill-regenerator "^0.6.1" core-js-compat "^3.37.1" semver "^6.3.1" @@ -2212,9 +2206,9 @@ integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.20.0", "@babel/runtime@^7.8.4": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" - integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.4.tgz#6ef37d678428306e7d75f054d5b1bdb8cf8aa8ee" + integrity sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w== dependencies: regenerator-runtime "^0.14.0" @@ -2227,23 +2221,23 @@ "@babel/parser" "^7.25.0" "@babel/types" "^7.25.0" -"@babel/traverse@^7.14.0", "@babel/traverse@^7.17.0", "@babel/traverse@^7.20.0", "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3": - version "7.25.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.3.tgz#f1b901951c83eda2f3e29450ce92743783373490" - integrity sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ== +"@babel/traverse@^7.14.0", "@babel/traverse@^7.17.0", "@babel/traverse@^7.20.0", "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.4.tgz#648678046990f2957407e3086e97044f13c3e18e" + integrity sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg== dependencies: "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.0" - "@babel/parser" "^7.25.3" + "@babel/generator" "^7.25.4" + "@babel/parser" "^7.25.4" "@babel/template" "^7.25.0" - "@babel/types" "^7.25.2" + "@babel/types" "^7.25.4" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.17.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125" - integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q== +"@babel/types@^7.0.0", "@babel/types@^7.17.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.4", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.4.tgz#6bcb46c72fdf1012a209d016c07f769e10adcb5f" + integrity sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ== dependencies: "@babel/helper-string-parser" "^7.24.8" "@babel/helper-validator-identifier" "^7.24.7" @@ -2867,55 +2861,55 @@ write-pkg "4.0.0" yargs "16.2.0" -"@next/env@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.5.tgz#1d9328ab828711d3517d0a1d505acb55e5ef7ad0" - integrity sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA== - -"@next/swc-darwin-arm64@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz#d0a160cf78c18731c51cc0bff131c706b3e9bb05" - integrity sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ== - -"@next/swc-darwin-x64@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz#eb832a992407f6e6352eed05a073379f1ce0589c" - integrity sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA== - -"@next/swc-linux-arm64-gnu@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz#098fdab57a4664969bc905f5801ef5a89582c689" - integrity sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA== - -"@next/swc-linux-arm64-musl@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz#243a1cc1087fb75481726dd289c7b219fa01f2b5" - integrity sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA== - -"@next/swc-linux-x64-gnu@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz#b8a2e436387ee4a52aa9719b718992e0330c4953" - integrity sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ== - -"@next/swc-linux-x64-musl@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz#cb8a9adad5fb8df86112cfbd363aab5c6d32757b" - integrity sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ== - -"@next/swc-win32-arm64-msvc@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz#81f996c1c38ea0900d4e7719cc8814be8a835da0" - integrity sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw== - -"@next/swc-win32-ia32-msvc@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz#f61c74ce823e10b2bc150e648fc192a7056422e0" - integrity sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg== - -"@next/swc-win32-x64-msvc@14.2.5": - version "14.2.5" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz#ed199a920efb510cfe941cd75ed38a7be21e756f" - integrity sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g== +"@next/env@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.10.tgz#1d3178340028ced2d679f84140877db4f420333c" + integrity sha512-dZIu93Bf5LUtluBXIv4woQw2cZVZ2DJTjax5/5DOs3lzEOeKLy7GxRSr4caK9/SCPdaW6bCgpye6+n4Dh9oJPw== + +"@next/swc-darwin-arm64@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.10.tgz#49d10ca4086fbd59ee68e204f75d7136eda2aa80" + integrity sha512-V3z10NV+cvMAfxQUMhKgfQnPbjw+Ew3cnr64b0lr8MDiBJs3eLnM6RpGC46nhfMZsiXgQngCJKWGTC/yDcgrDQ== + +"@next/swc-darwin-x64@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.10.tgz#0ebeae3afb8eac433882b79543295ab83624a1a8" + integrity sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA== + +"@next/swc-linux-arm64-gnu@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.10.tgz#7e602916d2fb55a3c532f74bed926a0137c16f20" + integrity sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA== + +"@next/swc-linux-arm64-musl@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.10.tgz#6b143f628ccee490b527562e934f8de578d4be47" + integrity sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ== + +"@next/swc-linux-x64-gnu@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.10.tgz#086f2f16a0678890a1eb46518c4dda381b046082" + integrity sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg== + +"@next/swc-linux-x64-musl@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.10.tgz#1befef10ed8dbcc5047b5d637a25ae3c30a0bfc3" + integrity sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA== + +"@next/swc-win32-arm64-msvc@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.10.tgz#731f52c3ae3c56a26cf21d474b11ae1529531209" + integrity sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ== + +"@next/swc-win32-ia32-msvc@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.10.tgz#32723ef7f04e25be12af357cc72ddfdd42fd1041" + integrity sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg== + +"@next/swc-win32-x64-msvc@14.2.10": + version "14.2.10" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.10.tgz#ee1d036cb5ec871816f96baee7991035bb242455" + integrity sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ== "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" @@ -2943,6 +2937,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + "@npmcli/arborist@6.2.9": version "6.2.9" resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-6.2.9.tgz#9ac892e5444206bd9bb3cb1ff18232322ac0fe54" @@ -3334,22 +3333,22 @@ dependencies: merge-options "^3.0.4" -"@react-native-community/cli-clean@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-11.3.5.tgz#07c8a01e433ea6c6e32eb647908be48952888cdd" - integrity sha512-1+7BU962wKkIkHRp/uW3jYbQKKGtU7L+R3g59D8K6uLccuxJYUBJv18753ojMa6SD3SAq5Xh31bAre+YwVcOTA== +"@react-native-community/cli-clean@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-11.4.1.tgz#0155a02e4158c8a61ba3d7a2b08f3ebebed81906" + integrity sha512-cwUbY3c70oBGv3FvQJWe2Qkq6m1+/dcEBonMDTYyH6i+6OrkzI4RkIGpWmbG1IS5JfE9ISUZkNL3946sxyWNkw== dependencies: - "@react-native-community/cli-tools" "11.3.5" + "@react-native-community/cli-tools" "11.4.1" chalk "^4.1.2" execa "^5.0.0" prompts "^2.4.0" -"@react-native-community/cli-clean@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-13.6.9.tgz#b6754f39c2b877c9d730feb848945150e1d52209" - integrity sha512-7Dj5+4p9JggxuVNOjPbduZBAP1SUgNhLKVw5noBUzT/3ZpUZkDM+RCSwyoyg8xKWoE4OrdUAXwAFlMcFDPKykA== +"@react-native-community/cli-clean@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-14.0.0.tgz#37b53762e5f3d02f452a44fc32a7f88a7419ccad" + integrity sha512-kvHthZTNur/wLLx8WL5Oh+r04zzzFAX16r8xuaLhu9qGTE6Th1JevbsIuiQb5IJqD8G/uZDKgIZ2a0/lONcbJg== dependencies: - "@react-native-community/cli-tools" "13.6.9" + "@react-native-community/cli-tools" "14.0.0" chalk "^4.1.2" execa "^5.0.0" fast-glob "^3.3.2" @@ -3364,26 +3363,26 @@ execa "^1.0.0" prompts "^2.4.0" -"@react-native-community/cli-config@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-11.3.5.tgz#07e48bb6cdecaa2aafa20da9888b5f35383a4382" - integrity sha512-fMblIsHlUleKfGsgWyjFJYfx1SqrsnhS/QXfA8w7iT6GrNOOjBp5UWx8+xlMDFcmOb9e42g1ExFDKl3n8FWkxQ== +"@react-native-community/cli-config@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-11.4.1.tgz#c27f91d2753f0f803cc79bbf299f19648a5d5627" + integrity sha512-sLdv1HFVqu5xNpeaR1+std0t7FFZaobpmpR0lFCOzKV7H/l611qS2Vo8zssmMK+oQbCs5JsX3SFPciODeIlaWA== dependencies: - "@react-native-community/cli-tools" "11.3.5" + "@react-native-community/cli-tools" "11.4.1" chalk "^4.1.2" cosmiconfig "^5.1.0" deepmerge "^4.3.0" glob "^7.1.3" joi "^17.2.1" -"@react-native-community/cli-config@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-13.6.9.tgz#d609a64d40a173c89bd7d24e31807bb7dcba69f9" - integrity sha512-rFfVBcNojcMm+KKHE/xqpqXg8HoKl4EC7bFHUrahMJ+y/tZll55+oX/PGG37rzB8QzP2UbMQ19DYQKC1G7kXeg== +"@react-native-community/cli-config@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-14.0.0.tgz#641ec08ddb44c90ceb947d8fc8e35de1a4bcf4a4" + integrity sha512-2Nr8KR+dgn1z+HLxT8piguQ1SoEzgKJnOPQKE1uakxWaRFcQ4LOXgzpIAscYwDW6jmQxdNqqbg2cRUoOS7IMtQ== dependencies: - "@react-native-community/cli-tools" "13.6.9" + "@react-native-community/cli-tools" "14.0.0" chalk "^4.1.2" - cosmiconfig "^5.1.0" + cosmiconfig "^9.0.0" deepmerge "^4.3.0" fast-glob "^3.3.2" joi "^17.2.1" @@ -3400,17 +3399,24 @@ glob "^7.1.3" joi "^17.2.1" -"@react-native-community/cli-debugger-ui@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.5.tgz#0dbb27759b9f6e4ca8cfcaab4fabfe349f765356" - integrity sha512-o5JVCKEpPUXMX4r3p1cYjiy3FgdOEkezZcQ6owWEae2dYvV19lLYyJwnocm9Y7aG9PvpgI3PIMVh3KZbhS21eA== +"@react-native-community/cli-debugger-ui@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.4.1.tgz#783cc276e1360baf8235dc8c6ebbbce0fe01d944" + integrity sha512-+pgIjGNW5TrJF37XG3djIOzP+WNoPp67to/ggDhrshuYgpymfb9XpDVsURJugy0Sy3RViqb83kQNK765QzTIvw== + dependencies: + serve-static "^1.13.1" + +"@react-native-community/cli-debugger-ui@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-14.0.0.tgz#ef02d531e70b86265d39773abc3b58ab5cb8f4b8" + integrity sha512-JpfzILfU7eKE9+7AMCAwNJv70H4tJGVv3ZGFqSVoK1YHg5QkVEGsHtoNW8AsqZRS6Fj4os+Fmh+r+z1L36sPmg== dependencies: serve-static "^1.13.1" -"@react-native-community/cli-debugger-ui@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-13.6.9.tgz#bc5727c51964206a00d417e5148b46331a81d5a5" - integrity sha512-TkN7IdFmGPPvTpAo3nCAH9uwGCPxWBEAwpqEZDrq0NWllI7Tdie8vDpGdrcuCcKalmhq6OYnkXzeBah7O1Ztpw== +"@react-native-community/cli-debugger-ui@14.0.0-alpha.11": + version "14.0.0-alpha.11" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-14.0.0-alpha.11.tgz#952bb7c162e136ebff1950e7e80706eb3155fe21" + integrity sha512-0wCNQxhCniyjyMXgR1qXliY180y/2QbvoiYpp2MleGQADr5M1b8lgI4GoyADh5kE+kX3VL0ssjgyxpmbpCD86A== dependencies: serve-static "^1.13.1" @@ -3421,46 +3427,44 @@ dependencies: serve-static "^1.13.1" -"@react-native-community/cli-doctor@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-11.3.5.tgz#f11e0651c53e0b58487837a272af725f046a5842" - integrity sha512-+4BuFHjoV4FFjX5y60l0s6nS0agidb1izTVwsFixeFKW73LUkOLu+Ae5HI94RAFEPE4ePEVNgYX3FynIau6K0g== +"@react-native-community/cli-doctor@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-11.4.1.tgz#516ef5932de3e12989695e7cb7aba82b81e7b2de" + integrity sha512-O6oPiRsl8pdkcyNktpzvJAXUqdocoY4jh7Tt7wA69B1JKCJA7aPCecwJgpUZb63ZYoxOtRtYM3BYQKzRMLIuUw== dependencies: - "@react-native-community/cli-config" "11.3.5" - "@react-native-community/cli-platform-android" "11.3.5" - "@react-native-community/cli-platform-ios" "11.3.5" - "@react-native-community/cli-tools" "11.3.5" + "@react-native-community/cli-config" "11.4.1" + "@react-native-community/cli-platform-android" "11.4.1" + "@react-native-community/cli-platform-ios" "11.4.1" + "@react-native-community/cli-tools" "11.4.1" chalk "^4.1.2" command-exists "^1.2.8" envinfo "^7.7.2" execa "^5.0.0" hermes-profile-transformer "^0.0.6" - ip "^1.1.5" node-stream-zip "^1.9.1" ora "^5.4.1" prompts "^2.4.0" - semver "^6.3.0" + semver "^7.5.2" strip-ansi "^5.2.0" sudo-prompt "^9.0.0" wcwidth "^1.0.1" yaml "^2.2.1" -"@react-native-community/cli-doctor@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-13.6.9.tgz#f1d4eeff427ddc8a9d19851042621c10939c35cb" - integrity sha512-5quFaLdWFQB+677GXh5dGU9I5eg2z6Vg4jOX9vKnc9IffwyIFAyJfCZHrxLSRPDGNXD7biDQUdoezXYGwb6P/A== - dependencies: - "@react-native-community/cli-config" "13.6.9" - "@react-native-community/cli-platform-android" "13.6.9" - "@react-native-community/cli-platform-apple" "13.6.9" - "@react-native-community/cli-platform-ios" "13.6.9" - "@react-native-community/cli-tools" "13.6.9" +"@react-native-community/cli-doctor@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-14.0.0.tgz#f6855495d5a53e9a2c206949958a8291ac3e326e" + integrity sha512-in6jylHjaPUaDzV+JtUblh8m9JYIHGjHOf6Xn57hrmE5Zwzwuueoe9rSMHF1P0mtDgRKrWPzAJVejElddfptWA== + dependencies: + "@react-native-community/cli-config" "14.0.0" + "@react-native-community/cli-platform-android" "14.0.0" + "@react-native-community/cli-platform-apple" "14.0.0" + "@react-native-community/cli-platform-ios" "14.0.0" + "@react-native-community/cli-tools" "14.0.0" chalk "^4.1.2" command-exists "^1.2.8" deepmerge "^4.3.0" - envinfo "^7.10.0" + envinfo "^7.13.0" execa "^5.0.0" - hermes-profile-transformer "^0.0.6" node-stream-zip "^1.9.1" ora "^5.4.1" semver "^7.5.2" @@ -3489,24 +3493,13 @@ sudo-prompt "^9.0.0" wcwidth "^1.0.1" -"@react-native-community/cli-hermes@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-11.3.5.tgz#fb557790a34f4354fa7a91b02217cdded26cafc4" - integrity sha512-+3m34hiaJpFel8BlJE7kJOaPzWR/8U8APZG2LXojbAdBAg99EGmQcwXIgsSVJFvH8h/nezf4DHbsPKigIe33zA== +"@react-native-community/cli-hermes@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-11.4.1.tgz#abf487ae8ab53c66f6f1178bcd37ecbbbac9fb5c" + integrity sha512-1VAjwcmv+i9BJTMMVn5Grw7AcgURhTyfHVghJ1YgBE2euEJxPuqPKSxP54wBOQKnWUwsuDQAtQf+jPJoCxJSSA== dependencies: - "@react-native-community/cli-platform-android" "11.3.5" - "@react-native-community/cli-tools" "11.3.5" - chalk "^4.1.2" - hermes-profile-transformer "^0.0.6" - ip "^1.1.5" - -"@react-native-community/cli-hermes@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-13.6.9.tgz#88c8dfe936a0d4272efc54429eda9ccc3fca3ad8" - integrity sha512-GvwiwgvFw4Ws+krg2+gYj8sR3g05evmNjAHkKIKMkDTJjZ8EdyxbkifRUs1ZCq3TMZy2oeblZBXCJVOH4W7ZbA== - dependencies: - "@react-native-community/cli-platform-android" "13.6.9" - "@react-native-community/cli-tools" "13.6.9" + "@react-native-community/cli-platform-android" "11.4.1" + "@react-native-community/cli-tools" "11.4.1" chalk "^4.1.2" hermes-profile-transformer "^0.0.6" @@ -3531,23 +3524,23 @@ glob "^7.1.3" logkitty "^0.7.1" -"@react-native-community/cli-platform-android@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.5.tgz#8be7ef382a3182fe63a698ed2edd4d90ab19246a" - integrity sha512-s4Lj7FKxJ/BofGi/ifjPfrA9MjFwIgYpHnHBSlqtbsvPoSYzmVCU2qlWM8fb3AmkXIwyYt4A6MEr3MmNT2UoBg== +"@react-native-community/cli-platform-android@11.4.1", "@react-native-community/cli-platform-android@^11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-11.4.1.tgz#ec5fc97e87834f2e33cb0d34dcef6c17b20f60fc" + integrity sha512-VMmXWIzk0Dq5RAd+HIEa3Oe7xl2jso7+gOr6E2HALF4A3fCKUjKZQ6iK2t6AfnY04zftvaiKw6zUXtrfl52AVQ== dependencies: - "@react-native-community/cli-tools" "11.3.5" + "@react-native-community/cli-tools" "11.4.1" chalk "^4.1.2" execa "^5.0.0" glob "^7.1.3" logkitty "^0.7.1" -"@react-native-community/cli-platform-android@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-13.6.9.tgz#b175b9b11334fc90da3f395432678bd53c30fae4" - integrity sha512-9KsYGdr08QhdvT3Ht7e8phQB3gDX9Fs427NJe0xnoBh+PDPTI2BD5ks5ttsH8CzEw8/P6H8tJCHq6hf2nxd9cw== +"@react-native-community/cli-platform-android@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-14.0.0.tgz#36f47999af9b386aaa8f8286923edd9a65101f28" + integrity sha512-nt7yVz3pGKQXnVa5MAk7zR+1n41kNKD3Hi2OgybH5tVShMBo7JQoL2ZVVH6/y/9wAwI/s7hXJgzf1OIP3sMq+Q== dependencies: - "@react-native-community/cli-tools" "13.6.9" + "@react-native-community/cli-tools" "14.0.0" chalk "^4.1.2" execa "^5.0.0" fast-glob "^3.3.2" @@ -3565,16 +3558,16 @@ glob "^7.1.3" logkitty "^0.7.1" -"@react-native-community/cli-platform-apple@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-apple/-/cli-platform-apple-13.6.9.tgz#02fb5dc47d62acd85f4d7a852e93216927a772fa" - integrity sha512-KoeIHfhxMhKXZPXmhQdl6EE+jGKWwoO9jUVWgBvibpVmsNjo7woaG/tfJMEWfWF3najX1EkQAoJWpCDBMYWtlA== +"@react-native-community/cli-platform-apple@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-apple/-/cli-platform-apple-14.0.0.tgz#7050af6fbc01b4ebe72e1bdcb48d188cbbf1b9ef" + integrity sha512-WniJL8vR4MeIsjqio2hiWWuUYUJEL3/9TDL5aXNwG68hH3tYgK3742+X9C+vRzdjTmf5IKc/a6PwLsdplFeiwQ== dependencies: - "@react-native-community/cli-tools" "13.6.9" + "@react-native-community/cli-tools" "14.0.0" chalk "^4.1.2" execa "^5.0.0" fast-glob "^3.3.2" - fast-xml-parser "^4.0.12" + fast-xml-parser "^4.2.4" ora "^5.4.1" "@react-native-community/cli-platform-ios@10.0.0": @@ -3588,24 +3581,24 @@ glob "^7.1.3" ora "^5.4.1" -"@react-native-community/cli-platform-ios@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.5.tgz#12a8cbf2638400b9986709466653ce4e7c9eca2a" - integrity sha512-ytJC/YCFD7P+KuQHOT5Jzh1ho2XbJEjq71yHa1gJP2PG/Q/uB4h1x2XpxDqv5iXU6E250yjvKMmkReKTW4CTig== +"@react-native-community/cli-platform-ios@11.4.1", "@react-native-community/cli-platform-ios@^11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.4.1.tgz#12d72741273b684734d5ed021415b7f543a6f009" + integrity sha512-RPhwn+q3IY9MpWc9w/Qmzv03mo8sXdah2eSZcECgweqD5SHWtOoRCUt11zM8jASpAQ8Tm5Je7YE9bHvdwGl4hA== dependencies: - "@react-native-community/cli-tools" "11.3.5" + "@react-native-community/cli-tools" "11.4.1" chalk "^4.1.2" execa "^5.0.0" fast-xml-parser "^4.0.12" glob "^7.1.3" ora "^5.4.1" -"@react-native-community/cli-platform-ios@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-13.6.9.tgz#f37ceab41c2302e8f0d4bcbd3bf58b3353db4306" - integrity sha512-CiUcHlGs8vE0CAB4oi1f+dzniqfGuhWPNrDvae2nm8dewlahTBwIcK5CawyGezjcJoeQhjBflh9vloska+nlnw== +"@react-native-community/cli-platform-ios@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-14.0.0.tgz#7c7c393a13415bf61aaad82f1a3583c30afb110e" + integrity sha512-8kxGv7mZ5nGMtueQDq+ndu08f0ikf3Zsqm3Ix8FY5KCXpSgP14uZloO2GlOImq/zFESij+oMhCkZJGggpWpfAw== dependencies: - "@react-native-community/cli-platform-apple" "13.6.9" + "@react-native-community/cli-platform-apple" "14.0.0" "@react-native-community/cli-platform-ios@^10.2.5": version "10.2.5" @@ -3619,21 +3612,21 @@ glob "^7.1.3" ora "^5.4.1" -"@react-native-community/cli-plugin-metro@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.5.tgz#5614c7ef3bc83cf70bcb0e6d988ab9d84a76008a" - integrity sha512-r9AekfeLKdblB7LfWB71IrNy1XM03WrByQlUQajUOZAP2NmUUBLl9pMZscPjJeOSgLpHB9ixEFTIOhTabri/qg== +"@react-native-community/cli-plugin-metro@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.4.1.tgz#8d51c59a9a720f99150d4153e757d5d1d1dabd22" + integrity sha512-JxbIqknYcQ5Z4rWROtu5LNakLfMiKoWcMoPqIrBLrV5ILm1XUJj1/8fATCcotZqV3yzB3SCJ3RrhKx7dQ3YELw== dependencies: - "@react-native-community/cli-server-api" "11.3.5" - "@react-native-community/cli-tools" "11.3.5" + "@react-native-community/cli-server-api" "11.4.1" + "@react-native-community/cli-tools" "11.4.1" chalk "^4.1.2" execa "^5.0.0" - metro "0.76.7" - metro-config "0.76.7" - metro-core "0.76.7" - metro-react-native-babel-transformer "0.76.7" - metro-resolver "0.76.7" - metro-runtime "0.76.7" + metro "^0.76.9" + metro-config "^0.76.9" + metro-core "^0.76.9" + metro-react-native-babel-transformer "^0.76.9" + metro-resolver "^0.76.9" + metro-runtime "^0.76.9" readline "^1.3.0" "@react-native-community/cli-plugin-metro@^10.0.0": @@ -3653,13 +3646,13 @@ metro-runtime "0.73.10" readline "^1.3.0" -"@react-native-community/cli-server-api@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-11.3.5.tgz#6f43f5844bd1eb73166546b8fa8bfd32064b21e7" - integrity sha512-PM/jF13uD1eAKuC84lntNuM5ZvJAtyb+H896P1dBIXa9boPLa3KejfUvNVoyOUJ5s8Ht25JKbc3yieV2+GMBDA== +"@react-native-community/cli-server-api@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-11.4.1.tgz#3dda094c4ab2369db34fe991c320e3cd78f097b3" + integrity sha512-isxXE8X5x+C4kN90yilD08jaLWD34hfqTfn/Xbl1u/igtdTsCaQGvWe9eaFamrpWFWTpVtj6k+vYfy8AtYSiKA== dependencies: - "@react-native-community/cli-debugger-ui" "11.3.5" - "@react-native-community/cli-tools" "11.3.5" + "@react-native-community/cli-debugger-ui" "11.4.1" + "@react-native-community/cli-tools" "11.4.1" compression "^1.7.1" connect "^3.6.5" errorhandler "^1.5.1" @@ -3668,20 +3661,35 @@ serve-static "^1.13.1" ws "^7.5.1" -"@react-native-community/cli-server-api@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-13.6.9.tgz#269e666bc26e9d0b2f42c7f6099559b5f9259e9d" - integrity sha512-W8FSlCPWymO+tlQfM3E0JmM8Oei5HZsIk5S0COOl0MRi8h0NmHI4WSTF2GCfbFZkcr2VI/fRsocoN8Au4EZAug== +"@react-native-community/cli-server-api@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-14.0.0.tgz#1b62b78e5ea7dead0ae4590465c977bc4af880fc" + integrity sha512-A0FIsj0QCcDl1rswaVlChICoNbfN+mkrKB5e1ab5tOYeZMMyCHqvU+eFvAvXjHUlIvVI+LbqCkf4IEdQ6H/2AQ== dependencies: - "@react-native-community/cli-debugger-ui" "13.6.9" - "@react-native-community/cli-tools" "13.6.9" + "@react-native-community/cli-debugger-ui" "14.0.0" + "@react-native-community/cli-tools" "14.0.0" compression "^1.7.1" connect "^3.6.5" errorhandler "^1.5.1" nocache "^3.0.1" pretty-format "^26.6.2" serve-static "^1.13.1" - ws "^6.2.2" + ws "^6.2.3" + +"@react-native-community/cli-server-api@14.0.0-alpha.11": + version "14.0.0-alpha.11" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-14.0.0-alpha.11.tgz#505163e11d3a30ebc874950956f72f5b3b6c5fc1" + integrity sha512-I7YeYI7S5wSxnQAqeG8LNqhT99FojiGIk87DU0vTp6U8hIMLcA90fUuBAyJY38AuQZ12ZJpGa8ObkhIhWzGkvg== + dependencies: + "@react-native-community/cli-debugger-ui" "14.0.0-alpha.11" + "@react-native-community/cli-tools" "14.0.0-alpha.11" + compression "^1.7.1" + connect "^3.6.5" + errorhandler "^1.5.1" + nocache "^3.0.1" + pretty-format "^26.6.2" + serve-static "^1.13.1" + ws "^6.2.3" "@react-native-community/cli-server-api@^10.0.0", "@react-native-community/cli-server-api@^10.1.1": version "10.1.1" @@ -3698,10 +3706,10 @@ serve-static "^1.13.1" ws "^7.5.1" -"@react-native-community/cli-tools@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-11.3.5.tgz#3f9d23a4c961d963f85c254718636db8a5fa3bce" - integrity sha512-zDklE1+ah/zL4BLxut5XbzqCj9KTHzbYBKX7//cXw2/0TpkNCaY9c+iKx//gZ5m7U1OKbb86Fm2b0AKtKVRf6Q== +"@react-native-community/cli-tools@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-11.4.1.tgz#f6c69967e077b10cd8a884a83e53eb199dd9ee9f" + integrity sha512-GuQIuY/kCPfLeXB1aiPZ5HvF+e/wdO42AYuNEmT7FpH/0nAhdTxA9qjL8m3vatDD2/YK7WNOSVNsl2UBZuOISg== dependencies: appdirsjs "^1.2.4" chalk "^4.1.2" @@ -3710,20 +3718,35 @@ node-fetch "^2.6.0" open "^6.2.0" ora "^5.4.1" - semver "^6.3.0" + semver "^7.5.2" shell-quote "^1.7.3" -"@react-native-community/cli-tools@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-13.6.9.tgz#2baee279358ba1a863e737b2fa9f45659ad91929" - integrity sha512-OXaSjoN0mZVw3nrAwcY1PC0uMfyTd9fz7Cy06dh+EJc+h0wikABsVRzV8cIOPrVV+PPEEXE0DBrH20T2puZzgQ== +"@react-native-community/cli-tools@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-14.0.0.tgz#07b57a8942a131618c198e3b64fb1ec846cd631d" + integrity sha512-L7GX5hyYYv0ZWbAyIQKzhHuShnwDqlKYB0tqn57wa5riGCaxYuRPTK+u4qy+WRCye7+i8M4Xj6oQtSd4z0T9cA== + dependencies: + appdirsjs "^1.2.4" + chalk "^4.1.2" + execa "^5.0.0" + find-up "^5.0.0" + mime "^2.4.1" + open "^6.2.0" + ora "^5.4.1" + semver "^7.5.2" + shell-quote "^1.7.3" + sudo-prompt "^9.0.0" + +"@react-native-community/cli-tools@14.0.0-alpha.11": + version "14.0.0-alpha.11" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-14.0.0-alpha.11.tgz#95b148a3e65a4c2519af608b27ed7091e7e8b78a" + integrity sha512-HQCfVnX9aqRdKdLxmQy4fUAUo+YhNGlBV7ZjOayPbuEGWJ4RN+vSy0Cawk7epo7hXd6vKzc7P7y3HlU6Kxs7+w== dependencies: appdirsjs "^1.2.4" chalk "^4.1.2" execa "^5.0.0" find-up "^5.0.0" mime "^2.4.1" - node-fetch "^2.6.0" open "^6.2.0" ora "^5.4.1" semver "^7.5.2" @@ -3745,17 +3768,17 @@ semver "^6.3.0" shell-quote "^1.7.3" -"@react-native-community/cli-types@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-11.3.5.tgz#9051205e164d5585f1ae3869a3b3ca1f2f43b9ba" - integrity sha512-pf0kdWMEfPSV/+8rcViDCFzbLMtWIHMZ8ay7hKwqaoWegsJ0oprSF2tSTH+LSC/7X1Beb9ssIvHj1m5C4es5Xg== +"@react-native-community/cli-types@11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-11.4.1.tgz#3842dc37ba3b09f929b485bcbd8218de19349ac2" + integrity sha512-B3q9A5BCneLDSoK/iSJ06MNyBn1qTxjdJeOgeS3MiCxgJpPcxyn/Yrc6+h0Cu9T9sgWj/dmectQPYWxtZeo5VA== dependencies: joi "^17.2.1" -"@react-native-community/cli-types@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-13.6.9.tgz#08bfb796eacf0daeb31e2de516e81e78a36a1a55" - integrity sha512-RLxDppvRxXfs3hxceW/mShi+6o5yS+kFPnPqZTaMKKR5aSg7LwDpLQW4K2D22irEG8e6RKDkZUeH9aL3vO2O0w== +"@react-native-community/cli-types@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-14.0.0.tgz#6cde2d2a93edd9b13238171edef30352d37e8dd2" + integrity sha512-CMUevd1pOWqvmvutkUiyQT2lNmMHUzSW7NKc1xvHgg39NjbS58Eh2pMzIUP85IwbYNeocfYc3PH19vA/8LnQtg== dependencies: joi "^17.2.1" @@ -3789,50 +3812,49 @@ prompts "^2.4.0" semver "^6.3.0" -"@react-native-community/cli@11.3.5": - version "11.3.5" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-11.3.5.tgz#18ac20ba96182662cf1088cbed20b6065935ddba" - integrity sha512-wMXgKEWe6uesw7vyXKKjx5EDRog0QdXHxdgRguG14AjQRao1+4gXEWq2yyExOTi/GDY6dfJBUGTCwGQxhnk/Lg== - dependencies: - "@react-native-community/cli-clean" "11.3.5" - "@react-native-community/cli-config" "11.3.5" - "@react-native-community/cli-debugger-ui" "11.3.5" - "@react-native-community/cli-doctor" "11.3.5" - "@react-native-community/cli-hermes" "11.3.5" - "@react-native-community/cli-plugin-metro" "11.3.5" - "@react-native-community/cli-server-api" "11.3.5" - "@react-native-community/cli-tools" "11.3.5" - "@react-native-community/cli-types" "11.3.5" +"@react-native-community/cli@14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-14.0.0.tgz#0c98d75ac55515d07972682c1053f46bfee93863" + integrity sha512-KwMKJB5jsDxqOhT8CGJ55BADDAYxlYDHv5R/ASQlEcdBEZxT0zZmnL0iiq2VqzETUy+Y/Nop+XDFgqyoQm0C2w== + dependencies: + "@react-native-community/cli-clean" "14.0.0" + "@react-native-community/cli-config" "14.0.0" + "@react-native-community/cli-debugger-ui" "14.0.0" + "@react-native-community/cli-doctor" "14.0.0" + "@react-native-community/cli-server-api" "14.0.0" + "@react-native-community/cli-tools" "14.0.0" + "@react-native-community/cli-types" "14.0.0" chalk "^4.1.2" commander "^9.4.1" + deepmerge "^4.3.0" execa "^5.0.0" - find-up "^4.1.0" + find-up "^5.0.0" fs-extra "^8.1.0" graceful-fs "^4.1.3" - prompts "^2.4.0" - semver "^6.3.0" + prompts "^2.4.2" + semver "^7.5.2" -"@react-native-community/cli@13.6.9": - version "13.6.9" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-13.6.9.tgz#ba6360b94e0aba9c4001bda256cf7e57e2ecb02c" - integrity sha512-hFJL4cgLPxncJJd/epQ4dHnMg5Jy/7Q56jFvA3MHViuKpzzfTCJCB+pGY54maZbtym53UJON9WTGpM3S81UfjQ== - dependencies: - "@react-native-community/cli-clean" "13.6.9" - "@react-native-community/cli-config" "13.6.9" - "@react-native-community/cli-debugger-ui" "13.6.9" - "@react-native-community/cli-doctor" "13.6.9" - "@react-native-community/cli-hermes" "13.6.9" - "@react-native-community/cli-server-api" "13.6.9" - "@react-native-community/cli-tools" "13.6.9" - "@react-native-community/cli-types" "13.6.9" +"@react-native-community/cli@^11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-11.4.1.tgz#9a6346486622860dad721da406df70e29a45491f" + integrity sha512-NdAageVMtNhtvRsrq4NgJf5Ey2nA1CqmLvn7PhSawg+aIzMKmZuzWxGVwr9CoPGyjvNiqJlCWrLGR7NzOyi/sA== + dependencies: + "@react-native-community/cli-clean" "11.4.1" + "@react-native-community/cli-config" "11.4.1" + "@react-native-community/cli-debugger-ui" "11.4.1" + "@react-native-community/cli-doctor" "11.4.1" + "@react-native-community/cli-hermes" "11.4.1" + "@react-native-community/cli-plugin-metro" "11.4.1" + "@react-native-community/cli-server-api" "11.4.1" + "@react-native-community/cli-tools" "11.4.1" + "@react-native-community/cli-types" "11.4.1" chalk "^4.1.2" commander "^9.4.1" - deepmerge "^4.3.0" execa "^5.0.0" find-up "^4.1.0" fs-extra "^8.1.0" graceful-fs "^4.1.3" - prompts "^2.4.2" + prompts "^2.4.0" semver "^7.5.2" "@react-native-community/netinfo@4.7.0": @@ -3840,10 +3862,10 @@ resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-4.7.0.tgz#7482d36836cac69d0a0ae25581f65bc472639930" integrity sha512-a/sDB+AsLEUNmhAUlAaTYeXKyQdFGBUfatqKkX5jluBo2CB3OAuTHfm7rSjcaLB9EmG5iSq3fOTpync2E7EYTA== -"@react-native/assets-registry@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.74.86.tgz#5a9dc5d4c74346194a895b0be6b87a7e6022cf53" - integrity sha512-rNWSa1MTqG3Z7ZfACIDlED+T63tNlt0Lr/ruvxFJL5IX6DRC6sIrb2SrbLrlXgz7C0FbhO0ub9zfHXISgrJOsQ== +"@react-native/assets-registry@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/assets-registry/-/assets-registry-0.75.2.tgz#2c522c537fa86298987b8c877c167ac9b485d3da" + integrity sha512-P1dLHjpUeC0AIkDHRYcx0qLMr+p92IPWL3pmczzo6T76Qa9XzruQOYy0jittxyBK91Csn6HHQ/eit8TeXW8MVw== "@react-native/assets-registry@^0.72.0": version "0.72.0" @@ -3855,44 +3877,45 @@ resolved "https://registry.yarnpkg.com/@react-native/assets/-/assets-1.0.0.tgz#c6f9bf63d274bafc8e970628de24986b30a55c8e" integrity sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ== -"@react-native/babel-plugin-codegen@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.74.86.tgz#4edbb8887c5cedefd52e8fda973b1da97c779db4" - integrity sha512-fO7exk0pdsOSsK3fvDz4YKe5nMeAMrsIGi525pft/L+dedjdeiWYmEoQVc9NElxwwNCldwRY6eNMw6IhKyjzLA== +"@react-native/babel-plugin-codegen@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.75.2.tgz#1d940df23ac4ca16b4bd3299f4a3c98081158960" + integrity sha512-BIKVh2ZJPkzluUGgCNgpoh6NTHgX8j04FCS0Z/rTmRJ66hir/EUBl8frMFKrOy/6i4VvZEltOWB5eWfHe1AYgw== dependencies: - "@react-native/codegen" "0.74.86" + "@react-native/codegen" "0.75.2" -"@react-native/babel-preset@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/babel-preset/-/babel-preset-0.74.86.tgz#8bb3fbd49ce11470eb8022dea2c1e51bfa8dedd4" - integrity sha512-6A+1NVAHugbBLFNU4iaYrq2lx8P7pINyqoyTtVAqd375PShRmLwu6GvuF3b/4avC97s6LmBljVTJ1xVHukA42g== +"@react-native/babel-preset@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/babel-preset/-/babel-preset-0.75.2.tgz#f66a762fd8e172e547eeebb25f2960a5144ea14f" + integrity sha512-mprpsas+WdCEMjQZnbDiAC4KKRmmLbMB+o/v4mDqKlH4Mcm7RdtP5t80MZGOVCHlceNp1uEIpXywx69DNwgbgg== dependencies: "@babel/core" "^7.20.0" - "@babel/plugin-proposal-async-generator-functions" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.18.0" "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.0" - "@babel/plugin-proposal-numeric-separator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.20.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.20.0" "@babel/plugin-syntax-dynamic-import" "^7.8.0" "@babel/plugin-syntax-export-default-from" "^7.0.0" "@babel/plugin-syntax-flow" "^7.18.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" "@babel/plugin-syntax-optional-chaining" "^7.0.0" "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-async-generator-functions" "^7.24.3" "@babel/plugin-transform-async-to-generator" "^7.20.0" "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-class-properties" "^7.24.1" "@babel/plugin-transform-classes" "^7.0.0" "@babel/plugin-transform-computed-properties" "^7.0.0" "@babel/plugin-transform-destructuring" "^7.20.0" "@babel/plugin-transform-flow-strip-types" "^7.20.0" + "@babel/plugin-transform-for-of" "^7.0.0" "@babel/plugin-transform-function-name" "^7.0.0" "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-logical-assignment-operators" "^7.24.1" "@babel/plugin-transform-modules-commonjs" "^7.0.0" "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.1" + "@babel/plugin-transform-numeric-separator" "^7.24.1" + "@babel/plugin-transform-object-rest-spread" "^7.24.5" + "@babel/plugin-transform-optional-catch-binding" "^7.24.1" + "@babel/plugin-transform-optional-chaining" "^7.24.5" "@babel/plugin-transform-parameters" "^7.0.0" "@babel/plugin-transform-private-methods" "^7.22.5" "@babel/plugin-transform-private-property-in-object" "^7.22.11" @@ -3900,6 +3923,7 @@ "@babel/plugin-transform-react-jsx" "^7.0.0" "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.20.0" "@babel/plugin-transform-runtime" "^7.0.0" "@babel/plugin-transform-shorthand-properties" "^7.0.0" "@babel/plugin-transform-spread" "^7.0.0" @@ -3907,24 +3931,25 @@ "@babel/plugin-transform-typescript" "^7.5.0" "@babel/plugin-transform-unicode-regex" "^7.0.0" "@babel/template" "^7.0.0" - "@react-native/babel-plugin-codegen" "0.74.86" + "@react-native/babel-plugin-codegen" "0.75.2" babel-plugin-transform-flow-enums "^0.0.2" react-refresh "^0.14.0" -"@react-native/codegen@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/codegen/-/codegen-0.74.86.tgz#90933f5ee555ffb95ca27372ba1e836f698c3192" - integrity sha512-BOwABta9035GJ/zLMkxQfgPMr47u1/1HqNIMk10FqmTe0jmROOxKEAeP4FbeS5L1voO4ug3dqr+mcuHrG+HNhA== +"@react-native/codegen@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/codegen/-/codegen-0.75.2.tgz#15674a9b21cf413eb37657fb045a06640bf54476" + integrity sha512-OkWdbtO2jTkfOXfj3ibIL27rM6LoaEuApOByU2G8X+HS6v9U87uJVJlMIRWBDmnxODzazuHwNVA2/wAmSbucaw== dependencies: "@babel/parser" "^7.20.0" glob "^7.1.1" - hermes-parser "0.19.1" + hermes-parser "0.22.0" invariant "^2.2.4" jscodeshift "^0.14.0" mkdirp "^0.5.1" nullthrows "^1.1.1" + yargs "^17.6.2" -"@react-native/codegen@^0.72.6": +"@react-native/codegen@^0.72.8": version "0.72.8" resolved "https://registry.yarnpkg.com/@react-native/codegen/-/codegen-0.72.8.tgz#0593f628e1310f430450a9479fbb4be35e7b63d6" integrity sha512-jQCcBlXV7B7ap5VlHhwIPieYz89yiRgwd2FPUBu+unz+kcJ6pAiB2U8RdLDmyIs8fiWd+Vq1xxaWs4TR329/ng== @@ -3937,15 +3962,15 @@ mkdirp "^0.5.1" nullthrows "^1.1.1" -"@react-native/community-cli-plugin@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/community-cli-plugin/-/community-cli-plugin-0.74.86.tgz#239592475b222e990ac3bb229d7cdfb8f9afcc39" - integrity sha512-q0fPDe6vx1vT5PdE3AiL+DNm0q7opzySiGle8B64bAKsa0ClIoRXAzZqolceiMHbSoCIhUbZxYtNGavrjuPyKw== +"@react-native/community-cli-plugin@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/community-cli-plugin/-/community-cli-plugin-0.75.2.tgz#f5943c22e6dd24fa8fc6151de8ba52b92e3cc61b" + integrity sha512-/tz0bzVja4FU0aAimzzQ7iYR43peaD6pzksArdrrGhlm8OvFYAQPOYSNeIQVMSarwnkNeg1naFKaeYf1o3++yA== dependencies: - "@react-native-community/cli-server-api" "13.6.9" - "@react-native-community/cli-tools" "13.6.9" - "@react-native/dev-middleware" "0.74.86" - "@react-native/metro-babel-transformer" "0.74.86" + "@react-native-community/cli-server-api" "14.0.0-alpha.11" + "@react-native-community/cli-tools" "14.0.0-alpha.11" + "@react-native/dev-middleware" "0.75.2" + "@react-native/metro-babel-transformer" "0.75.2" chalk "^4.0.0" execa "^5.1.1" metro "^0.80.3" @@ -3955,20 +3980,20 @@ querystring "^0.2.1" readline "^1.3.0" -"@react-native/debugger-frontend@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/debugger-frontend/-/debugger-frontend-0.74.86.tgz#87a3c7dfb12ee6e981165e304bbbe20e9b1fa009" - integrity sha512-Spq1kFX4qvPmT4HuTwpi1ALFtojlJ6s4GpWU2OnpevC/z7ks36lhD3J0rd0D9U5bkxtTYLcg31fPv7nGFC7XZg== +"@react-native/debugger-frontend@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/debugger-frontend/-/debugger-frontend-0.75.2.tgz#ead66eff1b0f8ad3c7a86b5845acc0c2cf69236e" + integrity sha512-qIC6mrlG8RQOPaYLZQiJwqnPchAVGnHWcVDeQxPMPLkM/D5+PC8tuKWYOwgLcEau3RZlgz7QQNk31Qj2/OJG6Q== -"@react-native/dev-middleware@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/dev-middleware/-/dev-middleware-0.74.86.tgz#b95f936c141dd44309a9ec558ed5ce034e270bc4" - integrity sha512-sc0tYxYt6dkUbNFI1IANzKO67M41BhjbJ6k/CHoFi/tGoNmHzg9IUZ89V4g3H8hn/VW9dETnPOFna1VO0sWrXg== +"@react-native/dev-middleware@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/dev-middleware/-/dev-middleware-0.75.2.tgz#feb325a9ec5a0fda640a0897957a43030801b1d3" + integrity sha512-fTC5m2uVjYp1XPaIJBFgscnQjPdGVsl96z/RfLgXDq0HBffyqbg29ttx6yTCx7lIa9Gdvf6nKQom+e+Oa4izSw== dependencies: "@isaacs/ttlcache" "^1.4.1" - "@react-native/debugger-frontend" "0.74.86" - "@rnx-kit/chromium-edge-launcher" "^1.0.0" + "@react-native/debugger-frontend" "0.75.2" chrome-launcher "^0.15.2" + chromium-edge-launcher "^0.2.0" connect "^3.6.5" debug "^2.2.0" node-fetch "^2.2.0" @@ -3976,37 +4001,36 @@ open "^7.0.3" selfsigned "^2.4.1" serve-static "^1.13.1" - temp-dir "^2.0.0" ws "^6.2.2" -"@react-native/gradle-plugin@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.74.86.tgz#5092d6023a4cefb1055fff251a8dae894379db9e" - integrity sha512-aoYeX7mjf3Efwc5t8AdcwC42oicMRKauGMZimvXY3xqfYV97G4foAYXrxQYZsMaxecFStdYMiXWyMFO/UFmEpA== +"@react-native/gradle-plugin@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.75.2.tgz#f5627aef8e7f17df089f4f8dae6373ea05c11854" + integrity sha512-AELeAOCZi3B2vE6SeN+mjpZjjqzqa76yfFBB3L3f3NWiu4dm/YClTGOj+5IVRRgbt8LDuRImhDoaj7ukheXr4Q== "@react-native/gradle-plugin@^0.72.11": version "0.72.11" resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.72.11.tgz#c063ef12778706611de7a1e42b74b14d9405fb9f" integrity sha512-P9iRnxiR2w7EHcZ0mJ+fmbPzMby77ZzV6y9sJI3lVLJzF7TLSdbwcQyD3lwMsiL+q5lKUHoZJS4sYmih+P2HXw== -"@react-native/js-polyfills@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.74.86.tgz#5c89c2febfb72930fee68d3eb04ba690f82a8403" - integrity sha512-Yrsj4a1rTkk618LUJJxOWFnyAZR3sHmXJwcj4qupkJs+ou3aDkixfXgVVrvQP39iBptaQvCpo7PSqs+LjSNYbA== +"@react-native/js-polyfills@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.75.2.tgz#0586fa51c043bcf9b99710ecb10982d851a0e358" + integrity sha512-AtLd3mbiE+FXK2Ru3l2NFOXDhUvzdUsCP4qspUw0haVaO/9xzV97RVD2zz0lur2f/LmZqQ2+KXyYzr7048b5iw== "@react-native/js-polyfills@^0.72.1": version "0.72.1" resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.72.1.tgz#905343ef0c51256f128256330fccbdb35b922291" integrity sha512-cRPZh2rBswFnGt5X5EUEPs0r+pAsXxYsifv/fgy9ZLQokuT52bPH+9xjDR+7TafRua5CttGW83wP4TntRcWNDA== -"@react-native/metro-babel-transformer@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.74.86.tgz#d67d3bf1699fcf834a70155635b30ae9f667b6dd" - integrity sha512-/9qN5zcnTHGDkC4jWibnoGmRnzDXiurl5wmkvspgnsdrJINN6eGpK8sdIn6nrHFOuPlp3Metqw3HkxbuAfNUXw== +"@react-native/metro-babel-transformer@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.75.2.tgz#bcb0d135c735b5cd50a7eb1ba4e51669c1f6224d" + integrity sha512-EygglCCuOub2sZ00CSIiEekCXoGL2XbOC6ssOB47M55QKvhdPG/0WBQXvmOmiN42uZgJK99Lj749v4rB0PlPIQ== dependencies: "@babel/core" "^7.20.0" - "@react-native/babel-preset" "0.74.86" - hermes-parser "0.19.1" + "@react-native/babel-preset" "0.75.2" + hermes-parser "0.22.0" nullthrows "^1.1.1" "@react-native/metro-config@^0.72.11": @@ -4024,12 +4048,12 @@ resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91" integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA== -"@react-native/normalize-colors@*", "@react-native/normalize-colors@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.74.86.tgz#8dadd294565cdb70b333f790711a019f18bbdd8b" - integrity sha512-GGA+nhwrQ1umwnkv7tuGbGIk0oBTeNbG4cUxNQX/CbYW0R98RCNxSbXjfw1XnXZd3lCSFLDxzw154V4hum2pNQ== +"@react-native/normalize-colors@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.75.2.tgz#de095f4b985580748ffa239a70ae63fbaa93724e" + integrity sha512-nPwWJFtsqNFS/qSG9yDOiSJ64mjG7RCP4X/HXFfyWzCM1jq49h/DYBdr+c3e7AvTKGIdy0gGT3vgaRUHZFVdUQ== -"@react-native/normalize-colors@^0.72.0": +"@react-native/normalize-colors@<0.73.0", "@react-native/normalize-colors@^0.72.0": version "0.72.0" resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz#14294b7ed3c1d92176d2a00df48456e8d7d62212" integrity sha512-285lfdqSXaqKuBbbtP9qL2tDrfxdOFtIMvkKadtleRQkdOxx+uzGvFr82KHmc/sSiMtfXGp7JnFYWVh4sFl7Yw== @@ -4039,15 +4063,15 @@ resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa" integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ== -"@react-native/virtualized-lists@0.74.86": - version "0.74.86" - resolved "https://registry.yarnpkg.com/@react-native/virtualized-lists/-/virtualized-lists-0.74.86.tgz#bcf99fa54de3b58c354afb77d5171afd0a0dbf05" - integrity sha512-f5wZpQvlGeWcyfK3Low0tOft9ounAaVQHpa4fiHjh9x3d2EPLwoaQe7sxS0q8/5pMISjddbF9S3ofpNuDxxoeA== +"@react-native/virtualized-lists@0.75.2": + version "0.75.2" + resolved "https://registry.yarnpkg.com/@react-native/virtualized-lists/-/virtualized-lists-0.75.2.tgz#6832fb0745a93e42dbda659426cc14a38a493282" + integrity sha512-pD5SVCjxc8k+JdoyQ+IlulBTEqJc3S4KUKsmv5zqbNCyETB0ZUvd4Su7bp+lLF6ALxx6KKmbGk8E3LaWEjUFFQ== dependencies: invariant "^2.2.4" nullthrows "^1.1.1" -"@react-native/virtualized-lists@^0.72.6": +"@react-native/virtualized-lists@^0.72.8": version "0.72.8" resolved "https://registry.yarnpkg.com/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz#a2c6a91ea0f1d40eb5a122fb063daedb92ed1dc3" integrity sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw== @@ -4055,18 +4079,6 @@ invariant "^2.2.4" nullthrows "^1.1.1" -"@rnx-kit/chromium-edge-launcher@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@rnx-kit/chromium-edge-launcher/-/chromium-edge-launcher-1.0.0.tgz#c0df8ea00a902c7a417cd9655aab06de398b939c" - integrity sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg== - dependencies: - "@types/node" "^18.0.0" - escape-string-regexp "^4.0.0" - is-wsl "^2.2.0" - lighthouse-logger "^1.0.0" - mkdirp "^1.0.4" - rimraf "^3.0.2" - "@rollup/plugin-typescript@11.1.5": version "11.1.5" resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-11.1.5.tgz#039c763bf943a5921f3f42be255895e75764cb91" @@ -4092,85 +4104,85 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.2.tgz#6b991cb44bf69e50163528ea85bed545330ba821" - integrity sha512-OHflWINKtoCFSpm/WmuQaWW4jeX+3Qt3XQDepkkiFTsoxFc5BpF3Z5aDxFZgBqRjO6ATP5+b1iilp4kGIZVWlA== - -"@rollup/rollup-android-arm64@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.2.tgz#5d3c8c2f9742d62ba258cc378bd2d4720f0c431c" - integrity sha512-k0OC/b14rNzMLDOE6QMBCjDRm3fQOHAL8Ldc9bxEWvMo4Ty9RY6rWmGetNTWhPo+/+FNd1lsQYRd0/1OSix36A== - -"@rollup/rollup-darwin-arm64@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.2.tgz#8eac8682a34a705bb6a57eb3e739fd6bbedfabed" - integrity sha512-IIARRgWCNWMTeQH+kr/gFTHJccKzwEaI0YSvtqkEBPj7AshElFq89TyreKNFAGh5frLfDCbodnq+Ye3dqGKPBw== - -"@rollup/rollup-darwin-x64@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.2.tgz#70a9953fc624bd7f645901f4250f6b5807ac7e92" - integrity sha512-52udDMFDv54BTAdnw+KXNF45QCvcJOcYGl3vQkp4vARyrcdI/cXH8VXTEv/8QWfd6Fru8QQuw1b2uNersXOL0g== - -"@rollup/rollup-linux-arm-gnueabihf@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.2.tgz#8f6c4ff4c4972413ff94345080380d4e3caa3c69" - integrity sha512-r+SI2t8srMPYZeoa1w0o/AfoVt9akI1ihgazGYPQGRilVAkuzMGiTtexNZkrPkQsyFrvqq/ni8f3zOnHw4hUbA== - -"@rollup/rollup-linux-arm-musleabihf@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.2.tgz#5d3c0fe5ea5ddf2feb511b3cb031df17eaa7e33d" - integrity sha512-+tYiL4QVjtI3KliKBGtUU7yhw0GMcJJuB9mLTCEauHEsqfk49gtUBXGtGP3h1LW8MbaTY6rSFIQV1XOBps1gBA== - -"@rollup/rollup-linux-arm64-gnu@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.2.tgz#b7f104388b2f5624d9f8adfff10ba59af8ab8ed1" - integrity sha512-OR5DcvZiYN75mXDNQQxlQPTv4D+uNCUsmSCSY2FolLf9W5I4DSoJyg7z9Ea3TjKfhPSGgMJiey1aWvlWuBzMtg== - -"@rollup/rollup-linux-arm64-musl@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.2.tgz#6d5ca6d3904309bec285ea5202d589cebb93dee4" - integrity sha512-Hw3jSfWdUSauEYFBSFIte6I8m6jOj+3vifLg8EU3lreWulAUpch4JBjDMtlKosrBzkr0kwKgL9iCfjA8L3geoA== - -"@rollup/rollup-linux-powerpc64le-gnu@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.2.tgz#4df9be1396ea9eb0ca99fd0f2e858008d7f063e3" - integrity sha512-rhjvoPBhBwVnJRq/+hi2Q3EMiVF538/o9dBuj9TVLclo9DuONqt5xfWSaE6MYiFKpo/lFPJ/iSI72rYWw5Hc7w== - -"@rollup/rollup-linux-riscv64-gnu@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.2.tgz#80d63c5562915a2f8616a04251fcaee0218112b0" - integrity sha512-EAz6vjPwHHs2qOCnpQkw4xs14XJq84I81sDRGPEjKPFVPBw7fwvtwhVjcZR6SLydCv8zNK8YGFblKWd/vRmP8g== - -"@rollup/rollup-linux-s390x-gnu@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.2.tgz#ef62e9bc5cc3b84fcfe96ec0a42d1989691217b3" - integrity sha512-IJSUX1xb8k/zN9j2I7B5Re6B0NNJDJ1+soezjNojhT8DEVeDNptq2jgycCOpRhyGj0+xBn7Cq+PK7Q+nd2hxLA== - -"@rollup/rollup-linux-x64-gnu@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.2.tgz#6a275282a0080fee98ddd9fda0de23c4c6bafd48" - integrity sha512-OgaToJ8jSxTpgGkZSkwKE+JQGihdcaqnyHEFOSAU45utQ+yLruE1dkonB2SDI8t375wOKgNn8pQvaWY9kPzxDQ== - -"@rollup/rollup-linux-x64-musl@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.2.tgz#64f0c704107e6b45b26dd8c2e1ff64246e4a1251" - integrity sha512-5V3mPpWkB066XZZBgSd1lwozBk7tmOkKtquyCJ6T4LN3mzKENXyBwWNQn8d0Ci81hvlBw5RoFgleVpL6aScLYg== - -"@rollup/rollup-win32-arm64-msvc@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.2.tgz#bada17b0c5017ff58d0feba401c43ff5a646c693" - integrity sha512-ayVstadfLeeXI9zUPiKRVT8qF55hm7hKa+0N1V6Vj+OTNFfKSoUxyZvzVvgtBxqSb5URQ8sK6fhwxr9/MLmxdA== - -"@rollup/rollup-win32-ia32-msvc@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.2.tgz#a716d862f6ac39d88bdb825e27f63aeb0387cd66" - integrity sha512-Mda7iG4fOLHNsPqjWSjANvNZYoW034yxgrndof0DwCy0D3FvTjeNo+HGE6oGWgvcLZNLlcp0hLEFcRs+UGsMLg== - -"@rollup/rollup-win32-x64-msvc@4.19.2": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.2.tgz#d67206c5f2e4b2832ce360bbbde194e96d16dc51" - integrity sha512-DPi0ubYhSow/00YqmG1jWm3qt1F8aXziHc/UNy8bo9cpCacqhuWu+iSq/fp2SyEQK7iYTZ60fBU9cat3MXTjIQ== +"@rollup/rollup-android-arm-eabi@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" + integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w== + +"@rollup/rollup-android-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb" + integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA== + +"@rollup/rollup-darwin-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b" + integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q== + +"@rollup/rollup-darwin-x64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791" + integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw== + +"@rollup/rollup-linux-arm-gnueabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232" + integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ== + +"@rollup/rollup-linux-arm-musleabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa" + integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg== + +"@rollup/rollup-linux-arm64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15" + integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw== + +"@rollup/rollup-linux-arm64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820" + integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e" + integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg== + +"@rollup/rollup-linux-riscv64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128" + integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA== + +"@rollup/rollup-linux-s390x-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc" + integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q== + +"@rollup/rollup-linux-x64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0" + integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg== + +"@rollup/rollup-linux-x64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f" + integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g== + +"@rollup/rollup-win32-arm64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0" + integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw== + +"@rollup/rollup-win32-ia32-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422" + integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g== + +"@rollup/rollup-win32-x64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" + integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== "@semantic-ui-react/event-stack@^3.1.0": version "3.1.3" @@ -4294,17 +4306,19 @@ tslib "^2.6.2" "@smithy/core@^2.3.1": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.3.2.tgz#4a1e3da41d2a3a494cbc6bd1fc6eeb26b2e27184" - integrity sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q== + version "2.4.0" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.4.0.tgz#56e917b6ab2dffeba681a05395c40a757d681147" + integrity sha512-cHXq+FneIF/KJbt4q4pjN186+Jf4ZB0ZOqEaZMBhT79srEyGDDBV31NqBRBjazz8ppQ1bJbDJMY9ba5wKFV36w== dependencies: "@smithy/middleware-endpoint" "^3.1.0" - "@smithy/middleware-retry" "^3.0.14" + "@smithy/middleware-retry" "^3.0.15" "@smithy/middleware-serde" "^3.0.3" "@smithy/protocol-http" "^4.1.0" - "@smithy/smithy-client" "^3.1.12" + "@smithy/smithy-client" "^3.2.0" "@smithy/types" "^3.3.0" + "@smithy/util-body-length-browser" "^3.0.0" "@smithy/util-middleware" "^3.0.3" + "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" "@smithy/credential-provider-imds@^3.2.0": @@ -4339,11 +4353,11 @@ tslib "^2.6.2" "@smithy/eventstream-serde-browser@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.5.tgz#3e971afd2b8a02a098af8decc4b9e3f35296d6a2" - integrity sha512-dEyiUYL/ekDfk+2Ra4GxV+xNnFoCmk1nuIXg+fMChFTrM2uI/1r9AdiTYzPqgb72yIv/NtAj6C3dG//1wwgakQ== + version "3.0.6" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.6.tgz#a4ab4f7cfbd137bcaa54c375276f9214e568fd8f" + integrity sha512-2hM54UWQUOrki4BtsUI1WzmD13/SeaqT/AB3EUJKbcver/WgKNaiJ5y5F5XXuVe6UekffVzuUDrBZVAA3AWRpQ== dependencies: - "@smithy/eventstream-serde-universal" "^3.0.4" + "@smithy/eventstream-serde-universal" "^3.0.5" "@smithy/types" "^3.3.0" tslib "^2.6.2" @@ -4356,18 +4370,18 @@ tslib "^2.6.2" "@smithy/eventstream-serde-node@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.4.tgz#6301752ca51b3ebabcd2dec112f1dacd990de4c1" - integrity sha512-mjlG0OzGAYuUpdUpflfb9zyLrBGgmQmrobNT8b42ZTsGv/J03+t24uhhtVEKG/b2jFtPIHF74Bq+VUtbzEKOKg== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.5.tgz#2bbf5c9312a28f23bc55ae284efa9499f8b8f982" + integrity sha512-+upXvnHNyZP095s11jF5dhGw/Ihzqwl5G+/KtMnoQOpdfC3B5HYCcDVG9EmgkhJMXJlM64PyN5gjJl0uXFQehQ== dependencies: - "@smithy/eventstream-serde-universal" "^3.0.4" + "@smithy/eventstream-serde-universal" "^3.0.5" "@smithy/types" "^3.3.0" tslib "^2.6.2" -"@smithy/eventstream-serde-universal@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.4.tgz#6754de5b94bdc286d8ef1d6bcf22d80f6ab68f30" - integrity sha512-Od9dv8zh3PgOD7Vj4T3HSuox16n0VG8jJIM2gvKASL6aCtcS8CfHZDWe1Ik3ZXW6xBouU+45Q5wgoliWDZiJ0A== +"@smithy/eventstream-serde-universal@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.5.tgz#e1cc2f71f4d174a03e00ce4b563395a81dd17bec" + integrity sha512-5u/nXbyoh1s4QxrvNre9V6vfyoLWuiVvvd5TlZjGThIikc3G+uNiG9uOTCWweSRjv1asdDIWK7nOmN7le4RYHQ== dependencies: "@smithy/eventstream-codec" "^3.1.2" "@smithy/types" "^3.3.0" @@ -4447,15 +4461,15 @@ "@smithy/util-middleware" "^3.0.3" tslib "^2.6.2" -"@smithy/middleware-retry@^3.0.13", "@smithy/middleware-retry@^3.0.14": - version "3.0.14" - resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz#739e8bac6e465e0cda26446999db614418e79da3" - integrity sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ== +"@smithy/middleware-retry@^3.0.13", "@smithy/middleware-retry@^3.0.15": + version "3.0.15" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.15.tgz#9b96900cde70d8aafd267e13f4e79241be90e0c7" + integrity sha512-iTMedvNt1ApdvkaoE8aSDuwaoc+BhvHqttbA/FO4Ty+y/S5hW6Ci/CTScG7vam4RYJWZxdTElc3MEfHRVH6cgQ== dependencies: "@smithy/node-config-provider" "^3.1.4" "@smithy/protocol-http" "^4.1.0" "@smithy/service-error-classification" "^3.0.3" - "@smithy/smithy-client" "^3.1.12" + "@smithy/smithy-client" "^3.2.0" "@smithy/types" "^3.3.0" "@smithy/util-middleware" "^3.0.3" "@smithy/util-retry" "^3.0.3" @@ -4561,10 +4575,10 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@smithy/smithy-client@^3.1.11", "@smithy/smithy-client@^3.1.12": - version "3.1.12" - resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.1.12.tgz#fb6386816ff8a5c50eab7503d4ee3ba2e4ebac63" - integrity sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA== +"@smithy/smithy-client@^3.1.11", "@smithy/smithy-client@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.2.0.tgz#6db94024e4bdaefa079ac68dbea23dafbea230c8" + integrity sha512-pDbtxs8WOhJLJSeaF/eAbPgXg4VVYFlRcL/zoNYA5WbG3wBL06CHtBSg53ppkttDpAJ/hdiede+xApip1CwSLw== dependencies: "@smithy/middleware-endpoint" "^3.1.0" "@smithy/middleware-stack" "^3.0.3" @@ -4643,26 +4657,26 @@ tslib "^2.6.2" "@smithy/util-defaults-mode-browser@^3.0.13": - version "3.0.14" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz#21f3ebcb07b9d6ae1274b9d655c38bdac59e5c06" - integrity sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w== + version "3.0.15" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.15.tgz#df73b9ae3dddc9126e0bb93ebc720b09d7163858" + integrity sha512-FZ4Psa3vjp8kOXcd3HJOiDPBCWtiilLl57r0cnNtq/Ga9RSDrM5ERL6xt+tO43+2af6Pn5Yp92x2n5vPuduNfg== dependencies: "@smithy/property-provider" "^3.1.3" - "@smithy/smithy-client" "^3.1.12" + "@smithy/smithy-client" "^3.2.0" "@smithy/types" "^3.3.0" bowser "^2.11.0" tslib "^2.6.2" "@smithy/util-defaults-mode-node@^3.0.13": - version "3.0.14" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz#6bb9e837282e84bbf5093dbcd120fcd296593f7a" - integrity sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ== + version "3.0.15" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.15.tgz#d52476e1f2e66525d918b51f8d5a9b0972bf518e" + integrity sha512-KSyAAx2q6d0t6f/S4XB2+3+6aQacm3aLMhs9aLMqn18uYGUepbdssfogW5JQZpc6lXNBnp0tEnR5e9CEKmEd7A== dependencies: "@smithy/config-resolver" "^3.0.5" "@smithy/credential-provider-imds" "^3.2.0" "@smithy/node-config-provider" "^3.1.4" "@smithy/property-provider" "^3.1.3" - "@smithy/smithy-client" "^3.1.12" + "@smithy/smithy-client" "^3.2.0" "@smithy/types" "^3.3.0" tslib "^2.6.2" @@ -5036,9 +5050,9 @@ integrity sha512-5ZZ5+YGmUE01yejiXsKnTcvhakMZ2UllZlMsQni53Doc1JWhe21ia8VntRoRD6fAEWw08JBh/z9qQHJ+//MrIg== "@types/aws-lambda@^8.10.134": - version "8.10.142" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.142.tgz#cb1d90bc45095e4f59e4ddfbb34a2e29c28d66b4" - integrity sha512-wy2y/2hQKrS6myOS++koXg3N1Hg+LLyPjaggCFajczSHZPqBnOMuT2sdH3kiASrmdBYyM3pmjyz5SoWraRllCQ== + version "8.10.143" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.143.tgz#383693fbaadc6994a71d64a7c09e8c244fad8dff" + integrity sha512-u5vzlcR14ge/4pMTTMDQr3MF0wEe38B2F9o84uC4F43vN5DGTy63npRrB6jQhyt+C0lGv4ZfiRcRkqJoZuPnmg== "@types/babel__core@^7.1.14": version "7.20.5" @@ -5083,26 +5097,10 @@ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.5.1.tgz#b29aa1f91a59f35e29ff8f7cb24faf1a3a750554" integrity sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g== -"@types/eslint-scope@^3.7.3": - version "3.7.7" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" - integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "9.6.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.0.tgz#51d4fe4d0316da9e9f2c80884f2c20ed5fb022ff" - integrity sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - "@types/eslint@^8.56.10": - version "8.56.11" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.11.tgz#e2ff61510a3b9454b3329fe7731e3b4c6f780041" - integrity sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q== + version "8.56.12" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.12.tgz#1657c814ffeba4d2f84c0d4ba0f44ca7ea1ca53a" + integrity sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -5173,7 +5171,7 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -5216,11 +5214,11 @@ "@types/node" "*" "@types/node@*": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.0.2.tgz#9fb1a2b31970871e8bf696f0e8a40d2e6d2bd04e" - integrity sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ== + version "22.5.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.0.tgz#10f01fe9465166b4cab72e75f60d8b99d019f958" + integrity sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg== dependencies: - undici-types "~6.11.1" + undici-types "~6.19.2" "@types/node@16.18.82": version "16.18.82" @@ -5235,18 +5233,18 @@ undici-types "~5.26.4" "@types/node@^18.0.0": - version "18.19.42" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.42.tgz#b54ed4752c85427906aab40917b0f7f3d724bf72" - integrity sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg== + version "18.19.46" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.46.tgz#51801396c01153e0626e36f43386e83bc768b072" + integrity sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA== dependencies: undici-types "~5.26.4" "@types/node@^20.3.1": - version "20.14.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.13.tgz#bf4fe8959ae1c43bc284de78bd6c01730933736b" - integrity sha512-+bHoGiZb8UiQ0+WEtmph2IWQCjIqg8MDZMAV+ppRRhUZnquF5mQkP/9vpSwJClEiSM/C7fZZExPzfU0vJTyp8w== + version "20.16.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.1.tgz#0b44b15271d0e2191ca68faf1fbe506e06aed732" + integrity sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ== dependencies: - undici-types "~5.26.4" + undici-types "~6.19.2" "@types/node@^8.9.5": version "8.10.66" @@ -5296,9 +5294,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^18.2.13": - version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== + version "18.3.4" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.4.tgz#dfdd534a1d081307144c00e325c06e00312c93a3" + integrity sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw== dependencies: "@types/prop-types" "*" csstype "^3.0.2" @@ -5357,9 +5355,9 @@ "@types/yargs-parser" "*" "@types/yargs@^17.0.8": - version "17.0.32" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" - integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" @@ -5994,9 +5992,9 @@ async-limiter@~1.0.0: integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== async@^3.2.2, async@^3.2.3: - version "3.2.5" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" @@ -6016,9 +6014,9 @@ aws-jwt-verify@^4.0.1: integrity sha512-kzvi71eD3w/mCpYRUY7cz6DX4bfYihGdI2yV3FYQ2JuZZenqAqDPz0gWj0ew6vlAtdEVBNb7p+Dm2TAIxpVYMA== axios@^1.0.0: - version "1.7.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" - integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== + version "1.7.5" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.5.tgz#21eed340eb5daf47d29b6e002424b3e88c8c54b1" + integrity sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -6093,13 +6091,13 @@ babel-plugin-polyfill-corejs2@^0.4.10: "@babel/helper-define-polyfill-provider" "^0.6.2" semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.10.1, babel-plugin-polyfill-corejs3@^0.10.4: - version "0.10.4" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz#789ac82405ad664c20476d0233b485281deb9c77" - integrity sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg== +babel-plugin-polyfill-corejs3@^0.10.6: + version "0.10.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" + integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.1" - core-js-compat "^3.36.1" + "@babel/helper-define-polyfill-provider" "^0.6.2" + core-js-compat "^3.38.0" babel-plugin-polyfill-regenerator@^0.6.1: version "0.6.2" @@ -6121,22 +6119,25 @@ babel-plugin-transform-flow-enums@^0.0.2: "@babel/plugin-syntax-flow" "^7.12.1" babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" babel-preset-fbjs@^3.4.0: version "3.4.0" @@ -6286,7 +6287,7 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -browserslist@^4.21.10, browserslist@^4.23.0, browserslist@^4.23.1: +browserslist@^4.21.10, browserslist@^4.23.1, browserslist@^4.23.3: version "4.23.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== @@ -6296,7 +6297,7 @@ browserslist@^4.21.10, browserslist@^4.23.0, browserslist@^4.23.1: node-releases "^2.0.18" update-browserslist-db "^1.1.0" -bs-logger@0.x: +bs-logger@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== @@ -6500,9 +6501,9 @@ camelcase@^6.0.0, camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001646: - version "1.0.30001646" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz#d472f2882259ba032dd73ee069ff01bfd059b25d" - integrity sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw== + version "1.0.30001653" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz#b8af452f8f33b1c77f122780a4aecebea0caca56" + integrity sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw== chalk@4.1.0: version "4.1.0" @@ -6589,6 +6590,18 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== +chromium-edge-launcher@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz#0c378f28c99aefc360705fa155de0113997f62fc" + integrity sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg== + dependencies: + "@types/node" "*" + escape-string-regexp "^4.0.0" + is-wsl "^2.2.0" + lighthouse-logger "^1.0.0" + mkdirp "^1.0.4" + rimraf "^3.0.2" + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -6600,9 +6613,9 @@ ci-info@^3.2.0, ci-info@^3.6.1: integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" - integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== + version "1.4.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.0.tgz#677de7ed7efff67cc40c9bf1897fea79d41b5215" + integrity sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g== classnames@^2.2.6: version "2.5.1" @@ -7005,12 +7018,12 @@ cookie@0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -core-js-compat@^3.36.1, core-js-compat@^3.37.1: - version "3.37.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.1.tgz#c844310c7852f4bdf49b8d339730b97e17ff09ee" - integrity sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg== +core-js-compat@^3.37.1, core-js-compat@^3.38.0: + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.1.tgz#2bc7a298746ca5a7bcb9c164bcb120f2ebc09a09" + integrity sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw== dependencies: - browserslist "^4.23.0" + browserslist "^4.23.3" core-util-is@~1.0.0: version "1.0.3" @@ -7037,7 +7050,17 @@ cosmiconfig@^8.2.0: parse-json "^5.2.0" path-type "^4.0.0" -crc-32@^1.2.2: +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== + dependencies: + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + +crc-32@1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== @@ -7166,9 +7189,9 @@ dateformat@^3.0.3: integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== dayjs@^1.8.15: - version "1.11.12" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.12.tgz#5245226cc7f40a15bf52e0b99fd2a04669ccac1d" - integrity sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg== + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== debounce@^1.2.1: version "1.2.1" @@ -7182,7 +7205,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@~4.3.4: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@~4.3.6: version "4.3.6" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== @@ -7327,15 +7350,6 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -deprecated-react-native-prop-types@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.1.0.tgz#8ed03a64c21b7fbdd2d000957b6838d4f38d2c66" - integrity sha512-WfepZHmRbbdTvhcolb8aOKEvQdcmTMn5tKLbqbXmkBvjFjRVWAYqsXk/DBsV8TZxws8SdGHLuHaJrHSQUPRdfw== - dependencies: - "@react-native/normalize-colors" "*" - invariant "*" - prop-types "*" - deprecated-react-native-prop-types@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-3.0.2.tgz#e724a9837e6a7ccb778753c06ae4f79065873493" @@ -7345,6 +7359,15 @@ deprecated-react-native-prop-types@^3.0.1: invariant "^2.2.4" prop-types "^15.8.1" +deprecated-react-native-prop-types@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.2.3.tgz#0ef845c1a80ef1636bd09060e4cdf70f9727e5ad" + integrity sha512-2rLTiMKidIFFYpIVM69UnQKngLqQfL6I11Ch8wGSBftS18FUXda+o2we2950X+1dmbgps28niI3qwyH4eX3Z1g== + dependencies: + "@react-native/normalize-colors" "<0.73.0" + invariant "^2.2.4" + prop-types "^15.8.1" + deprecation@^2.0.0: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" @@ -7465,9 +7488,9 @@ ejs@^3.1.10, ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz#cd477c830dd6fca41fbd5465c1ff6ce08ac22343" - integrity sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA== + version "1.5.13" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6" + integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q== emittery@^0.13.1: version "0.13.1" @@ -7475,9 +7498,9 @@ emittery@^0.13.1: integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^10.3.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" - integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw== + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== emoji-regex@^7.0.1: version "7.0.3" @@ -7504,6 +7527,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + encoding@^0.1.12, encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -7518,7 +7546,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.0.0, enhanced-resolve@^5.12.0, enhanced-resolve@^5.17.0: +enhanced-resolve@^5.0.0, enhanced-resolve@^5.15.0, enhanced-resolve@^5.17.1: version "5.17.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== @@ -7538,7 +7566,7 @@ entities@^4.4.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== -env-paths@^2.2.0: +env-paths@^2.2.0, env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== @@ -7548,7 +7576,7 @@ envinfo@7.8.1: resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== -envinfo@^7.10.0, envinfo@^7.7.2, envinfo@^7.7.3: +envinfo@^7.13.0, envinfo@^7.7.2, envinfo@^7.7.3: version "7.13.0" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.13.0.tgz#81fbb81e5da35d74e814941aeab7c325a606fb31" integrity sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q== @@ -7749,22 +7777,23 @@ eslint-import-resolver-node@^0.3.9: resolve "^1.22.4" eslint-import-resolver-typescript@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" - integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== + version "3.6.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e" + integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA== dependencies: - debug "^4.3.4" - enhanced-resolve "^5.12.0" - eslint-module-utils "^2.7.4" - fast-glob "^3.3.1" - get-tsconfig "^4.5.0" - is-core-module "^2.11.0" + "@nolyfill/is-core-module" "1.0.39" + debug "^4.3.5" + enhanced-resolve "^5.15.0" + eslint-module-utils "^2.8.1" + fast-glob "^3.3.2" + get-tsconfig "^4.7.5" + is-bun-module "^1.0.2" is-glob "^4.0.3" -eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" - integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== +eslint-module-utils@^2.8.0, eslint-module-utils@^2.8.1: + version "2.8.2" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz#2ecad69d71e1fa81f17f7f24d5d3e46b168de663" + integrity sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg== dependencies: debug "^3.2.7" @@ -7801,9 +7830,9 @@ eslint-plugin-import@^2.29.1: tsconfig-paths "^3.15.0" eslint-plugin-jsdoc@^48.0.4: - version "48.10.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.2.tgz#dd3fb8b8d4c6a0add3191b7f00b32a1e1ca7880d" - integrity sha512-xTkf/MmEeVrTbezc6kDqCJmK9RcseIKo8X4oyoDCMvV4LY8dqrQi8kmfRrv9n0gNBkCclevaOh2Lkmu6Fs8SLg== + version "48.11.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.11.0.tgz#7c8dae6ce0d814aff54b87fdb808f02635691ade" + integrity sha512-d12JHJDPNo7IFwTOAItCeJY1hcqoIxE0lHA8infQByLilQ9xkqrRa6laWCnsuCrf+8rUnvxXY1XuTbibRBNylA== dependencies: "@es-joy/jsdoccomment" "~0.46.0" are-docs-informative "^0.0.2" @@ -8146,7 +8175,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@3, fast-glob@^3.0.3, fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.1, fast-glob@^3.3.2: +fast-glob@3, fast-glob@^3.0.3, fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -8353,9 +8382,9 @@ flow-enums-runtime@^0.0.6: integrity sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw== flow-parser@0.*: - version "0.242.1" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.242.1.tgz#d95977303d2cca0c1cb39394f5f5098d1ed5fc95" - integrity sha512-E3ml21Q1S5cMAyPbtYslkvI6yZO5oCS/S2EoteeFH8Kx9iKOv/YOJ+dGd/yMf+H3YKfhMKjnOpyNwrO7NdddWA== + version "0.244.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.244.0.tgz#dc75ef468959ca72ad5fd89a6a9b0503c141ea8a" + integrity sha512-Dkc88m5k8bx1VvHTO9HEJ7tvMcSb3Zvcv1PY4OHK7pHdtdY2aUjhmPy6vpjVJ2uUUOIybRlb91sXE8g4doChtA== flow-parser@^0.185.0: version "0.185.2" @@ -8380,9 +8409,9 @@ for-each@^0.3.3: is-callable "^1.1.3" foreground-child@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" - integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -8587,7 +8616,7 @@ get-symbol-description@^1.0.2: es-errors "^1.3.0" get-intrinsic "^1.2.4" -get-tsconfig@^4.5.0, get-tsconfig@^4.7.0: +get-tsconfig@^4.7.0, get-tsconfig@^4.7.5: version "4.7.6" resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.6.tgz#118fd5b7b9bae234cc7705a00cd771d7eb65d62a" integrity sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA== @@ -8675,17 +8704,6 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@10.3.10, glob@^10.0.0@10.3.10, glob@^10.2.2: - version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" - glob@7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" @@ -8710,6 +8728,18 @@ glob@7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.2.2, glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -8896,15 +8926,15 @@ hermes-estree@0.12.0: resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.12.0.tgz#8a289f9aee854854422345e6995a48613bac2ca8" integrity sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw== -hermes-estree@0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.19.1.tgz#d5924f5fac2bf0532547ae9f506d6db8f3c96392" - integrity sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g== +hermes-estree@0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.22.0.tgz#38559502b119f728901d2cfe2ef422f277802a1d" + integrity sha512-FLBt5X9OfA8BERUdc6aZS36Xz3rRuB0Y/mfocSADWEJfomc1xfene33GdyAmtTkKTBXTN/EgAy+rjTKkkZJHlw== -hermes-estree@0.20.1: - version "0.20.1" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.20.1.tgz#0b9a544cf883a779a8e1444b915fa365bef7f72d" - integrity sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg== +hermes-estree@0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.23.0.tgz#89c5419877b9d6bce4bb616821f496f5c5daddbc" + integrity sha512-Rkp0PNLGpORw4ktsttkVbpYJbrYKS3hAnkxu8D9nvQi6LvSbuPa+tYw/t2u3Gjc35lYd/k95YkjqyTcN4zspag== hermes-estree@0.8.0: version "0.8.0" @@ -8918,19 +8948,19 @@ hermes-parser@0.12.0: dependencies: hermes-estree "0.12.0" -hermes-parser@0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.19.1.tgz#1044348097165b7c93dc198a80b04ed5130d6b1a" - integrity sha512-Vp+bXzxYJWrpEuJ/vXxUsLnt0+y4q9zyi4zUlkLqD8FKv4LjIfOvP69R/9Lty3dCyKh0E2BU7Eypqr63/rKT/A== +hermes-parser@0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.22.0.tgz#fc8e0e6c7bfa8db85b04c9f9544a102c4fcb4040" + integrity sha512-gn5RfZiEXCsIWsFGsKiykekktUoh0PdFWYocXsUdZIyWSckT6UIyPcyyUIPSR3kpnELWeK3n3ztAse7Mat6PSA== dependencies: - hermes-estree "0.19.1" + hermes-estree "0.22.0" -hermes-parser@0.20.1: - version "0.20.1" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.20.1.tgz#ad10597b99f718b91e283f81cbe636c50c3cff92" - integrity sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA== +hermes-parser@0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.23.0.tgz#3541907b77ca9e94fd093e8ef0ff97ca5340dee8" + integrity sha512-xLwM4ylfHGwrm+2qXfO1JT/fnqEDGSnpS/9hQ4VLtqTexSviu2ZpBgz07U8jVtndq67qdb/ps0qvaWDZ3fkTyg== dependencies: - hermes-estree "0.20.1" + hermes-estree "0.23.0" hermes-parser@0.8.0: version "0.8.0" @@ -9044,9 +9074,9 @@ humanize-ms@^1.2.1: ms "^2.0.0" husky@^9.0.11: - version "9.1.4" - resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.4.tgz#926fd19c18d345add5eab0a42b2b6d9a80259b34" - integrity sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA== + version "9.1.5" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.5.tgz#2b6edede53ee1adbbd3a3da490628a23f5243b83" + integrity sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag== iconv-lite@0.6.3, iconv-lite@^0.6.2: version "0.6.3" @@ -9087,9 +9117,9 @@ ignore-walk@^6.0.0: minimatch "^9.0.0" ignore@^5.0.4, ignore@^5.1.1, ignore@^5.1.2, ignore@^5.2.0, ignore@^5.2.4: - version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== image-size@^0.6.0: version "0.6.3" @@ -9247,7 +9277,7 @@ interpret@^3.1.1: resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== -invariant@*, invariant@^2.2.4: +invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -9262,11 +9292,6 @@ ip-address@^9.0.5: jsbn "1.1.0" sprintf-js "^1.1.3" -ip@^1.1.5: - version "1.1.9" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" - integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== - is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -9322,6 +9347,13 @@ is-builtin-module@^3.2.1: dependencies: builtin-modules "^3.3.0" +is-bun-module@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.1.0.tgz#a66b9830869437f6cdad440ba49ab6e4dc837269" + integrity sha512-4mTAVPlrXpaN3jtF0lsnPCMGnq4+qZjVIKq0HCpfcqf8OC1SM5oATCIAPM5V5FN05qp2NNnFndphmdZS9CV3hA== + dependencies: + semver "^7.6.3" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -9334,10 +9366,10 @@ is-ci@3.0.1: dependencies: ci-info "^3.2.0" -is-core-module@^2.11.0, is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.8.1: - version "2.15.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" - integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== +is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.8.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: hasown "^2.0.2" @@ -9647,10 +9679,10 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" - integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -10492,7 +10524,7 @@ lilconfig@^2.1.0: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== -lilconfig@^3.1.1, lilconfig@~3.1.1: +lilconfig@^3.1.1, lilconfig@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== @@ -10516,22 +10548,22 @@ lines-and-columns@~2.0.3: integrity sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A== lint-staged@^15.2.2: - version "15.2.7" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.7.tgz#97867e29ed632820c0fb90be06cd9ed384025649" - integrity sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw== + version "15.2.9" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.9.tgz#bf70d40b6b192df6ad756fb89822211615e0f4da" + integrity sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ== dependencies: chalk "~5.3.0" commander "~12.1.0" - debug "~4.3.4" + debug "~4.3.6" execa "~8.0.1" - lilconfig "~3.1.1" - listr2 "~8.2.1" + lilconfig "~3.1.2" + listr2 "~8.2.4" micromatch "~4.0.7" pidtree "~0.6.0" string-argv "~0.3.2" - yaml "~2.4.2" + yaml "~2.5.0" -listr2@~8.2.1: +listr2@~8.2.4: version "8.2.4" resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.4.tgz#486b51cbdb41889108cb7e2c90eeb44519f5a77f" integrity sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g== @@ -10617,7 +10649,7 @@ lodash.ismatch@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== -lodash.memoize@4.x: +lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== @@ -10723,7 +10755,7 @@ make-dir@^3.0.2, make-dir@^3.1.0: dependencies: semver "^6.0.0" -make-error@1.x: +make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -10888,15 +10920,6 @@ metro-babel-transformer@0.73.5: metro-source-map "0.73.5" nullthrows "^1.1.1" -metro-babel-transformer@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz#ba620d64cbaf97d1aa14146d654a3e5d7477fc62" - integrity sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw== - dependencies: - "@babel/core" "^7.20.0" - hermes-parser "0.12.0" - nullthrows "^1.1.1" - metro-babel-transformer@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.76.9.tgz#659ba481d471b5f748c31a8f9397094b629f50ec" @@ -10906,13 +10929,14 @@ metro-babel-transformer@0.76.9: hermes-parser "0.12.0" nullthrows "^1.1.1" -metro-babel-transformer@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.80.9.tgz#7051ba377b7d2140abd23f4846bbbb1e81fea99b" - integrity sha512-d76BSm64KZam1nifRZlNJmtwIgAeZhZG3fi3K+EmPOlrR8rDtBxQHDSN3fSGeNB9CirdTyabTMQCkCup6BXFSQ== +metro-babel-transformer@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.80.10.tgz#a8d204ae51872b1024715e2c545363d7a3acdca3" + integrity sha512-GXHueUzgzcazfzORDxDzWS9jVVRV6u+cR6TGvHOfGdfLzJCj7/D0PretLfyq+MwN20twHxLW+BUXkoaB8sCQBg== dependencies: "@babel/core" "^7.20.0" - hermes-parser "0.20.1" + flow-enums-runtime "^0.0.6" + hermes-parser "0.23.0" nullthrows "^1.1.1" metro-cache-key@0.73.10: @@ -10920,20 +10944,17 @@ metro-cache-key@0.73.10: resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.73.10.tgz#8d63591187d295b62a80aed64a87864b1e9d67a2" integrity sha512-JMVDl/EREDiUW//cIcUzRjKSwE2AFxVWk47cFBer+KA4ohXIG2CQPEquT56hOw1Y1s6gKNxxs1OlAOEsubrFjw== -metro-cache-key@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.76.7.tgz#70913f43b92b313096673c37532edd07438cb325" - integrity sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ== - metro-cache-key@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.76.9.tgz#6f17f821d6f306fa9028b7e79445eb18387d03d9" integrity sha512-ugJuYBLngHVh1t2Jj+uP9pSCQl7enzVXkuh6+N3l0FETfqjgOaSHlcnIhMPn6yueGsjmkiIfxQU4fyFVXRtSTw== -metro-cache-key@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.80.9.tgz#a04cbb0a7828509bb10dde9789ef761c0c60bc3d" - integrity sha512-hRcYGhEiWIdM87hU0fBlcGr+tHDEAT+7LYNCW89p5JhErFt/QaAkVx4fb5bW3YtXGv5BTV7AspWPERoIb99CXg== +metro-cache-key@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.80.10.tgz#7b2505c16ac333af857cedb20bde0373e1855944" + integrity sha512-57qBhO3zQfoU/hP4ZlLW5hVej2jVfBX6B4NcSfMj4LgDPL3YknWg80IJBxzQfjQY/m+fmMLmPy8aUMHzUp/guA== + dependencies: + flow-enums-runtime "^0.0.6" metro-cache@0.73.10: version "0.73.10" @@ -10943,14 +10964,6 @@ metro-cache@0.73.10: metro-core "0.73.10" rimraf "^3.0.2" -metro-cache@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.76.7.tgz#e49e51423fa960df4eeff9760d131f03e003a9eb" - integrity sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg== - dependencies: - metro-core "0.76.7" - rimraf "^3.0.2" - metro-cache@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.76.9.tgz#64326d7a8b470c3886a5e97d5e2a20acab20bc5f" @@ -10959,13 +10972,14 @@ metro-cache@0.76.9: metro-core "0.76.9" rimraf "^3.0.2" -metro-cache@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.80.9.tgz#b914318a90dbcd51b4c27836184519c441ba5123" - integrity sha512-ujEdSI43QwI+Dj2xuNax8LMo8UgKuXJEdxJkzGPU6iIx42nYa1byQ+aADv/iPh5sh5a//h5FopraW5voXSgm2w== +metro-cache@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.80.10.tgz#3110af31ee8d77397965d6c3e7afadb778bdc8a3" + integrity sha512-8CBtDJwMguIE5RvV3PU1QtxUG8oSSX54mIuAbRZmcQ0MYiOl9JdrMd4JCBvIyhiZLoSStph425SMyCSnjtJsdA== dependencies: - metro-core "0.80.9" - rimraf "^3.0.2" + exponential-backoff "^3.1.1" + flow-enums-runtime "^0.0.6" + metro-core "0.80.10" metro-config@0.73.10: version "0.73.10" @@ -10979,19 +10993,6 @@ metro-config@0.73.10: metro-core "0.73.10" metro-runtime "0.73.10" -metro-config@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.76.7.tgz#f0fc171707523aa7d3a9311550872136880558c0" - integrity sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg== - dependencies: - connect "^3.6.5" - cosmiconfig "^5.0.5" - jest-validate "^29.2.1" - metro "0.76.7" - metro-cache "0.76.7" - metro-core "0.76.7" - metro-runtime "0.76.7" - metro-config@0.76.9, metro-config@^0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.76.9.tgz#5e60aff9d8894c1ee6bbc5de23b7c8515a0b84a3" @@ -11005,18 +11006,19 @@ metro-config@0.76.9, metro-config@^0.76.9: metro-core "0.76.9" metro-runtime "0.76.9" -metro-config@0.80.9, metro-config@^0.80.3: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.80.9.tgz#4eb6948b0ddc7c38d9d4ba8ddf22a67ca1c2bc06" - integrity sha512-28wW7CqS3eJrunRGnsibWldqgwRP9ywBEf7kg+uzUHkSFJNKPM1K3UNSngHmH0EZjomizqQA2Zi6/y6VdZMolg== +metro-config@0.80.10, metro-config@^0.80.3: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.80.10.tgz#86c7a5e2665fb8b4c7ffd08976803c88fd6ce962" + integrity sha512-0GYAw0LkmGbmA81FepKQepL1KU/85Cyv7sAiWm6QWeV6AcVCpsKg6jGLqGHJ0LLPL60rWzA4TV1DQAlzdJAEtA== dependencies: connect "^3.6.5" cosmiconfig "^5.0.5" + flow-enums-runtime "^0.0.6" jest-validate "^29.6.3" - metro "0.80.9" - metro-cache "0.80.9" - metro-core "0.80.9" - metro-runtime "0.80.9" + metro "0.80.10" + metro-cache "0.80.10" + metro-core "0.80.10" + metro-runtime "0.80.10" metro-core@0.73.10: version "0.73.10" @@ -11026,15 +11028,7 @@ metro-core@0.73.10: lodash.throttle "^4.1.1" metro-resolver "0.73.10" -metro-core@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.76.7.tgz#5d2b8bac2cde801dc22666ad7be1336d1f021b61" - integrity sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw== - dependencies: - lodash.throttle "^4.1.1" - metro-resolver "0.76.7" - -metro-core@0.76.9: +metro-core@0.76.9, metro-core@^0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.76.9.tgz#5f55f0fbde41d28957e4f3bb187d32251403f00e" integrity sha512-DSeEr43Wrd5Q7ySfRzYzDwfV89g2OZTQDf1s3exOcLjE5fb7awoLOkA2h46ZzN8NcmbbM0cuJy6hOwF073/yRQ== @@ -11042,13 +11036,14 @@ metro-core@0.76.9: lodash.throttle "^4.1.1" metro-resolver "0.76.9" -metro-core@0.80.9, metro-core@^0.80.3: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.80.9.tgz#3af21d0b09d71ec9c0840f028bffb36bc3619727" - integrity sha512-tbltWQn+XTdULkGdzHIxlxk4SdnKxttvQQV3wpqqFbHDteR4gwCyTR2RyYJvxgU7HELfHtrVbqgqAdlPByUSbg== +metro-core@0.80.10, metro-core@^0.80.3: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.80.10.tgz#a3a7986ca8b635ada250149efdcd9b69bfefca85" + integrity sha512-nwBB6HbpGlNsZMuzxVqxqGIOsn5F3JKpsp8PziS7Z4mV8a/jA1d44mVOgYmDa2q5WlH5iJfRIIhdz24XRNDlLA== dependencies: + flow-enums-runtime "^0.0.6" lodash.throttle "^4.1.1" - metro-resolver "0.80.9" + metro-resolver "0.80.10" metro-file-map@0.73.10: version "0.73.10" @@ -11071,26 +11066,6 @@ metro-file-map@0.73.10: optionalDependencies: fsevents "^2.3.2" -metro-file-map@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.76.7.tgz#0f041a4f186ac672f0188180310609c8483ffe89" - integrity sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw== - dependencies: - anymatch "^3.0.3" - debug "^2.2.0" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - invariant "^2.2.4" - jest-regex-util "^27.0.6" - jest-util "^27.2.0" - jest-worker "^27.2.0" - micromatch "^4.0.4" - node-abort-controller "^3.1.1" - nullthrows "^1.1.1" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - metro-file-map@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.76.9.tgz#dd3d76ec23fc0ba8cb7b3a3b8075bb09e0b5d378" @@ -11111,14 +11086,15 @@ metro-file-map@0.76.9: optionalDependencies: fsevents "^2.3.2" -metro-file-map@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.80.9.tgz#ed8783f6e35dfc005794344c2a9fcd6e914885aa" - integrity sha512-sBUjVtQMHagItJH/wGU9sn3k2u0nrCl0CdR4SFMO1tksXLKbkigyQx4cbpcyPVOAmGTVuy3jyvBlELaGCAhplQ== +metro-file-map@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.80.10.tgz#7eef9e5ef96a5aad93e4f9680fadb6c1e1ca34bc" + integrity sha512-ytsUq8coneaN7ZCVk1IogojcGhLIbzWyiI2dNmw2nnBgV/0A+M5WaTTgZ6dJEz3dzjObPryDnkqWPvIGLCPtiw== dependencies: anymatch "^3.0.3" debug "^2.2.0" fb-watchman "^2.0.0" + flow-enums-runtime "^0.0.6" graceful-fs "^4.2.4" invariant "^2.2.4" jest-worker "^29.6.3" @@ -11144,17 +11120,6 @@ metro-inspector-proxy@0.73.10: ws "^7.5.1" yargs "^17.5.1" -metro-inspector-proxy@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz#c067df25056e932002a72a4b45cf7b4b749f808e" - integrity sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg== - dependencies: - connect "^3.6.5" - debug "^2.2.0" - node-fetch "^2.2.0" - ws "^7.5.1" - yargs "^17.6.2" - metro-inspector-proxy@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.76.9.tgz#0d333e64a7bc9d156d712265faa7b7ae88c775e8" @@ -11173,13 +11138,6 @@ metro-minify-terser@0.73.10: dependencies: terser "^5.15.0" -metro-minify-terser@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz#aefac8bb8b6b3a0fcb5ea0238623cf3e100893ff" - integrity sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA== - dependencies: - terser "^5.15.0" - metro-minify-terser@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-minify-terser/-/metro-minify-terser-0.76.9.tgz#3f6271da74dd57179852118443b62cc8dc578aab" @@ -11187,11 +11145,12 @@ metro-minify-terser@0.76.9: dependencies: terser "^5.15.0" -metro-minify-terser@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-minify-terser/-/metro-minify-terser-0.80.9.tgz#2b7798cba2bd4bd69cc5ce05a45bf66291542f83" - integrity sha512-FEeCeFbkvvPuhjixZ1FYrXtO0araTpV6UbcnGgDUpH7s7eR5FG/PiJz3TsuuPP/HwCK19cZtQydcA2QrCw446A== +metro-minify-terser@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-minify-terser/-/metro-minify-terser-0.80.10.tgz#21e10cdd52b05cc95c195b8c22bb09afc1b45347" + integrity sha512-Xyv9pEYpOsAerrld7cSLIcnCCpv8ItwysOmTA+AKf1q4KyE9cxrH2O2SA0FzMCkPzwxzBWmXwHUr+A89BpEM6g== dependencies: + flow-enums-runtime "^0.0.6" terser "^5.15.0" metro-minify-uglify@0.73.10: @@ -11201,13 +11160,6 @@ metro-minify-uglify@0.73.10: dependencies: uglify-es "^3.1.9" -metro-minify-uglify@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz#3e0143786718dcaea4e28a724698d4f8ac199a43" - integrity sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw== - dependencies: - uglify-es "^3.1.9" - metro-minify-uglify@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.76.9.tgz#e88c30c27911c053e1ee20e12077f0f4cbb154f8" @@ -11303,51 +11255,6 @@ metro-react-native-babel-preset@0.73.5: "@babel/template" "^7.0.0" react-refresh "^0.4.0" -metro-react-native-babel-preset@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz#dfe15c040d0918147a8b0e9f530d558287acbb54" - integrity sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw== - dependencies: - "@babel/core" "^7.20.0" - "@babel/plugin-proposal-async-generator-functions" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.18.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.0" - "@babel/plugin-proposal-numeric-separator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.20.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.20.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.18.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-syntax-optional-chaining" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.20.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.20.0" - "@babel/plugin-transform-flow-strip-types" "^7.20.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-self" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.5.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - babel-plugin-transform-flow-enums "^0.0.2" - react-refresh "^0.4.0" - metro-react-native-babel-preset@0.76.8: version "0.76.8" resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.8.tgz#7476efae14363cbdfeeec403b4f01d7348e6c048" @@ -11464,17 +11371,6 @@ metro-react-native-babel-transformer@0.73.5: metro-source-map "0.73.5" nullthrows "^1.1.1" -metro-react-native-babel-transformer@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz#ccc7c25b49ee8a1860aafdbf48bfa5441d206f8f" - integrity sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA== - dependencies: - "@babel/core" "^7.20.0" - babel-preset-fbjs "^3.4.0" - hermes-parser "0.12.0" - metro-react-native-babel-preset "0.76.7" - nullthrows "^1.1.1" - metro-react-native-babel-transformer@^0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.9.tgz#464aab85669ed39f7a59f1fd993a05de9543b09e" @@ -11493,20 +11389,17 @@ metro-resolver@0.73.10: dependencies: absolute-path "^0.0.0" -metro-resolver@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.76.7.tgz#f00ebead64e451c060f30926ecbf4f797588df52" - integrity sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA== - -metro-resolver@0.76.9: +metro-resolver@0.76.9, metro-resolver@^0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.76.9.tgz#79c244784b16ca56076bc1fc816d2ba74860e882" integrity sha512-s86ipNRas9vNR5lChzzSheF7HoaQEmzxBLzwFA6/2YcGmUCowcoyPAfs1yPh4cjMw9F1T4KlMLaiwniGE7HCyw== -metro-resolver@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.80.9.tgz#bae9120a0553e0cb59da6429e83a7e97465cc1a8" - integrity sha512-wAPIjkN59BQN6gocVsAvvpZ1+LQkkqUaswlT++cJafE/e54GoVkMNCmrR4BsgQHr9DknZ5Um/nKueeN7kaEz9w== +metro-resolver@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.80.10.tgz#d335e1daed29124d7f96dabe48f9c94a56176bac" + integrity sha512-EYC5CL7f+bSzrqdk1bylKqFNGabfiI5PDctxoPx70jFt89Jz+ThcOscENog8Jb4LEQFG6GkOYlwmPpsi7kx3QA== + dependencies: + flow-enums-runtime "^0.0.6" metro-runtime@0.73.10: version "0.73.10" @@ -11524,14 +11417,6 @@ metro-runtime@0.73.5: "@babel/runtime" "^7.0.0" react-refresh "^0.4.0" -metro-runtime@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.76.7.tgz#4d75f2dbbcd19a4f01e0d89494e140b0ba8247e4" - integrity sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug== - dependencies: - "@babel/runtime" "^7.0.0" - react-refresh "^0.4.0" - metro-runtime@0.76.9, metro-runtime@^0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.76.9.tgz#f8ebe150f8896ce1aef5d7f3a52844f8b4f721fb" @@ -11540,12 +11425,13 @@ metro-runtime@0.76.9, metro-runtime@^0.76.9: "@babel/runtime" "^7.0.0" react-refresh "^0.4.0" -metro-runtime@0.80.9, metro-runtime@^0.80.3: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.80.9.tgz#665312bd4e4d38fea921b3153d6ab47846eb4f08" - integrity sha512-8PTVIgrVcyU+X/rVCy/9yxNlvXsBCk5JwwkbAm/Dm+Abo6NBGtNjWF0M1Xo/NWCb4phamNWcD7cHdR91HhbJvg== +metro-runtime@0.80.10, metro-runtime@^0.80.3: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.80.10.tgz#3fbca798586fa3771018e1d2bd0ef7ac445805ba" + integrity sha512-Xh0N589ZmSIgJYAM+oYwlzTXEHfASZac9TYPCNbvjNTn0EHKqpoJ/+Im5G3MZT4oZzYv4YnvzRtjqS5k0tK94A== dependencies: "@babel/runtime" "^7.0.0" + flow-enums-runtime "^0.0.6" metro-source-map@0.73.10: version "0.73.10" @@ -11575,21 +11461,7 @@ metro-source-map@0.73.5: source-map "^0.5.6" vlq "^1.0.0" -metro-source-map@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.76.7.tgz#9a4aa3a35e1e8ffde9a74cd7ab5f49d9d4a4da14" - integrity sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w== - dependencies: - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - invariant "^2.2.4" - metro-symbolicate "0.76.7" - nullthrows "^1.1.1" - ob1 "0.76.7" - source-map "^0.5.6" - vlq "^1.0.0" - -metro-source-map@0.76.9: +metro-source-map@0.76.9, metro-source-map@^0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.76.9.tgz#0f976ada836717f307427d3830aea52a2ca7ed5f" integrity sha512-q5qsMlu8EFvsT46wUUh+ao+efDsicT30zmaPATNhq+PcTawDbDgnMuUD+FT0bvxxnisU2PWl91RdzKfNc2qPQA== @@ -11603,17 +11475,18 @@ metro-source-map@0.76.9: source-map "^0.5.6" vlq "^1.0.0" -metro-source-map@0.80.9, metro-source-map@^0.80.3: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.80.9.tgz#df8f673137548f37ab9f9dcfa771b354a452cfab" - integrity sha512-RMn+XS4VTJIwMPOUSj61xlxgBvPeY4G6s5uIn6kt6HB6A/k9ekhr65UkkDD7WzHYs3a9o869qU8tvOZvqeQzgw== +metro-source-map@0.80.10, metro-source-map@^0.80.3: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.80.10.tgz#95bc0c1edccd3e0b53af4126deda7fbbe104ef15" + integrity sha512-EyZswqJW8Uukv/HcQr6K19vkMXW1nzHAZPWJSEyJFKIbgp708QfRZ6vnZGmrtFxeJEaFdNup4bGnu8/mIOYlyA== dependencies: "@babel/traverse" "^7.20.0" "@babel/types" "^7.20.0" + flow-enums-runtime "^0.0.6" invariant "^2.2.4" - metro-symbolicate "0.80.9" + metro-symbolicate "0.80.10" nullthrows "^1.1.1" - ob1 "0.80.9" + ob1 "0.80.10" source-map "^0.5.6" vlq "^1.0.0" @@ -11641,18 +11514,6 @@ metro-symbolicate@0.73.5: through2 "^2.0.1" vlq "^1.0.0" -metro-symbolicate@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz#1720e6b4ce5676935d7a8a440f25d3f16638e87a" - integrity sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ== - dependencies: - invariant "^2.2.4" - metro-source-map "0.76.7" - nullthrows "^1.1.1" - source-map "^0.5.6" - through2 "^2.0.1" - vlq "^1.0.0" - metro-symbolicate@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.76.9.tgz#f1627ef6f73bb0c4d48c55684d3c87866a0b0920" @@ -11665,13 +11526,14 @@ metro-symbolicate@0.76.9: through2 "^2.0.1" vlq "^1.0.0" -metro-symbolicate@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.80.9.tgz#8d1d19d26ebb36b9d13dbd29814fdd71d6009db7" - integrity sha512-Ykae12rdqSs98hg41RKEToojuIW85wNdmSe/eHUgMkzbvCFNVgcC0w3dKZEhSsqQOXapXRlLtHkaHLil0UD/EA== +metro-symbolicate@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.80.10.tgz#441121d97408c5a3da25c49c3ce8ae7b034eadf7" + integrity sha512-qAoVUoSxpfZ2DwZV7IdnQGXCSsf2cAUExUcZyuCqGlY5kaWBb0mx2BL/xbMFDJ4wBp3sVvSBPtK/rt4J7a0xBA== dependencies: + flow-enums-runtime "^0.0.6" invariant "^2.2.4" - metro-source-map "0.80.9" + metro-source-map "0.80.10" nullthrows "^1.1.1" source-map "^0.5.6" through2 "^2.0.1" @@ -11688,17 +11550,6 @@ metro-transform-plugins@0.73.10: "@babel/traverse" "^7.20.0" nullthrows "^1.1.1" -metro-transform-plugins@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz#5d5f75371706fbf5166288e43ffd36b5e5bd05bc" - integrity sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg== - dependencies: - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.20.0" - nullthrows "^1.1.1" - metro-transform-plugins@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.76.9.tgz#73e34f2014d3df3c336a882b13e541bceb826d37" @@ -11710,15 +11561,16 @@ metro-transform-plugins@0.76.9: "@babel/traverse" "^7.20.0" nullthrows "^1.1.1" -metro-transform-plugins@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.80.9.tgz#473a2c0a9e48043210547abe61cdeedb77725422" - integrity sha512-UlDk/uc8UdfLNJhPbF3tvwajyuuygBcyp+yBuS/q0z3QSuN/EbLllY3rK8OTD9n4h00qZ/qgxGv/lMFJkwP4vg== +metro-transform-plugins@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.80.10.tgz#df8f44396154ad0bf151533b9bbcdfdf90fccebb" + integrity sha512-leAx9gtA+2MHLsCeWK6XTLBbv2fBnNFu/QiYhWzMq8HsOAP4u1xQAU0tSgPs8+1vYO34Plyn79xTLUtQCRSSUQ== dependencies: "@babel/core" "^7.20.0" "@babel/generator" "^7.20.0" "@babel/template" "^7.0.0" "@babel/traverse" "^7.20.0" + flow-enums-runtime "^0.0.6" nullthrows "^1.1.1" metro-transform-worker@0.73.10: @@ -11740,24 +11592,6 @@ metro-transform-worker@0.73.10: metro-transform-plugins "0.73.10" nullthrows "^1.1.1" -metro-transform-worker@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz#b842d5a542f1806cca401633fc002559b3e3d668" - integrity sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw== - dependencies: - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/parser" "^7.20.0" - "@babel/types" "^7.20.0" - babel-preset-fbjs "^3.4.0" - metro "0.76.7" - metro-babel-transformer "0.76.7" - metro-cache "0.76.7" - metro-cache-key "0.76.7" - metro-source-map "0.76.7" - metro-transform-plugins "0.76.7" - nullthrows "^1.1.1" - metro-transform-worker@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.76.9.tgz#281fad223f0447e1ff9cc44d6f7e33dfab9ab120" @@ -11777,22 +11611,23 @@ metro-transform-worker@0.76.9: metro-transform-plugins "0.76.9" nullthrows "^1.1.1" -metro-transform-worker@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.80.9.tgz#f1d8ef4f77228bb7e1d20d3c06934166e8ee3b28" - integrity sha512-c/IrzMUVnI0hSVVit4TXzt3A1GiUltGVlzCmLJWxNrBGHGrJhvgePj38+GXl1Xf4Fd4vx6qLUkKMQ3ux73bFLQ== +metro-transform-worker@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.80.10.tgz#aa083673653d5555b2eb34fec316759e57aa97ab" + integrity sha512-zNfNLD8Rz99U+JdOTqtF2o7iTjcDMMYdVS90z6+81Tzd2D0lDWVpls7R1hadS6xwM+ymgXFQTjM6V6wFoZaC0g== dependencies: "@babel/core" "^7.20.0" "@babel/generator" "^7.20.0" "@babel/parser" "^7.20.0" "@babel/types" "^7.20.0" - metro "0.80.9" - metro-babel-transformer "0.80.9" - metro-cache "0.80.9" - metro-cache-key "0.80.9" - metro-minify-terser "0.80.9" - metro-source-map "0.80.9" - metro-transform-plugins "0.80.9" + flow-enums-runtime "^0.0.6" + metro "0.80.10" + metro-babel-transformer "0.80.10" + metro-cache "0.80.10" + metro-cache-key "0.80.10" + metro-minify-terser "0.80.10" + metro-source-map "0.80.10" + metro-transform-plugins "0.80.10" nullthrows "^1.1.1" metro@0.73.10: @@ -11852,61 +11687,7 @@ metro@0.73.10: ws "^7.5.1" yargs "^17.5.1" -metro@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.76.7.tgz#4885917ad28738c7d1e556630e0155f687336230" - integrity sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/core" "^7.20.0" - "@babel/generator" "^7.20.0" - "@babel/parser" "^7.20.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.20.0" - "@babel/types" "^7.20.0" - accepts "^1.3.7" - async "^3.2.2" - chalk "^4.0.0" - ci-info "^2.0.0" - connect "^3.6.5" - debug "^2.2.0" - denodeify "^1.2.1" - error-stack-parser "^2.0.6" - graceful-fs "^4.2.4" - hermes-parser "0.12.0" - image-size "^1.0.2" - invariant "^2.2.4" - jest-worker "^27.2.0" - jsc-safe-url "^0.2.2" - lodash.throttle "^4.1.1" - metro-babel-transformer "0.76.7" - metro-cache "0.76.7" - metro-cache-key "0.76.7" - metro-config "0.76.7" - metro-core "0.76.7" - metro-file-map "0.76.7" - metro-inspector-proxy "0.76.7" - metro-minify-terser "0.76.7" - metro-minify-uglify "0.76.7" - metro-react-native-babel-preset "0.76.7" - metro-resolver "0.76.7" - metro-runtime "0.76.7" - metro-source-map "0.76.7" - metro-symbolicate "0.76.7" - metro-transform-plugins "0.76.7" - metro-transform-worker "0.76.7" - mime-types "^2.1.27" - node-fetch "^2.2.0" - nullthrows "^1.1.1" - rimraf "^3.0.2" - serialize-error "^2.1.0" - source-map "^0.5.6" - strip-ansi "^6.0.0" - throat "^5.0.0" - ws "^7.5.1" - yargs "^17.6.2" - -metro@0.76.9: +metro@0.76.9, metro@^0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/metro/-/metro-0.76.9.tgz#605fddf1a54d27762ddba2f636420ae2408862df" integrity sha512-gcjcfs0l5qIPg0lc5P7pj0x7vPJ97tan+OnEjiYLbKjR1D7Oa78CE93YUPyymUPH6q7VzlzMm1UjT35waEkZUw== @@ -11959,10 +11740,10 @@ metro@0.76.9: ws "^7.5.1" yargs "^17.6.2" -metro@0.80.9, metro@^0.80.3: - version "0.80.9" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.80.9.tgz#de3c2011df62036520d51d040d2dde0d015aecb6" - integrity sha512-Bc57Xf3GO2Xe4UWQsBj/oW6YfLPABEu8jfDVDiNmJvoQW4CO34oDPuYKe4KlXzXhcuNsqOtSxpbjCRRVjhhREg== +metro@0.80.10, metro@^0.80.3: + version "0.80.10" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.80.10.tgz#522f1ad7435632f0d9eac67f732083cf45205fbc" + integrity sha512-FDPi0X7wpafmDREXe1lgg3WzETxtXh6Kpq8+IwsG35R2tMyp2kFIqDdshdohuvDt1J/qDARcEPq7V/jElTb1kA== dependencies: "@babel/code-frame" "^7.0.0" "@babel/core" "^7.20.0" @@ -11978,40 +11759,40 @@ metro@0.80.9, metro@^0.80.3: debug "^2.2.0" denodeify "^1.2.1" error-stack-parser "^2.0.6" + flow-enums-runtime "^0.0.6" graceful-fs "^4.2.4" - hermes-parser "0.20.1" + hermes-parser "0.23.0" image-size "^1.0.2" invariant "^2.2.4" jest-worker "^29.6.3" jsc-safe-url "^0.2.2" lodash.throttle "^4.1.1" - metro-babel-transformer "0.80.9" - metro-cache "0.80.9" - metro-cache-key "0.80.9" - metro-config "0.80.9" - metro-core "0.80.9" - metro-file-map "0.80.9" - metro-resolver "0.80.9" - metro-runtime "0.80.9" - metro-source-map "0.80.9" - metro-symbolicate "0.80.9" - metro-transform-plugins "0.80.9" - metro-transform-worker "0.80.9" + metro-babel-transformer "0.80.10" + metro-cache "0.80.10" + metro-cache-key "0.80.10" + metro-config "0.80.10" + metro-core "0.80.10" + metro-file-map "0.80.10" + metro-resolver "0.80.10" + metro-runtime "0.80.10" + metro-source-map "0.80.10" + metro-symbolicate "0.80.10" + metro-transform-plugins "0.80.10" + metro-transform-worker "0.80.10" mime-types "^2.1.27" node-fetch "^2.2.0" nullthrows "^1.1.1" - rimraf "^3.0.2" serialize-error "^2.1.0" source-map "^0.5.6" strip-ansi "^6.0.0" throat "^5.0.0" - ws "^7.5.1" + ws "^7.5.10" yargs "^17.6.2" micromatch@^4.0.0, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@~4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" - integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: braces "^3.0.3" picomatch "^2.3.1" @@ -12075,7 +11856,7 @@ minimatch@3.0.5: dependencies: brace-expansion "^1.1.7" -"minimatch@6 || 7 || 8 || 9", minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: +"minimatch@6 || 7 || 8 || 9", minimatch@^9.0.0, minimatch@^9.0.3, minimatch@^9.0.4: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== @@ -12193,7 +11974,7 @@ minipass-sized@^1.0.3: dependencies: minipass "^3.0.0" -minipass@6.0.2, minipass@^4.2.4, "minipass@^5.0.0 || ^6.0.2", "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": +minipass@6.0.2, minipass@^4.2.4, "minipass@^5.0.0 || ^6.0.2", minipass@^7.1.2: version "6.0.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.2.tgz#542844b6c4ce95b202c0995b0a471f1229de4c81" integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== @@ -12329,11 +12110,11 @@ neo-async@^2.5.0, neo-async@^2.6.2: integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== "next@>= 13.5.0 < 15.0.0": - version "14.2.5" - resolved "https://registry.yarnpkg.com/next/-/next-14.2.5.tgz#afe4022bb0b752962e2205836587a289270efbea" - integrity sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA== + version "14.2.10" + resolved "https://registry.yarnpkg.com/next/-/next-14.2.10.tgz#331981a4fecb1ae8af1817d4db98fc9687ee1cb6" + integrity sha512-sDDExXnh33cY3RkS9JuFEKaS4HmlWmDKP1VJioucCG6z5KuA008DPsDZOzi8UfqEk3Ii+2NCQSJrfbEWtZZfww== dependencies: - "@next/env" "14.2.5" + "@next/env" "14.2.10" "@swc/helpers" "0.5.5" busboy "1.6.0" caniuse-lite "^1.0.30001579" @@ -12341,15 +12122,15 @@ neo-async@^2.5.0, neo-async@^2.6.2: postcss "8.4.31" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-darwin-arm64" "14.2.5" - "@next/swc-darwin-x64" "14.2.5" - "@next/swc-linux-arm64-gnu" "14.2.5" - "@next/swc-linux-arm64-musl" "14.2.5" - "@next/swc-linux-x64-gnu" "14.2.5" - "@next/swc-linux-x64-musl" "14.2.5" - "@next/swc-win32-arm64-msvc" "14.2.5" - "@next/swc-win32-ia32-msvc" "14.2.5" - "@next/swc-win32-x64-msvc" "14.2.5" + "@next/swc-darwin-arm64" "14.2.10" + "@next/swc-darwin-x64" "14.2.10" + "@next/swc-linux-arm64-gnu" "14.2.10" + "@next/swc-linux-arm64-musl" "14.2.10" + "@next/swc-linux-x64-gnu" "14.2.10" + "@next/swc-linux-x64-musl" "14.2.10" + "@next/swc-win32-arm64-msvc" "14.2.10" + "@next/swc-win32-ia32-msvc" "14.2.10" + "@next/swc-win32-x64-msvc" "14.2.10" nice-try@^1.0.4: version "1.0.5" @@ -12362,9 +12143,9 @@ nocache@^3.0.1: integrity sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw== node-abi@^3.3.0: - version "3.65.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.65.0.tgz#ca92d559388e1e9cab1680a18c1a18757cdac9d3" - integrity sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA== + version "3.67.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.67.0.tgz#1d159907f18d18e18809dbbb5df47ed2426a08df" + integrity sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw== dependencies: semver "^7.3.5" @@ -12731,20 +12512,17 @@ ob1@0.73.5: resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.73.5.tgz#b80dc4a6f787044e3d8afde3c2d034ae23d05a86" integrity sha512-MxQH/rCq9/COvgTQbjCldArmesGEidZVVQIn4vDUJvJJ8uMphXOTCBsgWTief2ugvb0WUimIaslKSA+qryFjjQ== -ob1@0.76.7: - version "0.76.7" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.76.7.tgz#95b68fadafd47e7a6a0ad64cf80f3140dd6d1124" - integrity sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ== - ob1@0.76.9: version "0.76.9" resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.76.9.tgz#a493e4b83a0fb39200de639804b5d06eed5599dc" integrity sha512-g0I/OLnSxf6OrN3QjSew3bTDJCdbZoWxnh8adh1z36alwCuGF1dgDeRA25bTYSakrG5WULSaWJPOdgnf1O/oQw== -ob1@0.80.9: - version "0.80.9" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.80.9.tgz#4ae3edd807536097674ff943509089f5d4e0649f" - integrity sha512-v9yOxowkZbxWhKOaaTyLjIm1aLy4ebMNcSn4NYJKOAI/Qv+SkfEfszpLr2GIxsccmb2Y2HA9qtsqiIJ80ucpVA== +ob1@0.80.10: + version "0.80.10" + resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.80.10.tgz#30dc7e4619cf591d46d7e16db5d4aed3e2674172" + integrity sha512-dJHyB0S6JkMorUSfSGcYGkkg9kmq3qDUu3ygZUKIfkr47XOPuG35r2Sk6tbwtHXbdKIXmcMvM8DF2CwgdyaHfQ== + dependencies: + flow-enums-runtime "^0.0.6" object-assign@^4.1.1: version "4.1.1" @@ -13023,6 +12801,11 @@ p-waterfall@2.1.1: dependencies: p-reduce "^2.0.0" +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + pacote@^15.0.0, pacote@^15.0.8, pacote@^15.2.0: version "15.2.0" resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.2.0.tgz#0f0dfcc3e60c7b39121b2ac612bf8596e95344d3" @@ -13172,7 +12955,7 @@ path-platform@~0.11.15: resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" integrity sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg== -path-scurry@1.10.0, path-scurry@^1.10.1, path-scurry@^1.6.1: +path-scurry@1.10.0, path-scurry@^1.11.1, path-scurry@^1.6.1: version "1.10.0" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.0.tgz#0ffbd4c1f7de9600f98a1405507d9f9acb438ab3" integrity sha512-tZFEaRQbMLjwrsmidsGJ6wDMv0iazJWk6SfIKnY4Xru8auXgmJkOBa5DUbYFcFD2Rzk2+KDlIiF0GVXNCbgC7g== @@ -13278,9 +13061,9 @@ possible-typed-array-names@^1.0.0: integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== postcss-selector-parser@^6.0.10: - version "6.1.1" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz#5be94b277b8955904476a2400260002ce6c56e38" - integrity sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg== + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -13422,7 +13205,7 @@ promzard@^1.0.0: dependencies: read "^3.0.1" -prop-types@*, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -13531,7 +13314,7 @@ react-devtools-core@^4.26.1, react-devtools-core@^4.27.2: shell-quote "^1.6.1" ws "^7" -react-devtools-core@^5.0.0: +react-devtools-core@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-5.3.1.tgz#d57f5b8f74f16e622bd6a7bc270161e4ba162666" integrity sha512-7FSb9meX0btdBQLwdFOwt6bGqvRPabmVMMslv8fgoSPqXyuGpgQe36kx8gR86XPw7aV1yVouTp6fyZ0EH+NfUw== @@ -13638,33 +13421,34 @@ react-native@0.71.0: whatwg-fetch "^3.0.0" ws "^6.2.2" -react-native@0.72.3: - version "0.72.3" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.72.3.tgz#f8d85ec81c9f3592d091ec8e9ac1694956a72765" - integrity sha512-QqISi+JVmCssNP2FlQ4MWhlc4O/I00MRE1/GClvyZ8h/6kdsyk/sOirkYdZqX3+DrJfI3q+OnyMnsyaXIQ/5tQ== +react-native@0.72.15: + version "0.72.15" + resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.72.15.tgz#9b74b0c39ec42befb70d494b535f863c4229ef55" + integrity sha512-UDxOZwCxhwb0dGuvcB/04uWzhDJ8etqW3fMOq6bv35WwEXMgKXXqZpshhMo64UVWm/m2ZmM32ckn5sf1EIqD9Q== dependencies: "@jest/create-cache-key-function" "^29.2.1" - "@react-native-community/cli" "11.3.5" - "@react-native-community/cli-platform-android" "11.3.5" - "@react-native-community/cli-platform-ios" "11.3.5" + "@react-native-community/cli" "^11.4.1" + "@react-native-community/cli-platform-android" "^11.4.1" + "@react-native-community/cli-platform-ios" "^11.4.1" "@react-native/assets-registry" "^0.72.0" - "@react-native/codegen" "^0.72.6" + "@react-native/codegen" "^0.72.8" "@react-native/gradle-plugin" "^0.72.11" "@react-native/js-polyfills" "^0.72.1" "@react-native/normalize-colors" "^0.72.0" - "@react-native/virtualized-lists" "^0.72.6" + "@react-native/virtualized-lists" "^0.72.8" abort-controller "^3.0.0" anser "^1.4.9" + ansi-regex "^5.0.0" base64-js "^1.1.2" - deprecated-react-native-prop-types "4.1.0" + deprecated-react-native-prop-types "^4.2.3" event-target-shim "^5.0.1" flow-enums-runtime "^0.0.5" invariant "^2.2.4" jest-environment-node "^29.2.1" jsc-android "^250231.0.0" memoize-one "^5.0.0" - metro-runtime "0.76.7" - metro-source-map "0.76.7" + metro-runtime "^0.76.9" + metro-source-map "^0.76.9" mkdirp "^0.5.1" nullthrows "^1.1.1" pretty-format "^26.5.2" @@ -13681,21 +13465,21 @@ react-native@0.72.3: yargs "^17.6.2" react-native@>=0.70: - version "0.74.4" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.74.4.tgz#932901ac635b2f135a5e4e210bc52f3f1153b8d0" - integrity sha512-Cox7h0UkFPY+79DsInn2BAhnmGiqKBHKoYHoPAPW8oQCPyna8jvS0hfUmHBWm/MOHSXi4NYPKd5plpD50B3B2Q== + version "0.75.2" + resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.75.2.tgz#12d7e3e63c8ab93dcab7a6d4c4c9f4ad199141d4" + integrity sha512-pP+Yswd/EurzAlKizytRrid9LJaPJzuNldc+o5t01md2VLHym8V7FWH2z9omFKtFTer8ERg0fAhG1fpd0Qq6bQ== dependencies: "@jest/create-cache-key-function" "^29.6.3" - "@react-native-community/cli" "13.6.9" - "@react-native-community/cli-platform-android" "13.6.9" - "@react-native-community/cli-platform-ios" "13.6.9" - "@react-native/assets-registry" "0.74.86" - "@react-native/codegen" "0.74.86" - "@react-native/community-cli-plugin" "0.74.86" - "@react-native/gradle-plugin" "0.74.86" - "@react-native/js-polyfills" "0.74.86" - "@react-native/normalize-colors" "0.74.86" - "@react-native/virtualized-lists" "0.74.86" + "@react-native-community/cli" "14.0.0" + "@react-native-community/cli-platform-android" "14.0.0" + "@react-native-community/cli-platform-ios" "14.0.0" + "@react-native/assets-registry" "0.75.2" + "@react-native/codegen" "0.75.2" + "@react-native/community-cli-plugin" "0.75.2" + "@react-native/gradle-plugin" "0.75.2" + "@react-native/js-polyfills" "0.75.2" + "@react-native/normalize-colors" "0.75.2" + "@react-native/virtualized-lists" "0.75.2" abort-controller "^3.0.0" anser "^1.4.9" ansi-regex "^5.0.0" @@ -13703,6 +13487,7 @@ react-native@>=0.70: chalk "^4.0.0" event-target-shim "^5.0.1" flow-enums-runtime "^0.0.6" + glob "^7.1.1" invariant "^2.2.4" jest-environment-node "^29.6.3" jsc-android "^250231.0.0" @@ -13713,11 +13498,11 @@ react-native@>=0.70: nullthrows "^1.1.1" pretty-format "^26.5.2" promise "^8.3.0" - react-devtools-core "^5.0.0" + react-devtools-core "^5.3.1" react-refresh "^0.14.0" - react-shallow-renderer "^16.15.0" regenerator-runtime "^0.13.2" scheduler "0.24.0-canary-efb381bbf-20230505" + semver "^7.1.3" stacktrace-parser "^0.1.10" whatwg-fetch "^3.0.0" ws "^6.2.2" @@ -14095,28 +13880,28 @@ rimraf@~2.6.2: glob "^7.1.3" rollup@^4.9.6: - version "4.19.2" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.19.2.tgz#4985cd2028965157e8d674a70e49f33aca9038eb" - integrity sha512-6/jgnN1svF9PjNYJ4ya3l+cqutg49vOZ4rVgsDKxdl+5gpGPnByFXWGyfH9YGx9i3nfBwSu1Iyu6vGwFFA0BdQ== + version "4.22.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f" + integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.19.2" - "@rollup/rollup-android-arm64" "4.19.2" - "@rollup/rollup-darwin-arm64" "4.19.2" - "@rollup/rollup-darwin-x64" "4.19.2" - "@rollup/rollup-linux-arm-gnueabihf" "4.19.2" - "@rollup/rollup-linux-arm-musleabihf" "4.19.2" - "@rollup/rollup-linux-arm64-gnu" "4.19.2" - "@rollup/rollup-linux-arm64-musl" "4.19.2" - "@rollup/rollup-linux-powerpc64le-gnu" "4.19.2" - "@rollup/rollup-linux-riscv64-gnu" "4.19.2" - "@rollup/rollup-linux-s390x-gnu" "4.19.2" - "@rollup/rollup-linux-x64-gnu" "4.19.2" - "@rollup/rollup-linux-x64-musl" "4.19.2" - "@rollup/rollup-win32-arm64-msvc" "4.19.2" - "@rollup/rollup-win32-ia32-msvc" "4.19.2" - "@rollup/rollup-win32-x64-msvc" "4.19.2" + "@rollup/rollup-android-arm-eabi" "4.22.4" + "@rollup/rollup-android-arm64" "4.22.4" + "@rollup/rollup-darwin-arm64" "4.22.4" + "@rollup/rollup-darwin-x64" "4.22.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.22.4" + "@rollup/rollup-linux-arm-musleabihf" "4.22.4" + "@rollup/rollup-linux-arm64-gnu" "4.22.4" + "@rollup/rollup-linux-arm64-musl" "4.22.4" + "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4" + "@rollup/rollup-linux-riscv64-gnu" "4.22.4" + "@rollup/rollup-linux-s390x-gnu" "4.22.4" + "@rollup/rollup-linux-x64-gnu" "4.22.4" + "@rollup/rollup-linux-x64-musl" "4.22.4" + "@rollup/rollup-win32-arm64-msvc" "4.22.4" + "@rollup/rollup-win32-ia32-msvc" "4.22.4" + "@rollup/rollup-win32-x64-msvc" "4.22.4" fsevents "~2.3.2" run-async@^2.4.0: @@ -14273,15 +14058,15 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: +semver@^7.0.0, semver@^7.1.1, semver@^7.1.3, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -14310,14 +14095,14 @@ serialize-javascript@^6.0.1: randombytes "^2.1.0" serve-static@^1.13.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" set-blocking@^2.0.0: version "2.0.0" @@ -14626,9 +14411,9 @@ spdx-expression-parse@^4.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.18" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz#22aa922dcf2f2885a6494a261f2d8b75345d0326" - integrity sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ== + version "3.0.20" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz#e44ed19ed318dd1e5888f93325cee800f0f51b89" + integrity sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw== split2@^3.2.2: version "3.2.2" @@ -15047,9 +14832,9 @@ terser-webpack-plugin@^5.3.10, terser-webpack-plugin@^5.3.6: terser "^5.26.0" terser@^5.15.0, terser@^5.26.0: - version "5.31.3" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.3.tgz#b24b7beb46062f4653f049eea4f0cd165d0f0c38" - integrity sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA== + version "5.31.6" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.6.tgz#c63858a0f0703988d0266a82fcbf2d7ba76422b1" + integrity sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -15182,19 +14967,19 @@ ts-api-utils@^1.0.1: integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== ts-jest@^29.1.1: - version "29.2.4" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.4.tgz#38ccf487407d7a63054a72689f6f99b075e296e5" - integrity sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw== + version "29.2.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.5.tgz#591a3c108e1f5ebd013d3152142cb5472b399d63" + integrity sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA== dependencies: - bs-logger "0.x" + bs-logger "^0.2.6" ejs "^3.1.10" - fast-json-stable-stringify "2.x" + fast-json-stable-stringify "^2.1.0" jest-util "^29.0.0" json5 "^2.2.3" - lodash.memoize "4.x" - make-error "1.x" - semver "^7.5.3" - yargs-parser "^21.0.1" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.6.3" + yargs-parser "^21.1.1" ts-loader@^9.4.3: version "9.5.1" @@ -15227,9 +15012,9 @@ tsconfig-paths@^4.1.2: strip-bom "^3.0.0" "tslib@1 || 2", tslib@^2.0.1, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" - integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== tslib@^1.11.1, tslib@^1.8.1: version "1.14.1" @@ -15459,9 +15244,9 @@ uglify-es@^3.1.9: source-map "~0.6.1" uglify-js@^3.1.4: - version "3.19.1" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.1.tgz#2d5df6a0872c43da43187968308d7741d44b8056" - integrity sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A== + version "3.19.2" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.2.tgz#319ae26a5fbd18d03c7dc02496cfa1d6f1cd4307" + integrity sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ== ulid@^2.3.0: version "2.3.0" @@ -15483,10 +15268,10 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -undici-types@~6.11.1: - version "6.11.1" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.11.1.tgz#432ea6e8efd54a48569705a699e62d8f4981b197" - integrity sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" @@ -15744,9 +15529,9 @@ warning@^4.0.2, warning@^4.0.3: loose-envify "^1.0.0" watchpack@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.1.tgz#29308f2cac150fa8e4c92f90e0ec954a9fed7fff" - integrity sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg== + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -15835,11 +15620,10 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5, webpack@^5.75.0, webpack@^5.88.0: - version "5.93.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" - integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== + version "5.94.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" + integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== dependencies: - "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.5" "@webassemblyjs/ast" "^1.12.1" "@webassemblyjs/wasm-edit" "^1.12.1" @@ -15848,7 +15632,7 @@ webpack@^5, webpack@^5.75.0, webpack@^5.88.0: acorn-import-attributes "^1.9.5" browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.0" + enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" @@ -16090,14 +15874,14 @@ write-pkg@4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@^6.2.2: +ws@^6.2.2, ws@^6.2.3: version "6.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee" integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== dependencies: async-limiter "~1.0.0" -ws@^7, ws@^7.3.1, ws@^7.5.1: +ws@^7, ws@^7.3.1, ws@^7.5.1, ws@^7.5.10: version "7.5.10" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== @@ -16173,22 +15957,17 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.2.1: +yaml@^2.2.1, yaml@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== -yaml@~2.4.2: - version "2.4.5" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e" - integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg== - yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@21.1.1, yargs-parser@^21.0.1, yargs-parser@^21.1.1: +yargs-parser@21.1.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==