From 7674c381b8d69a2cc20fbfe3baa56f7bde1dbf12 Mon Sep 17 00:00:00 2001 From: Donald Merand Date: Wed, 10 Jun 2026 15:24:04 -0400 Subject: [PATCH] Add store-auth source and auto fallback to store list Adds `--from auto|organization|store-auth`. `auto` (default) prefers the Shopify organization listing and falls back to locally stored store auth when the organization can't be listed for the current CLI session. Adds the store-auth source/local-source, the discriminated result contract, and the unavailable status that drives the fallback. --- .changeset/store-list-bp-auto.md | 2 +- .../interfaces/store-list.interface.ts | 8 +- .../generated/generated_docs_data_v2.json | 13 +- .../cli-kit/src/public/node/session.test.ts | 15 ++ packages/cli-kit/src/public/node/session.ts | 8 +- packages/cli/README.md | 30 ++- packages/cli/oclif.manifest.json | 25 ++- .../store/src/cli/commands/store/list.test.ts | 27 +-- packages/store/src/cli/commands/store/list.ts | 34 ++- .../src/cli/services/store/auth/index.ts | 2 +- .../cli/services/store/auth/stored-auth.ts | 2 +- .../cli/services/store/list/bp-source.test.ts | 110 +++++----- .../src/cli/services/store/list/bp-source.ts | 141 +++++++----- .../src/cli/services/store/list/index.test.ts | 205 +++++++++++++----- .../src/cli/services/store/list/index.ts | 71 +++++- .../services/store/list/local-source.test.ts | 39 ++++ .../cli/services/store/list/local-source.ts | 11 + .../cli/services/store/list/result.test.ts | 73 +++++-- .../src/cli/services/store/list/result.ts | 47 +++- .../src/cli/services/store/list/types.ts | 26 ++- 20 files changed, 627 insertions(+), 262 deletions(-) create mode 100644 packages/store/src/cli/services/store/list/local-source.test.ts create mode 100644 packages/store/src/cli/services/store/list/local-source.ts diff --git a/.changeset/store-list-bp-auto.md b/.changeset/store-list-bp-auto.md index 633ebc68162..c77c4b49a63 100644 --- a/.changeset/store-list-bp-auto.md +++ b/.changeset/store-list-bp-auto.md @@ -5,4 +5,4 @@ '@shopify/cli-kit': patch --- -Add `shopify store list` to list the stores in the Shopify organizations available to the current CLI account. When some organization lookups fail, the command returns the successful organizations with a warning and failure details for the skipped ones. +Add `shopify store list` with `--from auto|organization|store-auth`. By default the command prefers your Shopify organization and falls back to locally stored store auth when the organization can't be listed for the current CLI session. When some organization lookups fail, the command still returns successful organizations with a warning and failure details for the skipped organizations. diff --git a/docs-shopify.dev/commands/interfaces/store-list.interface.ts b/docs-shopify.dev/commands/interfaces/store-list.interface.ts index 757311f7e7f..7f21583dbfd 100644 --- a/docs-shopify.dev/commands/interfaces/store-list.interface.ts +++ b/docs-shopify.dev/commands/interfaces/store-list.interface.ts @@ -4,6 +4,12 @@ * @publicDocs */ export interface storelist { + /** + * Source for the listing. `auto` prefers your Shopify organization and falls back to locally stored store auth when necessary. + * @environment SHOPIFY_FLAG_STORE_LIST_FROM + */ + '--from '?: string + /** * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON @@ -17,7 +23,7 @@ export interface storelist { '--no-color'?: '' /** - * List stores for a single organization, by ID. + * List stores for a single organization, by ID. Only valid with `--from auto` or `--from organization`. * @environment SHOPIFY_FLAG_ORGANIZATION_ID */ '--organization-id '?: string diff --git a/docs-shopify.dev/generated/generated_docs_data_v2.json b/docs-shopify.dev/generated/generated_docs_data_v2.json index cf6b3ecdb44..56f4cbaf5d0 100644 --- a/docs-shopify.dev/generated/generated_docs_data_v2.json +++ b/docs-shopify.dev/generated/generated_docs_data_v2.json @@ -4346,6 +4346,15 @@ "description": "The following flags are available for the `store list` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/store-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--from ", + "value": "string", + "description": "Source for the listing. `auto` prefers your Shopify organization and falls back to locally stored store auth when necessary.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_STORE_LIST_FROM" + }, { "filePath": "docs-shopify.dev/commands/interfaces/store-list.interface.ts", "syntaxKind": "PropertySignature", @@ -4360,7 +4369,7 @@ "syntaxKind": "PropertySignature", "name": "--organization-id ", "value": "string", - "description": "List stores for a single organization, by ID.", + "description": "List stores for a single organization, by ID. Only valid with `--from auto` or `--from organization`.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_ORGANIZATION_ID" }, @@ -4383,7 +4392,7 @@ "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface storelist {\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * List stores for a single organization, by ID.\n * @environment SHOPIFY_FLAG_ORGANIZATION_ID\n */\n '--organization-id '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface storelist {\n /**\n * Source for the listing. `auto` prefers your Shopify organization and falls back to locally stored store auth when necessary.\n * @environment SHOPIFY_FLAG_STORE_LIST_FROM\n */\n '--from '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * List stores for a single organization, by ID. Only valid with `--from auto` or `--from organization`.\n * @environment SHOPIFY_FLAG_ORGANIZATION_ID\n */\n '--organization-id '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themecheck": { diff --git a/packages/cli-kit/src/public/node/session.test.ts b/packages/cli-kit/src/public/node/session.test.ts index 810f9acc1c1..ef689ec2104 100644 --- a/packages/cli-kit/src/public/node/session.test.ts +++ b/packages/cli-kit/src/public/node/session.test.ts @@ -216,6 +216,21 @@ describe('ensureAuthenticatedBusinessPlatform', () => { expect(got).toEqual('business_platform') }) + test('passes auth options through to the private auth helper', async () => { + // Given + vi.mocked(ensureAuthenticated).mockResolvedValueOnce({businessPlatform: 'business_platform', userId: '1234-5678'}) + + // When + await ensureAuthenticatedBusinessPlatform([], {noPrompt: true}) + + // Then + expect(ensureAuthenticated).toHaveBeenCalledWith( + {businessPlatformApi: {scopes: []}}, + process.env, + expect.objectContaining({noPrompt: true}), + ) + }) + test('throws error if there is no business_platform token', async () => { // Given vi.mocked(ensureAuthenticated).mockResolvedValueOnce({partners: 'partners_token', userId: '1234-5678'}) diff --git a/packages/cli-kit/src/public/node/session.ts b/packages/cli-kit/src/public/node/session.ts index 1ebffdeaf47..630626ecd90 100644 --- a/packages/cli-kit/src/public/node/session.ts +++ b/packages/cli-kit/src/public/node/session.ts @@ -270,13 +270,17 @@ ${outputToken.json(scopes)} * Ensure that we have a valid session to access the Business Platform API. * * @param scopes - Optional array of extra scopes to authenticate with. + * @param options - Optional auth behavior overrides such as `noPrompt`. * @returns The access token for the Business Platform API. */ -export async function ensureAuthenticatedBusinessPlatform(scopes: BusinessPlatformScope[] = []): Promise { +export async function ensureAuthenticatedBusinessPlatform( + scopes: BusinessPlatformScope[] = [], + options: EnsureAuthenticatedAdditionalOptions = {}, +): Promise { outputDebug(outputContent`Ensuring that the user is authenticated with the Business Platform API with the following scopes: ${outputToken.json(scopes)} `) - const tokens = await ensureAuthenticated({businessPlatformApi: {scopes}}, process.env) + const tokens = await ensureAuthenticated({businessPlatformApi: {scopes}}, process.env, options) if (!tokens.businessPlatform) { throw new BugError('No business-platform token found after ensuring authenticated') } diff --git a/packages/cli/README.md b/packages/cli/README.md index bc25e3977d7..1a4b96f7e93 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -2209,31 +2209,49 @@ EXAMPLES ## `shopify store list` -List stores in your Shopify organizations. +List stores available to the current CLI session. ``` USAGE - $ shopify store list [-j] [--no-color] [--organization-id ] [--verbose] + $ shopify store list [--from auto|organization|store-auth] [-j] [--no-color] [--organization-id ] + [--verbose] FLAGS -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. + --from=