From 2070cf2fd5fed7aa0059ef0f0973e6b0787255ab Mon Sep 17 00:00:00 2001 From: Gray Gilmore Date: Thu, 28 May 2026 14:17:26 -0700 Subject: [PATCH] Use validated storefront password for theme apps ensureValidPassword now treats an empty string as a provided password, so passing '' from the app dev flow skips the normal prompt/local storage fallback. Pass undefined instead so password-protected stores use the same validation path as theme dev, and keep the returned password on the theme app extension process options. --- .changeset/strict-toys-try.md | 5 ++++ .../dev/processes/theme-app-extension.test.ts | 28 +++++++++++++++++++ .../dev/processes/theme-app-extension.ts | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 .changeset/strict-toys-try.md diff --git a/.changeset/strict-toys-try.md b/.changeset/strict-toys-try.md new file mode 100644 index 00000000000..b7a80c1871c --- /dev/null +++ b/.changeset/strict-toys-try.md @@ -0,0 +1,5 @@ +--- +'@shopify/app': patch +--- + +Fix `app dev` always prompting for storefront password diff --git a/packages/app/src/cli/services/dev/processes/theme-app-extension.test.ts b/packages/app/src/cli/services/dev/processes/theme-app-extension.test.ts index bf9e0d15b01..a2a93321aab 100644 --- a/packages/app/src/cli/services/dev/processes/theme-app-extension.test.ts +++ b/packages/app/src/cli/services/dev/processes/theme-app-extension.test.ts @@ -14,6 +14,7 @@ import {Theme} from '@shopify/cli-kit/node/themes/types' import {vi, describe, test, expect, beforeEach} from 'vitest' import {renderInfo} from '@shopify/cli-kit/node/ui' import {partnersFqdn, adminFqdn} from '@shopify/cli-kit/node/context/fqdn' +import {ensureValidPassword, isStorefrontPasswordProtected} from '@shopify/theme' vi.mock('../../../utilities/extensions/theme/host-theme-manager') vi.mock('@shopify/cli-kit/node/output') @@ -35,6 +36,14 @@ vi.mock('@shopify/cli-kit/node/ui', async (realImport) => { }), } }) +vi.mock('@shopify/theme', async (realImport) => { + const realModule = await realImport() + return { + ...realModule, + ensureValidPassword: vi.fn(), + isStorefrontPasswordProtected: vi.fn(), + } +}) describe('setupPreviewThemeAppExtensionsProcess', () => { const mockAdminSession = {storeFqdn: 'test.myshopify.com'} as any as AdminSession @@ -176,6 +185,25 @@ describe('setupPreviewThemeAppExtensionsProcess', () => { orderedNextSteps: true, }) }) + + test('returns the validated storefront password when one is required', async () => { + const mockTheme = {id: 123} as Theme + const storefrontPassword = 'typed-password' + vi.mocked(fetchTheme).mockResolvedValue(mockTheme) + vi.mocked(isStorefrontPasswordProtected).mockResolvedValue(true) + vi.mocked(ensureValidPassword).mockResolvedValue(storefrontPassword) + + const result = await setupPreviewThemeAppExtensionsProcess({ + localApp: testApp({allExtensions: [await testThemeExtensions()]}), + remoteApp: testOrganizationApp(), + storeFqdn: 'test.myshopify.com', + theme: '1', + }) + + expect(ensureValidPassword).toHaveBeenCalledOnce() + expect(ensureValidPassword).toHaveBeenCalledWith(undefined, 'test.myshopify.com') + expect(result!.options.storefrontPassword).toEqual(storefrontPassword) + }) }) describe('findOrCreateHostTheme', () => { diff --git a/packages/app/src/cli/services/dev/processes/theme-app-extension.ts b/packages/app/src/cli/services/dev/processes/theme-app-extension.ts index 37b6f3c8c8d..cda4751c29c 100644 --- a/packages/app/src/cli/services/dev/processes/theme-app-extension.ts +++ b/packages/app/src/cli/services/dev/processes/theme-app-extension.ts @@ -53,7 +53,7 @@ export async function setupPreviewThemeAppExtensionsProcess( const storeFqdn = adminSession.storeFqdn const storefrontPassword = (await isStorefrontPasswordProtected(adminSession)) - ? await ensureValidPassword('', storeFqdn) + ? await ensureValidPassword(undefined, storeFqdn) : undefined const theme = await findOrCreateHostTheme(adminSession, options.theme)