From 9cc4d7c1db08614728ace656cffd5c0e3ccaeb20 Mon Sep 17 00:00:00 2001 From: Riley Nowak Date: Wed, 11 Sep 2024 14:22:00 -0300 Subject: [PATCH] Add specific error for invalid_target error --- .changeset/mighty-mice-design.md | 5 ++++ .../src/private/node/session/exchange.test.ts | 28 +++++++++++++++++-- .../src/private/node/session/exchange.ts | 15 ++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 .changeset/mighty-mice-design.md diff --git a/.changeset/mighty-mice-design.md b/.changeset/mighty-mice-design.md new file mode 100644 index 0000000000..6fa2a9138b --- /dev/null +++ b/.changeset/mighty-mice-design.md @@ -0,0 +1,5 @@ +--- +'@shopify/cli-kit': minor +--- + +Messaging improved for authorization errors related to invalid targets when using `theme` command diff --git a/packages/cli-kit/src/private/node/session/exchange.test.ts b/packages/cli-kit/src/private/node/session/exchange.test.ts index 750f96b417..67f2ec1de1 100644 --- a/packages/cli-kit/src/private/node/session/exchange.test.ts +++ b/packages/cli-kit/src/private/node/session/exchange.test.ts @@ -165,7 +165,7 @@ describe('exchange identity token for application tokens', () => { }) describe('refresh access tokens', () => { - test('throws a InvalidGrantError when Identity returns invalid_grant', async () => { + test('throws an InvalidGrantError when Identity returns invalid_grant', async () => { // Given const error = {error: 'invalid_grant'} const response = new Response(JSON.stringify(error), {status: 400}) @@ -178,7 +178,7 @@ describe('refresh access tokens', () => { return expect(got).rejects.toThrowError(InvalidGrantError) }) - test('throws a InvalidRequestError when Identity returns invalid_request', async () => { + test('throws an InvalidRequestError when Identity returns invalid_request', async () => { // Given const error = {error: 'invalid_request'} const response = new Response(JSON.stringify(error), {status: 400}) @@ -191,6 +191,30 @@ describe('refresh access tokens', () => { return expect(got).rejects.toThrowError(InvalidRequestError) }) + test('throws an InvalidTargetError when Identity returns invalid_target', async () => { + // Given + const error = {error: 'invalid_target'} + const response = new Response(JSON.stringify(error), {status: 400}) + vi.mocked(shopifyFetch).mockResolvedValue(response) + + // When + const got = () => refreshAccessToken(identityToken) + + // Then + await expect(got).rejects.toThrowError( + 'You are not authorized to use the CLI to develop in the provided store.' + + '\n\n' + + "You can't use Shopify CLI with development stores if you only have Partner " + + 'staff member access. If you want to use Shopify CLI to work on a development store, then ' + + 'you should be the store owner or create a staff account on the store.' + + '\n\n' + + "If you're the store owner, then you need to log in to the store directly using the " + + 'store URL at least once before you log in using Shopify CLI.' + + 'Logging in to the Shopify admin directly connects the development ' + + 'store with your Shopify login.', + ) + }) + test('throws an AbortError when Identity returns another error', async () => { // Given const error = {error: 'another'} diff --git a/packages/cli-kit/src/private/node/session/exchange.ts b/packages/cli-kit/src/private/node/session/exchange.ts index ddc229cf1c..d0ba6d4c66 100644 --- a/packages/cli-kit/src/private/node/session/exchange.ts +++ b/packages/cli-kit/src/private/node/session/exchange.ts @@ -11,6 +11,7 @@ import * as jose from 'jose' export class InvalidGrantError extends ExtendableError {} export class InvalidRequestError extends ExtendableError {} +class InvalidTargetError extends AbortError {} export interface ExchangeScopes { admin: string[] @@ -169,6 +170,17 @@ interface TokenRequestResult { } function tokenRequestErrorHandler(error: string) { + const invalidTargetErrorMessage = + 'You are not authorized to use the CLI to develop in the provided store.' + + '\n\n' + + "You can't use Shopify CLI with development stores if you only have Partner " + + 'staff member access. If you want to use Shopify CLI to work on a development store, then ' + + 'you should be the store owner or create a staff account on the store.' + + '\n\n' + + "If you're the store owner, then you need to log in to the store directly using the " + + 'store URL at least once before you log in using Shopify CLI.' + + 'Logging in to the Shopify admin directly connects the development ' + + 'store with your Shopify login.' if (error === 'invalid_grant') { // There's an scenario when Identity returns "invalid_grant" when trying to refresh the token // using a valid refresh token. When that happens, we take the user through the authentication flow. @@ -179,6 +191,9 @@ function tokenRequestErrorHandler(error: string) { // This means the token is invalid. We clear the session and throw an error to let the caller know. return new InvalidRequestError() } + if (error === 'invalid_target') { + return new InvalidTargetError(invalidTargetErrorMessage) + } // eslint-disable-next-line @shopify/cli/no-error-factory-functions return new AbortError(error) }