Skip to content

Commit 8a9c5a1

Browse files
committed
Fix App Management API app-not-found error message (shop/issues-develop#226)
When `shopify app config link --client-id=<id>` is invoked against a Dev Dashboard app, `AppManagementClient.appFromIdentifiers` would unconditionally destructure `app.activeRelease.version`, throwing a TypeError when the GraphQL `appByKey` query returned `null` for a non-existent client ID. Return undefined in that case so the caller in `appFromIdentifiers` (services/context.ts) can render the friendly "No app with client ID ... found" abort error, matching PartnersClient behaviour.
1 parent de64e8f commit 8a9c5a1

3 files changed

Lines changed: 64 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/app': patch
3+
---
4+
5+
Display a friendly error message instead of a stack trace when running `shopify app config link --client-id=<id>` against a Dev Dashboard app and the client ID does not exist.

packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,64 @@ describe('AppManagementClient', () => {
13881388
expect(client.bundleFormat).toBe('br')
13891389
})
13901390
})
1391+
1392+
describe('appFromIdentifiers', () => {
1393+
test('returns undefined when the app is not found', async () => {
1394+
// Given
1395+
const client = AppManagementClient.getInstance()
1396+
client.token = () => Promise.resolve('token')
1397+
vi.mocked(appManagementRequestDoc).mockResolvedValueOnce({app: null})
1398+
1399+
// When
1400+
const got = await client.appFromIdentifiers('non-existent-api-key')
1401+
1402+
// Then
1403+
expect(got).toBeUndefined()
1404+
})
1405+
1406+
test('returns the app when the app is found', async () => {
1407+
// Given
1408+
const client = AppManagementClient.getInstance()
1409+
client.token = () => Promise.resolve('token')
1410+
const apiKey = 'existing-api-key'
1411+
const mockedResponse = {
1412+
app: {
1413+
id: 'gid://shopify/App/1',
1414+
key: apiKey,
1415+
organizationId: 'gid://shopify/Organization/2',
1416+
activeRoot: {
1417+
grantedShopifyApprovalScopes: ['read_products'],
1418+
clientCredentials: {secrets: [{key: 'secret-1'}]},
1419+
},
1420+
activeRelease: {
1421+
id: 'gid://shopify/Release/1',
1422+
version: {
1423+
name: 'My App',
1424+
appModules: [],
1425+
},
1426+
},
1427+
},
1428+
}
1429+
vi.mocked(appManagementRequestDoc).mockResolvedValueOnce(mockedResponse)
1430+
1431+
// When
1432+
const got = await client.appFromIdentifiers(apiKey)
1433+
1434+
// Then
1435+
expect(got).toEqual({
1436+
id: 'gid://shopify/App/1',
1437+
title: 'My App',
1438+
apiKey,
1439+
apiSecretKeys: [{secret: 'secret-1'}],
1440+
organizationId: '2',
1441+
grantedScopes: ['read_products'],
1442+
applicationUrl: undefined,
1443+
embedded: undefined,
1444+
flags: [],
1445+
developerPlatformClient: client,
1446+
})
1447+
})
1448+
})
13911449
})
13921450

13931451
describe('ensureUserAccessToStore', () => {

packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ export class AppManagementClient implements DeveloperPlatformClient {
356356

357357
async appFromIdentifiers(apiKey: string): Promise<OrganizationApp | undefined> {
358358
const {app} = await this.activeAppVersionRawResult(apiKey)
359+
if (!app) return undefined
359360
const {name, appModules} = app.activeRelease.version
360361
const appHomeModule = appModules.find((mod) => mod.specification.externalIdentifier === 'app_home')
361362
const apiSecretKeys = app.activeRoot.clientCredentials.secrets.map((secret) => ({secret: secret.key}))

0 commit comments

Comments
 (0)