Skip to content

Commit 59a45b9

Browse files
committed
Filter explicit store lookups to active stores
1 parent 7078668 commit 59a45b9

2 files changed

Lines changed: 135 additions & 4 deletions

File tree

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

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import {
1919
} from '../../models/app/app.test-data.js'
2020
import {ExtensionInstance} from '../../models/extensions/extension-instance.js'
2121
import {ListApps} from '../../api/graphql/app-management/generated/apps.js'
22+
import {
23+
FetchStoreByDomain,
24+
FetchStoreByDomainQuery,
25+
} from '../../api/graphql/business-platform-organizations/generated/fetch_store_by_domain.js'
2226
import {
2327
ListAppDevStores,
2428
ListAppDevStoresQuery,
@@ -1452,6 +1456,133 @@ describe('AppManagementClient', () => {
14521456
})
14531457
})
14541458

1459+
describe('storeByDomain', () => {
1460+
test('queries Business Platform with STORE_STATUS=ACTIVE for each requested store type', async () => {
1461+
// Given
1462+
const orgGid = 'gid://shopify/Organization/123'
1463+
const shopDomain = 'my-production-store.myshopify.com'
1464+
const token = 'business-platform-token'
1465+
const emptyResponse: FetchStoreByDomainQuery = {
1466+
organization: {
1467+
id: orgGid,
1468+
name: 'Org 123',
1469+
accessibleShops: {edges: []},
1470+
currentUser: {organizationPermissions: []},
1471+
},
1472+
}
1473+
const productionResponse: FetchStoreByDomainQuery = {
1474+
organization: {
1475+
id: orgGid,
1476+
name: 'Org 123',
1477+
accessibleShops: {
1478+
edges: [
1479+
{
1480+
node: {
1481+
id: 'gid://BusinessPlatform/Shop/2',
1482+
externalId: encodedGidFromShopId('2'),
1483+
name: 'My Production Store',
1484+
storeType: 'PRODUCTION',
1485+
primaryDomain: shopDomain,
1486+
shortName: 'my-production-store',
1487+
url: `https://${shopDomain}`,
1488+
},
1489+
},
1490+
],
1491+
},
1492+
currentUser: {organizationPermissions: ['ondemand_access_to_stores']},
1493+
},
1494+
}
1495+
vi.mocked(businessPlatformOrganizationsRequestDoc)
1496+
.mockResolvedValueOnce(emptyResponse)
1497+
.mockResolvedValueOnce(productionResponse)
1498+
1499+
const client = AppManagementClient.getInstance()
1500+
client.businessPlatformToken = () => Promise.resolve(token)
1501+
1502+
// When
1503+
const result = await client.storeByDomain(orgGid, shopDomain, ['APP_DEVELOPMENT', 'PRODUCTION'])
1504+
1505+
// Then
1506+
expect(vi.mocked(businessPlatformOrganizationsRequestDoc)).toHaveBeenNthCalledWith(1, {
1507+
query: FetchStoreByDomain,
1508+
token,
1509+
organizationId: '123',
1510+
variables: {
1511+
domain: shopDomain,
1512+
filters: [
1513+
{field: 'STORE_TYPE', operator: 'EQUALS', value: 'app_development'},
1514+
{field: 'STORE_STATUS', operator: 'EQUALS', value: 'ACTIVE'},
1515+
],
1516+
},
1517+
unauthorizedHandler: {
1518+
type: 'token_refresh',
1519+
handler: expect.any(Function),
1520+
},
1521+
})
1522+
expect(vi.mocked(businessPlatformOrganizationsRequestDoc)).toHaveBeenNthCalledWith(2, {
1523+
query: FetchStoreByDomain,
1524+
token,
1525+
organizationId: '123',
1526+
variables: {
1527+
domain: shopDomain,
1528+
filters: [
1529+
{field: 'STORE_TYPE', operator: 'EQUALS', value: 'production'},
1530+
{field: 'STORE_STATUS', operator: 'EQUALS', value: 'ACTIVE'},
1531+
],
1532+
},
1533+
unauthorizedHandler: {
1534+
type: 'token_refresh',
1535+
handler: expect.any(Function),
1536+
},
1537+
})
1538+
expect(result).toMatchObject({
1539+
shopDomain,
1540+
shopName: 'My Production Store',
1541+
provisionable: true,
1542+
storeType: 'PRODUCTION',
1543+
})
1544+
})
1545+
1546+
test('returns undefined when no active stores match the requested filters', async () => {
1547+
// Given
1548+
vi.mocked(businessPlatformOrganizationsRequestDoc).mockResolvedValueOnce({
1549+
organization: {
1550+
id: 'gid://shopify/Organization/123',
1551+
name: 'Org 123',
1552+
accessibleShops: {edges: []},
1553+
currentUser: {organizationPermissions: []},
1554+
},
1555+
})
1556+
1557+
const client = AppManagementClient.getInstance()
1558+
client.businessPlatformToken = () => Promise.resolve('business-platform-token')
1559+
1560+
// When
1561+
const result = await client.storeByDomain('gid://shopify/Organization/123', 'missing-store.myshopify.com', [
1562+
'APP_DEVELOPMENT',
1563+
])
1564+
1565+
// Then
1566+
expect(result).toBeUndefined()
1567+
expect(vi.mocked(businessPlatformOrganizationsRequestDoc)).toHaveBeenCalledWith({
1568+
query: FetchStoreByDomain,
1569+
token: 'business-platform-token',
1570+
organizationId: '123',
1571+
variables: {
1572+
domain: 'missing-store.myshopify.com',
1573+
filters: [
1574+
{field: 'STORE_TYPE', operator: 'EQUALS', value: 'app_development'},
1575+
{field: 'STORE_STATUS', operator: 'EQUALS', value: 'ACTIVE'},
1576+
],
1577+
},
1578+
unauthorizedHandler: {
1579+
type: 'token_refresh',
1580+
handler: expect.any(Function),
1581+
},
1582+
})
1583+
})
1584+
})
1585+
14551586
describe('ensureUserAccessToStore', () => {
14561587
test('ensures user access to store', async () => {
14571588
// Given

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,11 +1486,11 @@ function toUserError(err: CreateAppVersionMutation['appVersionCreate']['userErro
14861486
return {...err, details}
14871487
}
14881488

1489-
// Keep explicit domain lookup broader than ListAppDevStores for now.
1490-
// If APP_DEVELOPMENT lookups also need to exclude deleted/inactive stores here,
1491-
// add STORE_STATUS=ACTIVE only for that store type and cover mixed storeTypes callers.
14921489
function storeByDomainFilters(storeType: Store) {
1493-
return [{field: 'STORE_TYPE' as const, operator: 'EQUALS' as const, value: storeType.toLowerCase()}]
1490+
return [
1491+
{field: 'STORE_TYPE' as const, operator: 'EQUALS' as const, value: storeType.toLowerCase()},
1492+
{field: 'STORE_STATUS' as const, operator: 'EQUALS' as const, value: 'ACTIVE'},
1493+
]
14941494
}
14951495

14961496
function isStoreProvisionable(permissions: string[]) {

0 commit comments

Comments
 (0)