feat(shopify): expand operations and refresh expiring credentials (#8… · simstudioai/sim@4308631 · GitHub
Skip to content

Commit 4308631

Browse files
authored
feat(shopify): expand operations and refresh expiring credentials (#8833)
* feat(shopify): expand operations and refresh expiring credentials * fix(shopify): align operation inputs and response contracts * fix(shopify): preserve scoped order updates and refine output contracts
1 parent f20b5b4 commit 4308631

49 files changed

Lines changed: 6552 additions & 883 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎apps/docs/content/docs/integrations/shopify.mdx‎

Lines changed: 703 additions & 64 deletions
Large diffs are not rendered by default.

‎apps/sim/app/api/auth/oauth2/callback/shopify/route.test.ts‎

Lines changed: 33 additions & 13 deletions

‎apps/sim/app/api/auth/oauth2/callback/shopify/route.ts‎

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { isSameOrigin } from '@/lib/core/utils/validation'
1414
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
1515
import { APP_ENTRY_PATH } from '@/lib/navigation/paths'
1616
import { completeShopifyOAuthConnection } from '@/lib/oauth/shopify'
17+
import { ShopifyOAuthError } from '@/lib/oauth/shopify-installation'
1718
import { parseShopifyOAuthState } from '@/lib/oauth/shopify-state'
1819

1920
const logger = createLogger('ShopifyCallback')
@@ -75,7 +76,7 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
7576
})
7677

7778
const {
78-
values: { SHOPIFY_CLIENT_ID: clientId, SHOPIFY_CLIENT_SECRET: clientSecret },
79+
values: { SHOPIFY_CLIENT_SECRET: clientSecret },
7980
} = requireConfiguredOAuthClient('shopify')
8081

8182
if (!validateHmac(searchParams, clientSecret)) {
@@ -111,64 +112,32 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
111112
clientSecret,
112113
})
113114

114-
const tokenResponse = await fetch(`https://${shopDomain}/admin/oauth/access_token`, {
115-
method: 'POST',
116-
headers: {
117-
'Content-Type': 'application/json',
118-
},
119-
body: JSON.stringify({
120-
client_id: clientId,
121-
client_secret: clientSecret,
122-
code: code,
123-
}),
124-
})
125-
126-
if (!tokenResponse.ok) {
127-
const errorText = await tokenResponse.text()
128-
logger.error('Failed to exchange code for token:', {
129-
status: tokenResponse.status,
130-
body: errorText,
131-
})
132-
return NextResponse.redirect(`${baseUrl}${APP_ENTRY_PATH}?error=shopify_token_error`)
133-
}
134-
135-
const tokenData = await tokenResponse.json()
136-
const accessToken = tokenData.access_token
137-
const scope = tokenData.scope
138-
139-
logger.info('Shopify token exchange successful:', {
140-
hasAccessToken: !!accessToken,
141-
scope: scope,
142-
})
143-
144-
if (!accessToken) {
145-
logger.error('No access token in response')
146-
return NextResponse.redirect(`${baseUrl}${APP_ENTRY_PATH}?error=shopify_no_token`)
115+
if (returnUrl && !isSameOrigin(returnUrl)) {
116+
throw new Error('Shopify OAuth state contains an invalid return URL')
147117
}
148118

149119
await completeShopifyOAuthConnection({
150-
accessToken,
120+
code,
151121
shopDomain,
152-
scope,
153122
userId: session.user.id,
154123
draftId,
155124
signal: request.signal,
156125
})
157126

158-
if (returnUrl && !isSameOrigin(returnUrl)) {
159-
throw new Error('Shopify OAuth state contains an invalid return URL')
160-
}
161127
const redirectUrl = returnUrl ?? `${baseUrl}${APP_ENTRY_PATH}`
162128
const finalUrl = new URL(redirectUrl)
163129
finalUrl.searchParams.set('shopify_connected', 'true')
164130

165131
return clearShopifyOAuthCookies(NextResponse.redirect(finalUrl))
166132
} catch (error) {
167-
logger.error('Error in Shopify OAuth callback:', error)
133+
if (request.signal.aborted) throw error
134+
logger.error('Shopify OAuth callback failed')
168135
const errorCode =
169136
error instanceof EnvCapabilityConfigurationError && error.capabilityId === 'oauth'
170137
? 'shopify_config_error'
171-
: 'shopify_callback_error'
138+
: error instanceof ShopifyOAuthError
139+
? error.callbackError
140+
: 'shopify_callback_error'
172141
return clearShopifyOAuthCookies(
173142
NextResponse.redirect(`${baseUrl}${APP_ENTRY_PATH}?error=${errorCode}`)
174143
)
Lines changed: 29 additions & 0 deletions

0 commit comments

Comments
 (0)