Skip to content

Commit 11bd780

Browse files
authored
Merge pull request #7187 from Shopify/dlm-store-auth-restructure
Store auth restructure
2 parents b38f61c + d2680ce commit 11bd780

29 files changed

Lines changed: 2344 additions & 1801 deletions

packages/cli/src/cli/commands/store/auth.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {describe, test, expect, vi, beforeEach} from 'vitest'
22
import StoreAuth from './auth.js'
3-
import {authenticateStoreWithApp} from '../../services/store/auth.js'
3+
import {authenticateStoreWithApp} from '../../services/store/auth/index.js'
44

5-
vi.mock('../../services/store/auth.js')
5+
vi.mock('../../services/store/auth/index.js')
66

77
describe('store auth command', () => {
88
beforeEach(() => {

packages/cli/src/cli/commands/store/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Command from '@shopify/cli-kit/node/base-command'
22
import {globalFlags} from '@shopify/cli-kit/node/cli'
33
import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn'
44
import {Flags} from '@oclif/core'
5-
import {authenticateStoreWithApp} from '../../services/store/auth.js'
5+
import {authenticateStoreWithApp} from '../../services/store/auth/index.js'
66

77
export default class StoreAuth extends Command {
88
static summary = 'Authenticate an app against a store for store commands.'

packages/cli/src/cli/services/store/admin-graphql-context.test.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import {AbortError} from '@shopify/cli-kit/node/error'
44
import {fetch} from '@shopify/cli-kit/node/http'
55
import {
66
clearStoredStoreAppSession,
7-
getStoredStoreAppSession,
8-
isSessionExpired,
7+
getCurrentStoredStoreAppSession,
98
setStoredStoreAppSession,
10-
} from './session.js'
11-
import {STORE_AUTH_APP_CLIENT_ID} from './auth-config.js'
9+
} from './auth/session-store.js'
10+
import {STORE_AUTH_APP_CLIENT_ID} from './auth/config.js'
1211
import {prepareAdminStoreGraphQLContext} from './admin-graphql-context.js'
1312

14-
vi.mock('./session.js')
13+
vi.mock('./auth/session-store.js')
1514
vi.mock('@shopify/cli-kit/node/http')
1615
vi.mock('@shopify/cli-kit/node/api/admin', async () => {
1716
const actual = await vi.importActual<typeof import('@shopify/cli-kit/node/api/admin')>('@shopify/cli-kit/node/api/admin')
@@ -23,6 +22,9 @@ vi.mock('@shopify/cli-kit/node/api/admin', async () => {
2322

2423
describe('prepareAdminStoreGraphQLContext', () => {
2524
const store = 'shop.myshopify.com'
25+
const futureExpiry = new Date(Date.now() + 60 * 60 * 1000).toISOString()
26+
const expiredAt = new Date(Date.now() - 60 * 1000).toISOString()
27+
2628
const storedSession = {
2729
store,
2830
clientId: STORE_AUTH_APP_CLIENT_ID,
@@ -31,13 +33,12 @@ describe('prepareAdminStoreGraphQLContext', () => {
3133
refreshToken: 'refresh-token',
3234
scopes: ['read_products'],
3335
acquiredAt: '2026-03-27T00:00:00.000Z',
34-
expiresAt: '2026-03-27T01:00:00.000Z',
36+
expiresAt: futureExpiry,
3537
}
3638

3739
beforeEach(() => {
3840
vi.clearAllMocks()
39-
vi.mocked(getStoredStoreAppSession).mockReturnValue(storedSession)
40-
vi.mocked(isSessionExpired).mockReturnValue(false)
41+
vi.mocked(getCurrentStoredStoreAppSession).mockReturnValue(storedSession)
4142
vi.mocked(fetchApiVersions).mockResolvedValue([
4243
{handle: '2025-10', supported: true},
4344
{handle: '2025-07', supported: true},
@@ -59,7 +60,7 @@ describe('prepareAdminStoreGraphQLContext', () => {
5960
})
6061

6162
test('refreshes expired sessions before resolving the API version', async () => {
62-
vi.mocked(isSessionExpired).mockReturnValue(true)
63+
vi.mocked(getCurrentStoredStoreAppSession).mockReturnValue({...storedSession, expiresAt: expiredAt})
6364
vi.mocked(fetch).mockResolvedValue({
6465
ok: true,
6566
text: vi.fn().mockResolvedValue(
@@ -98,7 +99,7 @@ describe('prepareAdminStoreGraphQLContext', () => {
9899
})
99100

100101
test('throws when no stored auth exists', async () => {
101-
vi.mocked(getStoredStoreAppSession).mockReturnValue(undefined)
102+
vi.mocked(getCurrentStoredStoreAppSession).mockReturnValue(undefined)
102103

103104
await expect(prepareAdminStoreGraphQLContext({store})).rejects.toMatchObject({
104105
message: `No stored app authentication found for ${store}.`,
@@ -108,7 +109,7 @@ describe('prepareAdminStoreGraphQLContext', () => {
108109
})
109110

110111
test('clears stored auth when token refresh fails', async () => {
111-
vi.mocked(isSessionExpired).mockReturnValue(true)
112+
vi.mocked(getCurrentStoredStoreAppSession).mockReturnValue({...storedSession, expiresAt: expiredAt})
112113
vi.mocked(fetch).mockResolvedValue({
113114
ok: false,
114115
status: 401,
@@ -124,8 +125,7 @@ describe('prepareAdminStoreGraphQLContext', () => {
124125
})
125126

126127
test('throws when an expired session cannot be refreshed because no refresh token is stored', async () => {
127-
vi.mocked(isSessionExpired).mockReturnValue(true)
128-
vi.mocked(getStoredStoreAppSession).mockReturnValue({...storedSession, refreshToken: undefined})
128+
vi.mocked(getCurrentStoredStoreAppSession).mockReturnValue({...storedSession, refreshToken: undefined, expiresAt: expiredAt})
129129

130130
await expect(prepareAdminStoreGraphQLContext({store})).rejects.toMatchObject({
131131
message: `No refresh token stored for ${store}.`,
@@ -136,7 +136,7 @@ describe('prepareAdminStoreGraphQLContext', () => {
136136
})
137137

138138
test('clears only the current stored auth when token refresh returns an invalid response body', async () => {
139-
vi.mocked(isSessionExpired).mockReturnValue(true)
139+
vi.mocked(getCurrentStoredStoreAppSession).mockReturnValue({...storedSession, expiresAt: expiredAt})
140140
vi.mocked(fetch).mockResolvedValue({
141141
ok: true,
142142
text: vi.fn().mockResolvedValue(JSON.stringify({refresh_token: 'fresh-refresh-token'})),
@@ -151,7 +151,7 @@ describe('prepareAdminStoreGraphQLContext', () => {
151151
})
152152

153153
test('clears only the current stored auth when token refresh returns malformed JSON', async () => {
154-
vi.mocked(isSessionExpired).mockReturnValue(true)
154+
vi.mocked(getCurrentStoredStoreAppSession).mockReturnValue({...storedSession, expiresAt: expiredAt})
155155
vi.mocked(fetch).mockResolvedValue({
156156
ok: true,
157157
text: vi.fn().mockResolvedValue('not-json'),

packages/cli/src/cli/services/store/admin-graphql-context.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import {fetchApiVersions} from '@shopify/cli-kit/node/api/admin'
22
import {AbortError} from '@shopify/cli-kit/node/error'
33
import {outputContent, outputDebug, outputToken} from '@shopify/cli-kit/node/output'
44
import {AdminSession} from '@shopify/cli-kit/node/session'
5-
import {reauthenticateStoreAuthError} from './auth-recovery.js'
6-
import {clearStoredStoreAppSession} from './session.js'
7-
import type {StoredStoreAppSession} from './session.js'
8-
import {loadStoredStoreSession} from './stored-session.js'
5+
import {reauthenticateStoreAuthError} from './auth/recovery.js'
6+
import {clearStoredStoreAppSession} from './auth/session-store.js'
7+
import type {StoredStoreAppSession} from './auth/session-store.js'
8+
import {loadStoredStoreSession} from './auth/session-lifecycle.js'
99

1010
export interface AdminStoreGraphQLContext {
1111
adminSession: AdminSession

packages/cli/src/cli/services/store/admin-graphql-transport.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import {beforeEach, describe, expect, test, vi} from 'vitest'
22
import {adminUrl} from '@shopify/cli-kit/node/api/admin'
33
import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql'
44
import {renderSingleTask} from '@shopify/cli-kit/node/ui'
5-
import {clearStoredStoreAppSession} from './session.js'
5+
import {clearStoredStoreAppSession} from './auth/session-store.js'
66
import {prepareStoreExecuteRequest} from './execute-request.js'
77
import {runAdminStoreGraphQLOperation} from './admin-graphql-transport.js'
88

9-
vi.mock('./session.js')
9+
vi.mock('./auth/session-store.js')
1010
vi.mock('@shopify/cli-kit/node/api/graphql')
1111
vi.mock('@shopify/cli-kit/node/ui')
1212
vi.mock('@shopify/cli-kit/node/api/admin', async () => {

packages/cli/src/cli/services/store/admin-graphql-transport.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import {AbortError} from '@shopify/cli-kit/node/error'
44
import {outputContent} from '@shopify/cli-kit/node/output'
55
import {AdminSession} from '@shopify/cli-kit/node/session'
66
import {renderSingleTask} from '@shopify/cli-kit/node/ui'
7-
import {reauthenticateStoreAuthError} from './auth-recovery.js'
7+
import {reauthenticateStoreAuthError} from './auth/recovery.js'
88
import {PreparedStoreExecuteRequest} from './execute-request.js'
9-
import {clearStoredStoreAppSession} from './session.js'
9+
import {clearStoredStoreAppSession} from './auth/session-store.js'
1010

1111
function isGraphQLClientError(error: unknown): error is {response: {errors?: unknown; status?: number}} {
1212
if (!error || typeof error !== 'object' || !('response' in error)) return false

0 commit comments

Comments
 (0)