Skip to content

Commit 16a3be0

Browse files
committed
Force all requests in app management to have an unauthorizedHandler
1 parent 7b973d3 commit 16a3be0

File tree

10 files changed

+457
-358
lines changed

10 files changed

+457
-358
lines changed

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

Lines changed: 130 additions & 122 deletions
Large diffs are not rendered by default.

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

Lines changed: 150 additions & 139 deletions
Large diffs are not rendered by default.

packages/cli-kit/src/public/node/api/admin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export async function adminRequestDoc<TResult, TVariables extends Variables>(
8080
}
8181
let unauthorizedHandler: UnauthorizedHandler | undefined
8282
if ('refresh' in session) {
83-
unauthorizedHandler = {type: 'simple', handler: session.refresh as () => Promise<void>}
83+
unauthorizedHandler = {type: 'token_refresh', handler: session.refresh as () => Promise<{token: string}>}
8484
}
8585
const result = graphqlRequestDoc<TResult, TVariables>({
8686
...opts,

packages/cli-kit/src/public/node/api/app-dev.test.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {appDevRequest} from './app-dev.js'
1+
import {appDevRequestDoc} from './app-dev.js'
22
import {graphqlRequestDoc} from './graphql.js'
33
import {serviceEnvironment, Environment} from '../../../private/node/context/service.js'
44
import {test, vi, expect, describe} from 'vitest'
@@ -33,7 +33,16 @@ describe('appDevRequest', () => {
3333
const query = 'query' as unknown as TypedDocumentNode<object, {variables: string}>
3434

3535
// When
36-
await appDevRequest(query, shopFqdn, mockedToken, {variables: 'variables'})
36+
await appDevRequestDoc({
37+
query,
38+
shopFqdn,
39+
token: mockedToken,
40+
variables: {variables: 'variables'},
41+
unauthorizedHandler: {
42+
type: 'token_refresh',
43+
handler: vi.fn().mockResolvedValue({token: mockedToken}),
44+
},
45+
})
3746

3847
// Then
3948
expect(graphqlRequestDoc).toHaveBeenLastCalledWith({
@@ -42,6 +51,10 @@ describe('appDevRequest', () => {
4251
url: 'https://test-shop.shop.dev/app_dev/unstable/graphql.json',
4352
token: mockedToken,
4453
variables: {variables: 'variables'},
54+
unauthorizedHandler: {
55+
type: 'token_refresh',
56+
handler: expect.any(Function),
57+
},
4558
})
4659
})
4760

@@ -51,7 +64,16 @@ describe('appDevRequest', () => {
5164
const query = 'query' as unknown as TypedDocumentNode<object, {variables: string}>
5265

5366
// When
54-
await appDevRequest(query, shopFqdn, mockedToken, {variables: 'variables'})
67+
await appDevRequestDoc({
68+
query,
69+
shopFqdn,
70+
token: mockedToken,
71+
variables: {variables: 'variables'},
72+
unauthorizedHandler: {
73+
type: 'token_refresh',
74+
handler: vi.fn().mockResolvedValue({token: mockedToken}),
75+
},
76+
})
5577

5678
// Then
5779
expect(graphqlRequestDoc).toHaveBeenLastCalledWith({
@@ -61,6 +83,10 @@ describe('appDevRequest', () => {
6183
token: mockedToken,
6284
addedHeaders: {'x-forwarded-host': shopFqdn},
6385
variables: {variables: 'variables'},
86+
unauthorizedHandler: {
87+
type: 'token_refresh',
88+
handler: expect.any(Function),
89+
},
6490
})
6591
})
6692
})

packages/cli-kit/src/public/node/api/app-dev.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {graphqlRequestDoc} from './graphql.js'
1+
import {graphqlRequestDoc, UnauthorizedHandler} from './graphql.js'
22
import {appDevFqdn, normalizeStoreFqdn} from '../context/fqdn.js'
33
import {serviceEnvironment} from '../../../private/node/context/service.js'
44
import Bottleneck from 'bottleneck'
@@ -14,36 +14,45 @@ const limiter = new Bottleneck({
1414
})
1515

1616
/**
17-
* Executes an org-scoped GraphQL query against the App Management API.
18-
* Uses typed documents.
19-
*
2017
* @param query - GraphQL query to execute.
2118
* @param shopFqdn - The shop fqdn.
2219
* @param token - Partners token.
2320
* @param variables - GraphQL variables to pass to the query.
21+
* @param unauthorizedHandler - Unauthorized handler to use.
22+
*/
23+
export interface AppDevRequestOptions<TResult, TVariables extends Variables> {
24+
query: TypedDocumentNode<TResult, TVariables>
25+
shopFqdn: string
26+
token: string
27+
unauthorizedHandler: UnauthorizedHandler
28+
variables?: TVariables
29+
}
30+
/**
31+
* Executes an org-scoped GraphQL query against the App Management API.
32+
* Uses typed documents.
33+
*
34+
* @param options - The options for the request.
2435
* @returns The response of the query of generic type <T>.
2536
*/
26-
export async function appDevRequest<TResult, TVariables extends Variables>(
27-
query: TypedDocumentNode<TResult, TVariables>,
28-
shopFqdn: string,
29-
token: string,
30-
variables?: TVariables,
37+
export async function appDevRequestDoc<TResult, TVariables extends Variables>(
38+
options: AppDevRequestOptions<TResult, TVariables>,
3139
): Promise<TResult> {
3240
const api = 'App Dev'
33-
const normalizedShopFqdn = await normalizeStoreFqdn(shopFqdn)
41+
const normalizedShopFqdn = await normalizeStoreFqdn(options.shopFqdn)
3442
const fqdn = await appDevFqdn(normalizedShopFqdn)
3543
const url = `https://${fqdn}/app_dev/unstable/graphql.json`
3644

3745
const addedHeaders = serviceEnvironment() === 'local' ? {'x-forwarded-host': normalizedShopFqdn} : undefined
3846

3947
const result = limiter.schedule<TResult>(() =>
4048
graphqlRequestDoc<TResult, TVariables>({
41-
query,
49+
query: options.query,
4250
api,
4351
url,
44-
token,
52+
token: options.token,
4553
addedHeaders,
46-
variables,
54+
variables: options.variables,
55+
unauthorizedHandler: options.unauthorizedHandler,
4756
}),
4857
)
4958

packages/cli-kit/src/public/node/api/app-management.test.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,18 @@ describe('appManagementRequestDoc', () => {
2727

2828
// When
2929
const query = 'query' as unknown as TypedDocumentNode<object, {variables: string}>
30-
await appManagementRequestDoc(
31-
orgId,
30+
await appManagementRequestDoc({
31+
organizationId: orgId,
3232
query,
33-
mockedToken,
34-
{variables: 'variables'},
35-
{cacheTTL: {hours: 1}, cacheExtraKey: '1234'},
36-
)
33+
token: mockedToken,
34+
variables: {variables: 'variables'},
35+
requestOptions: {requestMode: 'slow-request'},
36+
cacheOptions: {cacheTTL: {hours: 1}, cacheExtraKey: `1234`},
37+
unauthorizedHandler: {
38+
type: 'token_refresh',
39+
handler: vi.fn().mockResolvedValue({token: mockedToken}),
40+
},
41+
})
3742

3843
// Then
3944
expect(graphqlRequestDoc).toHaveBeenLastCalledWith({
@@ -44,6 +49,11 @@ describe('appManagementRequestDoc', () => {
4449
variables: {variables: 'variables'},
4550
responseOptions: {onResponse: handleDeprecations},
4651
cacheOptions: {cacheTTL: {hours: 1}, cacheExtraKey: `1234${orgId}`},
52+
preferredBehaviour: 'slow-request',
53+
unauthorizedHandler: {
54+
type: 'token_refresh',
55+
handler: expect.any(Function),
56+
},
4757
})
4858
})
4959
})

packages/cli-kit/src/public/node/api/app-management.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,38 +50,45 @@ export interface RequestOptions {
5050
}
5151

5252
/**
53-
* Executes an org-scoped GraphQL query against the App Management API. Uses typed documents.
54-
*
5553
* @param orgId - The organization ID.
5654
* @param query - GraphQL query to execute.
5755
* @param token - Partners token.
5856
* @param variables - GraphQL variables to pass to the query.
5957
* @param cacheOptions - Cache options for the request. If not present, the request will not be cached.
6058
* @param requestOptions - Preferred behaviour for the request.
6159
* @param unauthorizedHandler - Optional handler for unauthorized requests.
60+
*/
61+
export interface AppManagementRequestOptions<TResult, TVariables extends Variables> {
62+
organizationId: string
63+
query: TypedDocumentNode<TResult, TVariables>
64+
token: string
65+
variables?: TVariables
66+
cacheOptions?: CacheOptions
67+
requestOptions?: RequestOptions
68+
unauthorizedHandler: UnauthorizedHandler
69+
}
70+
71+
/**
72+
* Executes an org-scoped GraphQL query against the App Management API. Uses typed documents.
73+
*
74+
* @param options - The options for the request.
6275
* @returns The response of the query of generic type <T>.
6376
*/
6477
export async function appManagementRequestDoc<TResult, TVariables extends Variables>(
65-
orgId: string,
66-
query: TypedDocumentNode<TResult, TVariables>,
67-
token: string,
68-
variables?: TVariables,
69-
cacheOptions?: CacheOptions,
70-
requestOptions?: RequestOptions,
71-
unauthorizedHandler?: UnauthorizedHandler,
78+
options: AppManagementRequestOptions<TResult, TVariables>,
7279
): Promise<TResult> {
7380
// For app management, we need to cache the response based on the orgId.
74-
const cacheExtraKey = (cacheOptions?.cacheExtraKey ?? '') + orgId
75-
const newCacheOptions = cacheOptions ? {...cacheOptions, cacheExtraKey} : undefined
81+
const cacheExtraKey = (options.cacheOptions?.cacheExtraKey ?? '') + options.organizationId
82+
const newCacheOptions = options.cacheOptions ? {...options.cacheOptions, cacheExtraKey} : undefined
7683

7784
const result = limiter.schedule<TResult>(async () =>
7885
graphqlRequestDoc<TResult, TVariables>({
79-
...(await setupRequest(orgId, token)),
80-
query,
81-
variables,
86+
...(await setupRequest(options.organizationId, options.token)),
87+
query: options.query,
88+
variables: options.variables,
8289
cacheOptions: newCacheOptions,
83-
preferredBehaviour: requestOptions?.requestMode,
84-
unauthorizedHandler,
90+
preferredBehaviour: options.requestOptions?.requestMode,
91+
unauthorizedHandler: options.unauthorizedHandler,
8592
}),
8693
)
8794

packages/cli-kit/src/public/node/api/business-platform.ts

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {CacheOptions, Exact, GraphQLVariables, graphqlRequest, graphqlRequestDoc} from './graphql.js'
1+
import {CacheOptions, GraphQLVariables, UnauthorizedHandler, graphqlRequest, graphqlRequestDoc} from './graphql.js'
22
import {handleDeprecations} from './partners.js'
33
import {businessPlatformFqdn} from '../context/fqdn.js'
44
import {TypedDocumentNode} from '@graphql-typed-document-node/core'
@@ -45,25 +45,34 @@ export async function businessPlatformRequest<T>(
4545
}
4646

4747
/**
48-
* Executes a GraphQL query against the Business Platform Destinations API. Uses typed documents.
49-
*
5048
* @param query - GraphQL query to execute.
5149
* @param token - Business Platform token.
5250
* @param variables - GraphQL variables to pass to the query.
5351
* @param cacheOptions - Cache options for the request. If not present, the request will not be cached.
52+
*/
53+
export interface BusinessPlatformRequestOptions<TResult, TVariables extends Variables> {
54+
query: TypedDocumentNode<TResult, TVariables>
55+
token: string
56+
variables?: TVariables
57+
cacheOptions?: CacheOptions
58+
unauthorizedHandler: UnauthorizedHandler
59+
}
60+
61+
/**
62+
* Executes a GraphQL query against the Business Platform Destinations API. Uses typed documents.
63+
*
64+
* @param options - The options for the request.
5465
* @returns The response of the query of generic type <TResult>.
5566
*/
5667
export async function businessPlatformRequestDoc<TResult, TVariables extends Variables>(
57-
query: TypedDocumentNode<TResult, TVariables>,
58-
token: string,
59-
variables?: TVariables,
60-
cacheOptions?: CacheOptions,
68+
options: BusinessPlatformRequestOptions<TResult, TVariables>,
6169
): Promise<TResult> {
6270
return graphqlRequestDoc<TResult, TVariables>({
63-
...(await setupRequest(token)),
64-
query,
65-
variables,
66-
cacheOptions,
71+
...(await setupRequest(options.token)),
72+
query: options.query,
73+
variables: options.variables,
74+
cacheOptions: options.cacheOptions,
75+
unauthorizedHandler: options.unauthorizedHandler,
6776
})
6877
}
6978

@@ -85,46 +94,49 @@ async function setupOrganizationsRequest(token: string, organizationId: string)
8594
}
8695
}
8796

97+
export interface BusinessPlatformOrganizationsRequestNonTypedOptions {
98+
query: string
99+
token: string
100+
organizationId: string
101+
unauthorizedHandler: UnauthorizedHandler
102+
variables?: GraphQLVariables
103+
}
104+
88105
/**
89106
* Executes a GraphQL query against the Business Platform Organizations API.
90107
*
91-
* @param query - GraphQL query to execute.
92-
* @param token - Business Platform token.
93-
* @param organizationId - Organization ID as a numeric (non-GID) value.
94-
* @param variables - GraphQL variables to pass to the query.
108+
* @param options - The options for the request.
95109
* @returns The response of the query of generic type <T>.
96110
*/
97111
export async function businessPlatformOrganizationsRequest<T>(
98-
query: string,
99-
token: string,
100-
organizationId: string,
101-
variables?: GraphQLVariables,
112+
options: BusinessPlatformOrganizationsRequestNonTypedOptions,
102113
): Promise<T> {
103114
return graphqlRequest<T>({
104-
query,
105-
...(await setupOrganizationsRequest(token, organizationId)),
106-
variables,
115+
query: options.query,
116+
...(await setupOrganizationsRequest(options.token, options.organizationId)),
117+
variables: options.variables,
118+
unauthorizedHandler: options.unauthorizedHandler,
107119
})
108120
}
109121

122+
export interface BusinessPlatformOrganizationsRequestOptions<TResult, TVariables extends Variables>
123+
extends BusinessPlatformRequestOptions<TResult, TVariables> {
124+
organizationId: string
125+
}
126+
110127
/**
111128
* Executes a GraphQL query against the Business Platform Organizations API. Uses typed documents.
112129
*
113-
* @param query - GraphQL query to execute.
114-
* @param token - Business Platform token.
115-
* @param organizationId - Organization ID as a numeric value.
116-
* @param variables - GraphQL variables to pass to the query.
130+
* @param options - The options for the request.
117131
* @returns The response of the query of generic type <T>.
118132
*/
119133
export async function businessPlatformOrganizationsRequestDoc<TResult, TVariables extends Variables>(
120-
query: TypedDocumentNode<TResult, TVariables> | TypedDocumentNode<TResult, Exact<{[key: string]: never}>>,
121-
token: string,
122-
organizationId: string,
123-
variables?: TVariables,
134+
options: BusinessPlatformOrganizationsRequestOptions<TResult, TVariables>,
124135
): Promise<TResult> {
125136
return graphqlRequestDoc<TResult, TVariables>({
126-
query,
127-
...(await setupOrganizationsRequest(token, organizationId)),
128-
variables,
137+
query: options.query,
138+
...(await setupOrganizationsRequest(options.token, options.organizationId)),
139+
variables: options.variables,
140+
unauthorizedHandler: options.unauthorizedHandler,
129141
})
130142
}

0 commit comments

Comments
 (0)