diff --git a/packages/cli-kit/src/private/node/conf-store.ts b/packages/cli-kit/src/private/node/conf-store.ts index 1c585eae41a..b3c122ec6d5 100644 --- a/packages/cli-kit/src/private/node/conf-store.ts +++ b/packages/cli-kit/src/private/node/conf-store.ts @@ -26,12 +26,21 @@ interface Cache { [rateLimitKey: RateLimitKey]: CacheValue } +export interface PendingDeviceAuth { + deviceCode: string + interval: number + expiresAt: number + verificationUriComplete: string + scopes: string[] +} + export interface ConfSchema { sessionStore: string currentSessionId?: string devSessionStore?: string currentDevSessionId?: string cache?: Cache + pendingDeviceAuth?: PendingDeviceAuth } let _instance: LocalStorage | undefined @@ -112,6 +121,27 @@ export function removeCurrentSessionId(config: LocalStorage = cliKit config.delete(currentSessionIdKey()) } +/** + * Get pending device auth state (used for non-interactive login flow). + */ +export function getPendingDeviceAuth(config: LocalStorage = cliKitStore()): PendingDeviceAuth | undefined { + return config.get('pendingDeviceAuth') +} + +/** + * Stash pending device auth state for later resumption. + */ +export function setPendingDeviceAuth(auth: PendingDeviceAuth, config: LocalStorage = cliKitStore()): void { + config.set('pendingDeviceAuth', auth) +} + +/** + * Clear pending device auth state. + */ +export function clearPendingDeviceAuth(config: LocalStorage = cliKitStore()): void { + config.delete('pendingDeviceAuth') +} + type CacheValueForKey = NonNullable['value'] /** diff --git a/packages/cli-kit/src/private/node/session.ts b/packages/cli-kit/src/private/node/session.ts index 91cd578c5b7..3f711f718fd 100644 --- a/packages/cli-kit/src/private/node/session.ts +++ b/packages/cli-kit/src/private/node/session.ts @@ -293,8 +293,6 @@ The CLI is currently unable to prompt for reauthentication.`, */ async function executeCompleteFlow(applications: OAuthApplications): Promise { const scopes = getFlattenScopes(applications) - const exchangeScopes = getExchangeScopes(applications) - const store = applications.adminApi?.storeFqdn if (firstPartyDev()) { outputDebug(outputContent`Authenticating as Shopify Employee...`) scopes.push('employee') @@ -314,6 +312,22 @@ async function executeCompleteFlow(applications: OAuthApplications): Promise { + const exchangeScopes = getExchangeScopes(applications) + const store = applications.adminApi?.storeFqdn + // Exchange identity token for application tokens outputDebug(outputContent`CLI token received. Exchanging it for application tokens...`) const result = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, store) @@ -322,17 +336,13 @@ async function executeCompleteFlow(applications: OAuthApplications): Promise { +export async function requestDeviceAuthorization( + scopes: string[], + {noPrompt = false}: {noPrompt?: boolean} = {}, +): Promise { const fqdn = await identityFqdn() const identityClientId = clientId() const queryParams = {client_id: identityClientId, scope: scopes.join(' ')} @@ -69,32 +73,31 @@ export async function requestDeviceAuthorization(scopes: string[]): Promise { + if (noPrompt) { + outputInfo(outputContent`\nUser verification code: ${jsonResult.user_code}`) outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`) - } - - if (isCloudEnvironment() || !isTTY()) { - cloudMessage() } else { - outputInfo('👉 Press any key to open the login page on your browser') - await keypress() - const opened = await openURL(jsonResult.verification_uri_complete) - if (opened) { - outputInfo(outputContent`Opened link to start the auth process: ${linkToken}`) + outputInfo('\nTo run this command, log in to Shopify.') + outputInfo(outputContent`User verification code: ${jsonResult.user_code}`) + + if (isCI()) { + throw new AbortError( + 'Authorization is required to continue, but the current environment does not support interactive prompts.', + 'To resolve this, specify credentials in your environment, or run the command in an interactive environment such as your local terminal.', + ) + } else if (isCloudEnvironment() || !isTTY()) { + outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`) } else { - cloudMessage() + outputInfo('👉 Press any key to open the login page on your browser') + await keypress() + const opened = await openURL(jsonResult.verification_uri_complete) + if (opened) { + outputInfo(outputContent`Opened link to start the auth process: ${linkToken}`) + } else { + outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`) + } } } diff --git a/packages/cli-kit/src/public/node/session.ts b/packages/cli-kit/src/public/node/session.ts index 9757e55862e..7c391d15eb9 100644 --- a/packages/cli-kit/src/public/node/session.ts +++ b/packages/cli-kit/src/public/node/session.ts @@ -1,9 +1,11 @@ import {shopifyFetch} from './http.js' import {nonRandomUUID} from './crypto.js' import {getCliToken} from './environment.js' +import {identityFqdn} from './context/fqdn.js' import {AbortError, BugError} from './error.js' import {outputContent, outputToken, outputDebug} from './output.js' import * as sessionStore from '../../private/node/session/store.js' +import {getCurrentSessionId, setCurrentSessionId} from '../../private/node/conf-store.js' import { exchangeCustomPartnerToken, exchangeCliTokenForAppManagementAccessToken, @@ -274,6 +276,27 @@ ${outputToken.json(scopes)} return tokens.businessPlatform } +/** + * Returns info about the currently logged-in user, or undefined if not logged in. + * Does not trigger any authentication flow. + * + * @returns The current user's alias, or undefined if not logged in. + */ +export async function getCurrentUserInfo(): Promise<{alias: string} | undefined> { + const currentSessionId = getCurrentSessionId() + if (!currentSessionId) return undefined + + const sessions = await sessionStore.fetch() + if (!sessions) return undefined + + const fqdn = await identityFqdn() + const session = sessions[fqdn]?.[currentSessionId] + if (!session) return undefined + + const alias = session.identity.alias ?? currentSessionId + return {alias} +} + /** * Logout from Shopify. * @@ -283,6 +306,94 @@ export function logout(): Promise { return sessionStore.remove() } +/** + * Start the device authorization flow without polling. + * Stashes the device code for later resumption via `resumeDeviceAuth`. + * + * @returns The verification URL the user must visit to authorize. + */ +export async function startDeviceAuthNoPolling(): Promise<{verificationUriComplete: string}> { + const {requestDeviceAuthorization} = await import('../../private/node/session/device-authorization.js') + const {allDefaultScopes} = await import('../../private/node/session/scopes.js') + const {setPendingDeviceAuth} = await import('../../private/node/conf-store.js') + + const scopes = allDefaultScopes() + const deviceAuth = await requestDeviceAuthorization(scopes, {noPrompt: true}) + + setPendingDeviceAuth({ + deviceCode: deviceAuth.deviceCode, + interval: deviceAuth.interval ?? 5, + expiresAt: Date.now() + deviceAuth.expiresIn * 1000, + verificationUriComplete: deviceAuth.verificationUriComplete ?? deviceAuth.verificationUri, + scopes, + }) + + return {verificationUriComplete: deviceAuth.verificationUriComplete ?? deviceAuth.verificationUri} +} + +export type ResumeDeviceAuthResult = + | {status: 'success'; alias: string} + | {status: 'pending'; verificationUriComplete: string} + | {status: 'expired'; message: string} + | {status: 'denied'; message: string} + | {status: 'no_pending'; message: string} + +/** + * Resume a previously started device authorization flow. + * Exchanges the stashed device code for tokens and stores the session. + * + * @returns The result of the resume attempt. + */ +export async function resumeDeviceAuth(): Promise { + const {exchangeDeviceCodeForAccessToken} = await import('../../private/node/session/exchange.js') + const {getPendingDeviceAuth, clearPendingDeviceAuth} = await import('../../private/node/conf-store.js') + const {completeAuthFlow} = await import('../../private/node/session.js') + + const pending = getPendingDeviceAuth() + if (!pending) { + return {status: 'no_pending', message: 'No pending login flow. Run `shopify auth login --no-polling` first.'} + } + + if (Date.now() > pending.expiresAt) { + clearPendingDeviceAuth() + return {status: 'expired', message: 'The login flow has expired. Run `shopify auth login --no-polling` again.'} + } + + const result = await exchangeDeviceCodeForAccessToken(pending.deviceCode) + + if (result.isErr()) { + const error = result.error + if (error === 'authorization_pending') { + return {status: 'pending', verificationUriComplete: pending.verificationUriComplete} + } + if (error === 'expired_token') { + clearPendingDeviceAuth() + return {status: 'expired', message: 'The login flow has expired. Run `shopify auth login --no-polling` again.'} + } + // access_denied or unknown + clearPendingDeviceAuth() + return {status: 'denied', message: `Authorization failed: ${error}`} + } + + // Successfully got an identity token — complete the flow + const identityToken = result.value + const session = await completeAuthFlow(identityToken, {}) + const fqdn = await identityFqdn() + + // Store the session + const existingSessions = (await sessionStore.fetch()) ?? {} + const newSessionId = session.identity.userId + const updatedSessions = { + ...existingSessions, + [fqdn]: {...existingSessions[fqdn], [newSessionId]: session}, + } + await sessionStore.store(updatedSessions) + setCurrentSessionId(newSessionId) + + clearPendingDeviceAuth() + return {status: 'success', alias: session.identity.alias ?? newSessionId} +} + /** * Ensure that we have a valid Admin session for the given store, with access on behalf of the app. * diff --git a/packages/cli/README.md b/packages/cli/README.md index def3a91294f..ea15b3afe8d 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -32,6 +32,7 @@ * [`shopify app webhook trigger`](#shopify-app-webhook-trigger) * [`shopify auth login`](#shopify-auth-login) * [`shopify auth logout`](#shopify-auth-logout) +* [`shopify auth whoami`](#shopify-auth-whoami) * [`shopify commands`](#shopify-commands) * [`shopify config autocorrect off`](#shopify-config-autocorrect-off) * [`shopify config autocorrect on`](#shopify-config-autocorrect-on) @@ -1054,10 +1055,13 @@ Logs you in to your Shopify account. ``` USAGE - $ shopify auth login [--alias ] + $ shopify auth login [--alias ] [--no-polling] [--resume] FLAGS --alias= [env: SHOPIFY_FLAG_AUTH_ALIAS] Alias of the session you want to login to. + --no-polling [env: SHOPIFY_FLAG_AUTH_NO_POLLING] Start the login flow without polling. Prints the auth URL and + exits immediately. + --resume [env: SHOPIFY_FLAG_AUTH_RESUME] Resume a previously started login flow. DESCRIPTION Logs you in to your Shopify account. @@ -1075,6 +1079,18 @@ DESCRIPTION Logs you out of the Shopify account or Partner account and store. ``` +## `shopify auth whoami` + +Displays the currently logged-in Shopify account. + +``` +USAGE + $ shopify auth whoami + +DESCRIPTION + Displays the currently logged-in Shopify account. +``` + ## `shopify commands` List all shopify commands. diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index 329f37fb024..3e962066b43 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -179,7 +179,1860 @@ "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Cancel a bulk operation." + "summary": "Cancel a bulk operation.", + "customPluginName": "@shopify/app" + }, + "app:bulk:status": { + "aliases": [], + "args": {}, + "description": "Check the status of a specific bulk operation by ID, or list all bulk operations belonging to this app on this store in the last 7 days.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about \"bulk query operations\" (https://shopify.dev/docs/api/usage/bulk-operations/queries) and \"bulk mutation operations\" (https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use \"`bulk execute`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) to start a new bulk operation.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "id": { + "description": "The bulk operation ID (numeric ID or full GID). If not provided, lists all bulk operations belonging to this app on this store in the last 7 days.", + "env": "SHOPIFY_FLAG_ID", + "name": "id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "store": { + "char": "s", + "description": "The store domain. Must be an existing dev store.", + "env": "SHOPIFY_FLAG_STORE", + "name": "store", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:bulk:status", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Check the status of bulk operations.", + "descriptionWithMarkdown": "Check the status of a specific bulk operation by ID, or list all bulk operations belonging to this app on this store in the last 7 days.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about [bulk query operations](https://shopify.dev/docs/api/usage/bulk-operations/queries) and [bulk mutation operations](https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use [`bulk execute`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) to start a new bulk operation.", + "customPluginName": "@shopify/app" + }, + "app:config:validate": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", + "descriptionWithMarkdown": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:config:validate", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Validate your app configuration and extensions." + }, + "app:deploy": { + "aliases": [], + "args": {}, + "description": "\"Builds the app\" (https://shopify.dev/docs/api/shopify-cli/app/app-build), then deploys your app configuration and extensions.\n\n This command creates an app version, which is a snapshot of your app configuration and all extensions. This version is then released to users.\n\n This command doesn't deploy your \"web app\" (https://shopify.dev/docs/apps/tools/cli/structure#web-components). You need to \"deploy your web app\" (https://shopify.dev/docs/apps/deployment/web) to your own hosting solution.\n ", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "force": { + "char": "f", + "description": "[Deprecated] Deploy without asking for confirmation. Equivalent to --allow-updates --allow-deletes. Use --allow-updates for CI/CD environments instead.", + "env": "SHOPIFY_FLAG_FORCE", + "hidden": false, + "name": "force", + "allowNo": false, + "type": "boolean" + }, + "allow-updates": { + "description": "Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.", + "env": "SHOPIFY_FLAG_ALLOW_UPDATES", + "hidden": false, + "name": "allow-updates", + "allowNo": false, + "type": "boolean" + }, + "allow-deletes": { + "description": "Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.", + "env": "SHOPIFY_FLAG_ALLOW_DELETES", + "hidden": false, + "name": "allow-deletes", + "allowNo": false, + "type": "boolean" + }, + "no-release": { + "description": "Creates a version but doesn't release it - it's not made available to merchants. With this flag, a user confirmation is not required.", + "env": "SHOPIFY_FLAG_NO_RELEASE", + "exclusive": [ + "allow-updates", + "allow-deletes" + ], + "hidden": false, + "name": "no-release", + "allowNo": false, + "type": "boolean" + }, + "no-build": { + "description": "Use with caution: Skips building any elements of the app that require building. You should ensure your app has been prepared in advance, such as by running `shopify app build` or by caching build artifacts.", + "env": "SHOPIFY_FLAG_NO_BUILD", + "name": "no-build", + "allowNo": false, + "type": "boolean" + }, + "message": { + "description": "Optional message that will be associated with this version. This is for internal use only and won't be available externally.", + "env": "SHOPIFY_FLAG_MESSAGE", + "hidden": false, + "name": "message", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "version": { + "description": "Optional version tag that will be associated with this app version. If not provided, an auto-generated identifier will be generated for this app version.", + "env": "SHOPIFY_FLAG_VERSION", + "hidden": false, + "name": "version", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "source-control-url": { + "description": "URL associated with the new app version.", + "env": "SHOPIFY_FLAG_SOURCE_CONTROL_URL", + "hidden": false, + "name": "source-control-url", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:deploy", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Deploy your Shopify app.", + "descriptionWithMarkdown": "[Builds the app](https://shopify.dev/docs/api/shopify-cli/app/app-build), then deploys your app configuration and extensions.\n\n This command creates an app version, which is a snapshot of your app configuration and all extensions. This version is then released to users.\n\n This command doesn't deploy your [web app](https://shopify.dev/docs/apps/tools/cli/structure#web-components). You need to [deploy your web app](https://shopify.dev/docs/apps/deployment/web) to your own hosting solution.\n ", + "customPluginName": "@shopify/app" + }, + "app:dev": { + "aliases": [], + "args": {}, + "description": "Builds and previews your app on a dev store, and watches for changes. \"Read more about testing apps locally\" (https://shopify.dev/docs/apps/build/cli-for-apps/test-apps-locally).", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", + "env": "SHOPIFY_FLAG_STORE", + "name": "store", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "skip-dependencies-installation": { + "description": "Skips the installation of dependencies. Deprecated, use workspaces instead.", + "env": "SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION", + "name": "skip-dependencies-installation", + "allowNo": false, + "type": "boolean" + }, + "no-update": { + "description": "Uses the app URL from the toml file instead an autogenerated URL for dev.", + "env": "SHOPIFY_FLAG_NO_UPDATE", + "name": "no-update", + "allowNo": false, + "type": "boolean" + }, + "subscription-product-url": { + "description": "Resource URL for subscription UI extension. Format: \"/products/{productId}\"", + "env": "SHOPIFY_FLAG_SUBSCRIPTION_PRODUCT_URL", + "name": "subscription-product-url", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "checkout-cart-url": { + "description": "Resource URL for checkout UI extension. Format: \"/cart/{productVariantID}:{productQuantity}\"", + "env": "SHOPIFY_FLAG_CHECKOUT_CART_URL", + "name": "checkout-cart-url", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "tunnel-url": { + "description": "Use a custom tunnel, it must be running before executing dev. Format: \"https://my-tunnel-url:port\".", + "env": "SHOPIFY_FLAG_TUNNEL_URL", + "exclusive": [ + "tunnel" + ], + "name": "tunnel-url", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "use-localhost": { + "description": "Service entry point will listen to localhost. A tunnel won't be used. Will work for testing many app features, but not those that directly invoke your app (E.g: Webhooks)", + "env": "SHOPIFY_FLAG_USE_LOCALHOST", + "exclusive": [ + "tunnel-url" + ], + "name": "use-localhost", + "allowNo": false, + "type": "boolean" + }, + "localhost-port": { + "description": "Port to use for localhost.", + "env": "SHOPIFY_FLAG_LOCALHOST_PORT", + "name": "localhost-port", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "theme": { + "char": "t", + "description": "Theme ID or name of the theme app extension host theme.", + "env": "SHOPIFY_FLAG_THEME", + "name": "theme", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "theme-app-extension-port": { + "description": "Local port of the theme app extension development server.", + "env": "SHOPIFY_FLAG_THEME_APP_EXTENSION_PORT", + "name": "theme-app-extension-port", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "notify": { + "description": "The file path or URL. The file path is to a file that you want updated on idle. The URL path is where you want a webhook posted to report on file changes.", + "env": "SHOPIFY_FLAG_NOTIFY", + "name": "notify", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "graphiql-port": { + "description": "Local port of the GraphiQL development server.", + "env": "SHOPIFY_FLAG_GRAPHIQL_PORT", + "hidden": true, + "name": "graphiql-port", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "graphiql-key": { + "description": "Key used to authenticate GraphiQL requests. By default, a key is automatically derived from the app secret. Use this flag to override with a custom key.", + "env": "SHOPIFY_FLAG_GRAPHIQL_KEY", + "hidden": true, + "name": "graphiql-key", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:dev", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Run the app.", + "descriptionWithMarkdown": "Builds and previews your app on a dev store, and watches for changes. [Read more about testing apps locally](https://shopify.dev/docs/apps/build/cli-for-apps/test-apps-locally).", + "customPluginName": "@shopify/app" + }, + "app:dev:clean": { + "aliases": [], + "args": {}, + "description": "Stop the dev preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development store.", + "env": "SHOPIFY_FLAG_STORE", + "hidden": false, + "name": "store", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:dev:clean", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Cleans up the dev preview from the selected store.", + "descriptionWithMarkdown": "Stop the dev preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ", + "customPluginName": "@shopify/app" + }, + "app:logs": { + "aliases": [], + "args": {}, + "description": "\n Opens a real-time stream of detailed app logs from the selected app and store.\n Use the `--source` argument to limit output to a particular log source, such as a specific Shopify Function handle. Use the `shopify app logs sources` command to view a list of sources.\n Use the `--status` argument to filter on status, either `success` or `failure`.\n ```\n shopify app logs --status=success --source=extension.discount-function\n ```\n ", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "json": { + "char": "j", + "description": "Output the result as JSON.", + "env": "SHOPIFY_FLAG_JSON", + "hidden": false, + "name": "json", + "allowNo": false, + "type": "boolean" + }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", + "env": "SHOPIFY_FLAG_STORE", + "name": "store", + "hasDynamicHelp": false, + "multiple": true, + "type": "option" + }, + "source": { + "description": "Filters output to the specified log source.", + "env": "SHOPIFY_FLAG_SOURCE", + "name": "source", + "hasDynamicHelp": false, + "multiple": true, + "type": "option" + }, + "status": { + "description": "Filters output to the specified status (success or failure).", + "env": "SHOPIFY_FLAG_STATUS", + "name": "status", + "hasDynamicHelp": false, + "multiple": false, + "options": [ + "success", + "failure" + ], + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:logs", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Stream detailed logs for your Shopify app.", + "descriptionWithMarkdown": "\n Opens a real-time stream of detailed app logs from the selected app and store.\n Use the `--source` argument to limit output to a particular log source, such as a specific Shopify Function handle. Use the `shopify app logs sources` command to view a list of sources.\n Use the `--status` argument to filter on status, either `success` or `failure`.\n ```\n shopify app logs --status=success --source=extension.discount-function\n ```\n ", + "customPluginName": "@shopify/app" + }, + "app:logs:sources": { + "aliases": [], + "args": {}, + "description": "The output source names can be used with the `--source` argument of `shopify app logs` to filter log output. Currently only function extensions are supported as sources.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:logs:sources", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Print out a list of sources that may be used with the logs command.", + "descriptionWithMarkdown": "The output source names can be used with the `--source` argument of `shopify app logs` to filter log output. Currently only function extensions are supported as sources.", + "customPluginName": "@shopify/app" + }, + "app:import-custom-data-definitions": { + "aliases": [], + "args": {}, + "description": "Import metafield and metaobject definitions from your development store. \"Read more about declarative custom data definitions\" (https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions).", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", + "env": "SHOPIFY_FLAG_STORE", + "name": "store", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "include-existing": { + "description": "Include existing declared definitions in the output.", + "env": "SHOPIFY_FLAG_INCLUDE_EXISTING", + "name": "include-existing", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:import-custom-data-definitions", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Import metafield and metaobject definitions.", + "descriptionWithMarkdown": "Import metafield and metaobject definitions from your development store. [Read more about declarative custom data definitions](https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions).", + "customPluginName": "@shopify/app" + }, + "app:import-extensions": { + "aliases": [], + "args": {}, + "description": "Import dashboard-managed extensions into your app.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:import-extensions", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "customPluginName": "@shopify/app" + }, + "app:info": { + "aliases": [], + "args": {}, + "description": "The information returned includes the following:\n\n - The app and dev store that's used when you run the \"dev\" (https://shopify.dev/docs/api/shopify-cli/app/app-dev) command. You can reset these configurations using \"`dev --reset`\" (https://shopify.dev/docs/api/shopify-cli/app/app-dev#flags-propertydetail-reset).\n - The \"structure\" (https://shopify.dev/docs/apps/tools/cli/structure) of your app project.\n - The \"access scopes\" (https://shopify.dev/docs/api/usage) your app has requested.\n - System information, including the package manager and version of Shopify CLI used in the project.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "json": { + "char": "j", + "description": "Output the result as JSON.", + "env": "SHOPIFY_FLAG_JSON", + "hidden": false, + "name": "json", + "allowNo": false, + "type": "boolean" + }, + "web-env": { + "description": "Outputs environment variables necessary for running and deploying web/.", + "env": "SHOPIFY_FLAG_OUTPUT_WEB_ENV", + "hidden": false, + "name": "web-env", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:info", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Print basic information about your app and extensions.", + "descriptionWithMarkdown": "The information returned includes the following:\n\n - The app and dev store that's used when you run the [dev](https://shopify.dev/docs/api/shopify-cli/app/app-dev) command. You can reset these configurations using [`dev --reset`](https://shopify.dev/docs/api/shopify-cli/app/app-dev#flags-propertydetail-reset).\n - The [structure](https://shopify.dev/docs/apps/tools/cli/structure) of your app project.\n - The [access scopes](https://shopify.dev/docs/api/usage) your app has requested.\n - System information, including the package manager and version of Shopify CLI used in the project.", + "customPluginName": "@shopify/app" + }, + "app:init": { + "aliases": [], + "args": {}, + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "name": { + "char": "n", + "description": "The name for the new app. When provided, skips the app selection prompt and creates a new app with this name.", + "env": "SHOPIFY_FLAG_NAME", + "hidden": false, + "name": "name", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "path": { + "char": "p", + "env": "SHOPIFY_FLAG_PATH", + "hidden": false, + "name": "path", + "default": "/Users/nickwesselman/src/shopify-cli/packages/cli", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "template": { + "description": "The app template. Accepts one of the following:\n - \n - Any GitHub repo with optional branch and subpath, e.g., https://github.com/Shopify//[subpath]#[branch]", + "env": "SHOPIFY_FLAG_TEMPLATE", + "name": "template", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "flavor": { + "description": "Which flavor of the given template to use.", + "env": "SHOPIFY_FLAG_TEMPLATE_FLAVOR", + "name": "flavor", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "package-manager": { + "char": "d", + "env": "SHOPIFY_FLAG_PACKAGE_MANAGER", + "hidden": false, + "name": "package-manager", + "hasDynamicHelp": false, + "multiple": false, + "options": [ + "npm", + "yarn", + "pnpm", + "bun" + ], + "type": "option" + }, + "local": { + "char": "l", + "env": "SHOPIFY_FLAG_LOCAL", + "hidden": true, + "name": "local", + "allowNo": false, + "type": "boolean" + }, + "client-id": { + "description": "The Client ID of your app. Use this to automatically link your new project to an existing app. Using this flag avoids the app selection prompt.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "organization-id": { + "description": "The organization ID. Your organization ID can be found in your Dev Dashboard URL: https://dev.shopify.com/dashboard/", + "env": "SHOPIFY_FLAG_ORGANIZATION_ID", + "exclusive": [ + "client-id" + ], + "hidden": false, + "name": "organization-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:init", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Create a new app project", + "customPluginName": "@shopify/app" + }, + "app:validate": { + "aliases": [], + "args": {}, + "description": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:validate", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Validate your app configuration and extensions.", + "descriptionWithMarkdown": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", + "customPluginName": "@shopify/app" + }, + "app:release": { + "aliases": [], + "args": {}, + "description": "Releases an existing app version. Pass the name of the version that you want to release using the `--version` flag.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "force": { + "char": "f", + "description": "[Deprecated] Release without asking for confirmation. Equivalent to --allow-updates --allow-deletes. Use --allow-updates for CI/CD environments instead.", + "env": "SHOPIFY_FLAG_FORCE", + "hidden": false, + "name": "force", + "allowNo": false, + "type": "boolean" + }, + "allow-updates": { + "description": "Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.", + "env": "SHOPIFY_FLAG_ALLOW_UPDATES", + "hidden": false, + "name": "allow-updates", + "allowNo": false, + "type": "boolean" + }, + "allow-deletes": { + "description": "Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.", + "env": "SHOPIFY_FLAG_ALLOW_DELETES", + "hidden": false, + "name": "allow-deletes", + "allowNo": false, + "type": "boolean" + }, + "version": { + "description": "The name of the app version to release.", + "env": "SHOPIFY_FLAG_VERSION", + "hidden": false, + "name": "version", + "required": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:release", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Release an app version.", + "usage": "app release --version ", + "descriptionWithMarkdown": "Releases an existing app version. Pass the name of the version that you want to release using the `--version` flag.", + "customPluginName": "@shopify/app" + }, + "app:config:link": { + "aliases": [], + "args": {}, + "description": "Pulls app configuration from the Developer Dashboard and creates or overwrites a configuration file. You can create a new app with this command to start with a default configuration file.\n\n For more information on the format of the created TOML configuration file, refer to the \"App configuration\" (https://shopify.dev/docs/apps/tools/cli/configuration) page.\n ", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:config:link", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Fetch your app configuration from the Developer Dashboard.", + "descriptionWithMarkdown": "Pulls app configuration from the Developer Dashboard and creates or overwrites a configuration file. You can create a new app with this command to start with a default configuration file.\n\n For more information on the format of the created TOML configuration file, refer to the [App configuration](https://shopify.dev/docs/apps/tools/cli/configuration) page.\n ", + "customPluginName": "@shopify/app" + }, + "app:config:use": { + "aliases": [], + "args": { + "config": { + "description": "The name of the app configuration. Can be 'shopify.app.staging.toml' or simply 'staging'.", + "name": "config" + } + }, + "description": "Sets default configuration when you run app-related CLI commands. If you omit the `config-name` parameter, then you'll be prompted to choose from the configuration files in your project.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:config:use", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Activate an app configuration.", + "usage": "app config use [config] [flags]", + "descriptionWithMarkdown": "Sets default configuration when you run app-related CLI commands. If you omit the `config-name` parameter, then you'll be prompted to choose from the configuration files in your project.", + "customPluginName": "@shopify/app" + }, + "app:config:pull": { + "aliases": [], + "args": {}, + "description": "Pulls the latest configuration from the already-linked Shopify app and updates the selected configuration file.\n\nThis command reuses the existing linked app and organization and skips all interactive prompts. Use `--config` to target a specific configuration file, or omit it to use the default one.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:config:pull", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Refresh an already-linked app configuration without prompts.", + "descriptionWithMarkdown": "Pulls the latest configuration from the already-linked Shopify app and updates the selected configuration file.\n\nThis command reuses the existing linked app and organization and skips all interactive prompts. Use `--config` to target a specific configuration file, or omit it to use the default one.", + "customPluginName": "@shopify/app" + }, + "app:env:pull": { + "aliases": [], + "args": {}, + "description": "Creates or updates an `.env` files that contains app and app extension environment variables.\n\n When an existing `.env` file is updated, changes to the variables are displayed in the terminal output. Existing variables and commented variables are preserved.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "env-file": { + "description": "Specify an environment file to update if the update flag is set", + "env": "SHOPIFY_FLAG_ENV_FILE", + "hidden": false, + "name": "env-file", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:env:pull", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Pull app and extensions environment variables.", + "descriptionWithMarkdown": "Creates or updates an `.env` files that contains app and app extension environment variables.\n\n When an existing `.env` file is updated, changes to the variables are displayed in the terminal output. Existing variables and commented variables are preserved.", + "customPluginName": "@shopify/app" + }, + "app:env:show": { + "aliases": [], + "args": {}, + "description": "Displays environment variables that can be used to deploy apps and app extensions.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:env:show", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Display app and extensions environment variables.", + "descriptionWithMarkdown": "Displays environment variables that can be used to deploy apps and app extensions.", + "customPluginName": "@shopify/app" + }, + "app:execute": { + "aliases": [], + "args": {}, + "description": "Executes an Admin API GraphQL query or mutation on the specified store. Mutations are only allowed on dev stores.\n\n For operations that process large amounts of data, use \"`bulk execute`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) instead.", + "flags": { + "no-color": { + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "allowNo": false, + "type": "boolean" + }, + "verbose": { + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "allowNo": false, + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "name": "path", + "noCacheDefault": true, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hidden": false, + "name": "config", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "client-id", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "reset": { + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "allowNo": false, + "type": "boolean" + }, + "query": { + "char": "q", + "description": "The GraphQL query or mutation, as a string.", + "env": "SHOPIFY_FLAG_QUERY", + "name": "query", + "required": false, + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "query-file": { + "description": "Path to a file containing the GraphQL query or mutation. Can't be used with --query.", + "env": "SHOPIFY_FLAG_QUERY_FILE", + "name": "query-file", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "variables": { + "char": "v", + "description": "The values for any GraphQL variables in your query or mutation, in JSON format.", + "env": "SHOPIFY_FLAG_VARIABLES", + "exclusive": [ + "variable-file" + ], + "name": "variables", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "variable-file": { + "description": "Path to a file containing GraphQL variables in JSON format. Can't be used with --variables.", + "env": "SHOPIFY_FLAG_VARIABLE_FILE", + "exclusive": [ + "variables" + ], + "name": "variable-file", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "store": { + "char": "s", + "description": "The myshopify.com domain of the store to execute against. The app must be installed on the store. If not specified, you will be prompted to select a store.", + "env": "SHOPIFY_FLAG_STORE", + "name": "store", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "version": { + "description": "The API version to use for the query or mutation. Defaults to the latest stable version.", + "env": "SHOPIFY_FLAG_VERSION", + "name": "version", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, + "output-file": { + "description": "The file name where results should be written, instead of STDOUT.", + "env": "SHOPIFY_FLAG_OUTPUT_FILE", + "name": "output-file", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [], + "id": "app:execute", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Execute GraphQL queries and mutations.", + "descriptionWithMarkdown": "Executes an Admin API GraphQL query or mutation on the specified store. Mutations are only allowed on dev stores.\n\n For operations that process large amounts of data, use [`bulk execute`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) instead.", + "customPluginName": "@shopify/app" }, "app:bulk:execute": { "aliases": [ @@ -187,9 +2040,644 @@ "args": { }, "customPluginName": "@shopify/app", - "description": "Executes an Admin API GraphQL query or mutation on the specified store, as a bulk operation. Mutations are only allowed on dev stores.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about \"bulk query operations\" (https://shopify.dev/docs/api/usage/bulk-operations/queries) and \"bulk mutation operations\" (https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use \"`bulk status`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-status) to check the status of your bulk operations.", - "descriptionWithMarkdown": "Executes an Admin API GraphQL query or mutation on the specified store, as a bulk operation. Mutations are only allowed on dev stores.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about [bulk query operations](https://shopify.dev/docs/api/usage/bulk-operations/queries) and [bulk mutation operations](https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use [`bulk status`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-status) to check the status of your bulk operations.", + "description": "Executes an Admin API GraphQL query or mutation on the specified store, as a bulk operation. Mutations are only allowed on dev stores.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about \"bulk query operations\" (https://shopify.dev/docs/api/usage/bulk-operations/queries) and \"bulk mutation operations\" (https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use \"`bulk status`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-status) to check the status of your bulk operations.", + "descriptionWithMarkdown": "Executes an Admin API GraphQL query or mutation on the specified store, as a bulk operation. Mutations are only allowed on dev stores.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about [bulk query operations](https://shopify.dev/docs/api/usage/bulk-operations/queries) and [bulk mutation operations](https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use [`bulk status`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-status) to check the status of your bulk operations.", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "output-file": { + "dependsOn": [ + "watch" + ], + "description": "The file path where results should be written if --watch is specified. If not specified, results will be written to STDOUT.", + "env": "SHOPIFY_FLAG_OUTPUT_FILE", + "hasDynamicHelp": false, + "multiple": false, + "name": "output-file", + "type": "option" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "query": { + "char": "q", + "description": "The GraphQL query or mutation to run as a bulk operation.", + "env": "SHOPIFY_FLAG_QUERY", + "hasDynamicHelp": false, + "multiple": false, + "name": "query", + "required": false, + "type": "option" + }, + "query-file": { + "description": "Path to a file containing the GraphQL query or mutation. Can't be used with --query.", + "env": "SHOPIFY_FLAG_QUERY_FILE", + "hasDynamicHelp": false, + "multiple": false, + "name": "query-file", + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "store": { + "char": "s", + "description": "The store domain. Must be an existing dev store.", + "env": "SHOPIFY_FLAG_STORE", + "hasDynamicHelp": false, + "multiple": false, + "name": "store", + "type": "option" + }, + "variable-file": { + "description": "Path to a file containing GraphQL variables in JSONL format (one JSON object per line). Can't be used with --variables.", + "env": "SHOPIFY_FLAG_VARIABLE_FILE", + "exclusive": [ + "variables" + ], + "hasDynamicHelp": false, + "multiple": false, + "name": "variable-file", + "type": "option" + }, + "variables": { + "char": "v", + "description": "The values for any GraphQL variables in your mutation, in JSON format. Can be specified multiple times.", + "env": "SHOPIFY_FLAG_VARIABLES", + "exclusive": [ + "variable-file" + ], + "hasDynamicHelp": false, + "multiple": true, + "name": "variables", + "type": "option" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + }, + "version": { + "description": "The API version to use for the bulk operation. If not specified, uses the latest stable version.", + "env": "SHOPIFY_FLAG_VERSION", + "hasDynamicHelp": false, + "multiple": false, + "name": "version", + "type": "option" + }, + "watch": { + "allowNo": false, + "description": "Wait for bulk operation results before exiting. Defaults to false.", + "env": "SHOPIFY_FLAG_WATCH", + "name": "watch", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:bulk:execute", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Execute bulk operations." + }, + "app:bulk:status": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Check the status of a specific bulk operation by ID, or list all bulk operations belonging to this app on this store in the last 7 days.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about \"bulk query operations\" (https://shopify.dev/docs/api/usage/bulk-operations/queries) and \"bulk mutation operations\" (https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use \"`bulk execute`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) to start a new bulk operation.", + "descriptionWithMarkdown": "Check the status of a specific bulk operation by ID, or list all bulk operations belonging to this app on this store in the last 7 days.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about [bulk query operations](https://shopify.dev/docs/api/usage/bulk-operations/queries) and [bulk mutation operations](https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use [`bulk execute`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) to start a new bulk operation.", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "id": { + "description": "The bulk operation ID (numeric ID or full GID). If not provided, lists all bulk operations belonging to this app on this store in the last 7 days.", + "env": "SHOPIFY_FLAG_ID", + "hasDynamicHelp": false, + "multiple": false, + "name": "id", + "type": "option" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "store": { + "char": "s", + "description": "The store domain. Must be an existing dev store.", + "env": "SHOPIFY_FLAG_STORE", + "hasDynamicHelp": false, + "multiple": false, + "name": "store", + "type": "option" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:bulk:status", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Check the status of bulk operations." + }, + "app:config:link": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Pulls app configuration from the Developer Dashboard and creates or overwrites a configuration file. You can create a new app with this command to start with a default configuration file.\n\n For more information on the format of the created TOML configuration file, refer to the \"App configuration\" (https://shopify.dev/docs/apps/tools/cli/configuration) page.\n ", + "descriptionWithMarkdown": "Pulls app configuration from the Developer Dashboard and creates or overwrites a configuration file. You can create a new app with this command to start with a default configuration file.\n\n For more information on the format of the created TOML configuration file, refer to the [App configuration](https://shopify.dev/docs/apps/tools/cli/configuration) page.\n ", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:config:link", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Fetch your app configuration from the Developer Dashboard." + }, + "app:config:pull": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Pulls the latest configuration from the already-linked Shopify app and updates the selected configuration file.\n\nThis command reuses the existing linked app and organization and skips all interactive prompts. Use `--config` to target a specific configuration file, or omit it to use the default one.", + "descriptionWithMarkdown": "Pulls the latest configuration from the already-linked Shopify app and updates the selected configuration file.\n\nThis command reuses the existing linked app and organization and skips all interactive prompts. Use `--config` to target a specific configuration file, or omit it to use the default one.", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:config:pull", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Refresh an already-linked app configuration without prompts." + }, + "app:config:use": { + "aliases": [ + ], + "args": { + "config": { + "description": "The name of the app configuration. Can be 'shopify.app.staging.toml' or simply 'staging'.", + "name": "config" + } + }, + "customPluginName": "@shopify/app", + "description": "Sets default configuration when you run app-related CLI commands. If you omit the `config-name` parameter, then you'll be prompted to choose from the configuration files in your project.", + "descriptionWithMarkdown": "Sets default configuration when you run app-related CLI commands. If you omit the `config-name` parameter, then you'll be prompted to choose from the configuration files in your project.", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:config:use", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Activate an app configuration.", + "usage": "app config use [config] [flags]" + }, + "app:deploy": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "\"Builds the app\" (https://shopify.dev/docs/api/shopify-cli/app/app-build), then deploys your app configuration and extensions.\n\n This command creates an app version, which is a snapshot of your app configuration and all extensions. This version is then released to users.\n\n This command doesn't deploy your \"web app\" (https://shopify.dev/docs/apps/tools/cli/structure#web-components). You need to \"deploy your web app\" (https://shopify.dev/docs/apps/deployment/web) to your own hosting solution.\n ", + "descriptionWithMarkdown": "[Builds the app](https://shopify.dev/docs/api/shopify-cli/app/app-build), then deploys your app configuration and extensions.\n\n This command creates an app version, which is a snapshot of your app configuration and all extensions. This version is then released to users.\n\n This command doesn't deploy your [web app](https://shopify.dev/docs/apps/tools/cli/structure#web-components). You need to [deploy your web app](https://shopify.dev/docs/apps/deployment/web) to your own hosting solution.\n ", + "flags": { + "allow-deletes": { + "allowNo": false, + "description": "Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.", + "env": "SHOPIFY_FLAG_ALLOW_DELETES", + "hidden": false, + "name": "allow-deletes", + "type": "boolean" + }, + "allow-updates": { + "allowNo": false, + "description": "Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.", + "env": "SHOPIFY_FLAG_ALLOW_UPDATES", + "hidden": false, + "name": "allow-updates", + "type": "boolean" + }, + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "force": { + "allowNo": false, + "char": "f", + "description": "[Deprecated] Deploy without asking for confirmation. Equivalent to --allow-updates --allow-deletes. Use --allow-updates for CI/CD environments instead.", + "env": "SHOPIFY_FLAG_FORCE", + "hidden": false, + "name": "force", + "type": "boolean" + }, + "message": { + "description": "Optional message that will be associated with this version. This is for internal use only and won't be available externally.", + "env": "SHOPIFY_FLAG_MESSAGE", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "message", + "type": "option" + }, + "no-build": { + "allowNo": false, + "description": "Use with caution: Skips building any elements of the app that require building. You should ensure your app has been prepared in advance, such as by running `shopify app build` or by caching build artifacts.", + "env": "SHOPIFY_FLAG_NO_BUILD", + "name": "no-build", + "type": "boolean" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "no-release": { + "allowNo": false, + "description": "Creates a version but doesn't release it - it's not made available to merchants. With this flag, a user confirmation is not required.", + "env": "SHOPIFY_FLAG_NO_RELEASE", + "exclusive": [ + "allow-updates", + "allow-deletes" + ], + "hidden": false, + "name": "no-release", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "source-control-url": { + "description": "URL associated with the new app version.", + "env": "SHOPIFY_FLAG_SOURCE_CONTROL_URL", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "source-control-url", + "type": "option" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + }, + "version": { + "description": "Optional version tag that will be associated with this app version. If not provided, an auto-generated identifier will be generated for this app version.", + "env": "SHOPIFY_FLAG_VERSION", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "version", + "type": "option" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:deploy", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Deploy your Shopify app." + }, + "app:dev": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Builds and previews your app on a dev store, and watches for changes. \"Read more about testing apps locally\" (https://shopify.dev/docs/apps/build/cli-for-apps/test-apps-locally).", + "descriptionWithMarkdown": "Builds and previews your app on a dev store, and watches for changes. [Read more about testing apps locally](https://shopify.dev/docs/apps/build/cli-for-apps/test-apps-locally).", "flags": { + "checkout-cart-url": { + "description": "Resource URL for checkout UI extension. Format: \"/cart/{productVariantID}:{productQuantity}\"", + "env": "SHOPIFY_FLAG_CHECKOUT_CART_URL", + "hasDynamicHelp": false, + "multiple": false, + "name": "checkout-cart-url", + "type": "option" + }, "client-id": { "description": "The Client ID of your app.", "env": "SHOPIFY_FLAG_CLIENT_ID", @@ -212,6 +2700,32 @@ "name": "config", "type": "option" }, + "graphiql-key": { + "description": "Key used to authenticate GraphiQL requests. By default, a key is automatically derived from the app secret. Use this flag to override with a custom key.", + "env": "SHOPIFY_FLAG_GRAPHIQL_KEY", + "hasDynamicHelp": false, + "hidden": true, + "multiple": false, + "name": "graphiql-key", + "type": "option" + }, + "graphiql-port": { + "description": "Local port of the GraphiQL development server.", + "env": "SHOPIFY_FLAG_GRAPHIQL_PORT", + "hasDynamicHelp": false, + "hidden": true, + "multiple": false, + "name": "graphiql-port", + "type": "option" + }, + "localhost-port": { + "description": "Port to use for localhost.", + "env": "SHOPIFY_FLAG_LOCALHOST_PORT", + "hasDynamicHelp": false, + "multiple": false, + "name": "localhost-port", + "type": "option" + }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -220,15 +2734,19 @@ "name": "no-color", "type": "boolean" }, - "output-file": { - "dependsOn": [ - "watch" - ], - "description": "The file path where results should be written if --watch is specified. If not specified, results will be written to STDOUT.", - "env": "SHOPIFY_FLAG_OUTPUT_FILE", + "no-update": { + "allowNo": false, + "description": "Uses the app URL from the toml file instead an autogenerated URL for dev.", + "env": "SHOPIFY_FLAG_NO_UPDATE", + "name": "no-update", + "type": "boolean" + }, + "notify": { + "description": "The file path or URL. The file path is to a file that you want updated on idle. The URL path is where you want a webhook posted to report on file changes.", + "env": "SHOPIFY_FLAG_NOTIFY", "hasDynamicHelp": false, "multiple": false, - "name": "output-file", + "name": "notify", "type": "option" }, "path": { @@ -240,24 +2758,6 @@ "noCacheDefault": true, "type": "option" }, - "query": { - "char": "q", - "description": "The GraphQL query or mutation to run as a bulk operation.", - "env": "SHOPIFY_FLAG_QUERY", - "hasDynamicHelp": false, - "multiple": false, - "name": "query", - "required": false, - "type": "option" - }, - "query-file": { - "description": "Path to a file containing the GraphQL query or mutation. Can't be used with --query.", - "env": "SHOPIFY_FLAG_QUERY_FILE", - "hasDynamicHelp": false, - "multiple": false, - "name": "query-file", - "type": "option" - }, "reset": { "allowNo": false, "description": "Reset all your settings.", @@ -269,38 +2769,68 @@ "name": "reset", "type": "boolean" }, + "skip-dependencies-installation": { + "allowNo": false, + "description": "Skips the installation of dependencies. Deprecated, use workspaces instead.", + "env": "SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION", + "name": "skip-dependencies-installation", + "type": "boolean" + }, "store": { "char": "s", - "description": "The store domain. Must be an existing dev store.", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", "env": "SHOPIFY_FLAG_STORE", "hasDynamicHelp": false, "multiple": false, "name": "store", "type": "option" }, - "variable-file": { - "description": "Path to a file containing GraphQL variables in JSONL format (one JSON object per line). Can't be used with --variables.", - "env": "SHOPIFY_FLAG_VARIABLE_FILE", - "exclusive": [ - "variables" - ], + "subscription-product-url": { + "description": "Resource URL for subscription UI extension. Format: \"/products/{productId}\"", + "env": "SHOPIFY_FLAG_SUBSCRIPTION_PRODUCT_URL", "hasDynamicHelp": false, "multiple": false, - "name": "variable-file", + "name": "subscription-product-url", "type": "option" }, - "variables": { - "char": "v", - "description": "The values for any GraphQL variables in your mutation, in JSON format. Can be specified multiple times.", - "env": "SHOPIFY_FLAG_VARIABLES", + "theme": { + "char": "t", + "description": "Theme ID or name of the theme app extension host theme.", + "env": "SHOPIFY_FLAG_THEME", + "hasDynamicHelp": false, + "multiple": false, + "name": "theme", + "type": "option" + }, + "theme-app-extension-port": { + "description": "Local port of the theme app extension development server.", + "env": "SHOPIFY_FLAG_THEME_APP_EXTENSION_PORT", + "hasDynamicHelp": false, + "multiple": false, + "name": "theme-app-extension-port", + "type": "option" + }, + "tunnel-url": { + "description": "Use a custom tunnel, it must be running before executing dev. Format: \"https://my-tunnel-url:port\".", + "env": "SHOPIFY_FLAG_TUNNEL_URL", "exclusive": [ - "variable-file" + "tunnel" ], "hasDynamicHelp": false, - "multiple": true, - "name": "variables", + "multiple": false, + "name": "tunnel-url", "type": "option" }, + "use-localhost": { + "allowNo": false, + "description": "Service entry point will listen to localhost. A tunnel won't be used. Will work for testing many app features, but not those that directly invoke your app (E.g: Webhooks)", + "env": "SHOPIFY_FLAG_USE_LOCALHOST", + "exclusive": [ + "tunnel-url" + ], + "name": "use-localhost", + "type": "boolean" + }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -308,41 +2838,114 @@ "hidden": false, "name": "verbose", "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:dev", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Run the app." + }, + "app:dev:clean": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Stop the dev preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ", + "descriptionWithMarkdown": "Stop the dev preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" }, - "version": { - "description": "The API version to use for the bulk operation. If not specified, uses the latest stable version.", - "env": "SHOPIFY_FLAG_VERSION", + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", "hasDynamicHelp": false, + "hidden": false, "multiple": false, - "name": "version", + "name": "config", "type": "option" }, - "watch": { + "no-color": { "allowNo": false, - "description": "Wait for bulk operation results before exiting. Defaults to false.", - "env": "SHOPIFY_FLAG_WATCH", - "name": "watch", + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development store.", + "env": "SHOPIFY_FLAG_STORE", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "store", + "type": "option" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", "type": "boolean" } }, "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:bulk:execute", + "id": "app:dev:clean", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Execute bulk operations." + "summary": "Cleans up the dev preview from the selected store." }, - "app:bulk:status": { + "app:env:pull": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Check the status of a specific bulk operation by ID, or list all bulk operations belonging to this app on this store in the last 7 days.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about \"bulk query operations\" (https://shopify.dev/docs/api/usage/bulk-operations/queries) and \"bulk mutation operations\" (https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use \"`bulk execute`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) to start a new bulk operation.", - "descriptionWithMarkdown": "Check the status of a specific bulk operation by ID, or list all bulk operations belonging to this app on this store in the last 7 days.\n\n Bulk operations allow you to process large amounts of data asynchronously. Learn more about [bulk query operations](https://shopify.dev/docs/api/usage/bulk-operations/queries) and [bulk mutation operations](https://shopify.dev/docs/api/usage/bulk-operations/imports).\n\n Use [`bulk execute`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) to start a new bulk operation.", + "description": "Creates or updates an `.env` files that contains app and app extension environment variables.\n\n When an existing `.env` file is updated, changes to the variables are displayed in the terminal output. Existing variables and commented variables are preserved.", + "descriptionWithMarkdown": "Creates or updates an `.env` files that contains app and app extension environment variables.\n\n When an existing `.env` file is updated, changes to the variables are displayed in the terminal output. Existing variables and commented variables are preserved.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -366,12 +2969,13 @@ "name": "config", "type": "option" }, - "id": { - "description": "The bulk operation ID (numeric ID or full GID). If not provided, lists all bulk operations belonging to this app on this store in the last 7 days.", - "env": "SHOPIFY_FLAG_ID", + "env-file": { + "description": "Specify an environment file to update if the update flag is set", + "env": "SHOPIFY_FLAG_ENV_FILE", "hasDynamicHelp": false, + "hidden": false, "multiple": false, - "name": "id", + "name": "env-file", "type": "option" }, "no-color": { @@ -402,15 +3006,6 @@ "name": "reset", "type": "boolean" }, - "store": { - "char": "s", - "description": "The store domain. Must be an existing dev store.", - "env": "SHOPIFY_FLAG_STORE", - "hasDynamicHelp": false, - "multiple": false, - "name": "store", - "type": "option" - }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -423,21 +3018,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:bulk:status", + "id": "app:env:pull", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Check the status of bulk operations." + "summary": "Pull app and extensions environment variables." }, - "app:config:link": { + "app:env:show": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Pulls app configuration from the Developer Dashboard and creates or overwrites a configuration file. You can create a new app with this command to start with a default configuration file.\n\n For more information on the format of the created TOML configuration file, refer to the \"App configuration\" (https://shopify.dev/docs/apps/tools/cli/configuration) page.\n ", - "descriptionWithMarkdown": "Pulls app configuration from the Developer Dashboard and creates or overwrites a configuration file. You can create a new app with this command to start with a default configuration file.\n\n For more information on the format of the created TOML configuration file, refer to the [App configuration](https://shopify.dev/docs/apps/tools/cli/configuration) page.\n ", + "description": "Displays environment variables that can be used to deploy apps and app extensions.", + "descriptionWithMarkdown": "Displays environment variables that can be used to deploy apps and app extensions.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -501,21 +3096,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:config:link", + "id": "app:env:show", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Fetch your app configuration from the Developer Dashboard." + "summary": "Display app and extensions environment variables." }, - "app:config:pull": { + "app:execute": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Pulls the latest configuration from the already-linked Shopify app and updates the selected configuration file.\n\nThis command reuses the existing linked app and organization and skips all interactive prompts. Use `--config` to target a specific configuration file, or omit it to use the default one.", - "descriptionWithMarkdown": "Pulls the latest configuration from the already-linked Shopify app and updates the selected configuration file.\n\nThis command reuses the existing linked app and organization and skips all interactive prompts. Use `--config` to target a specific configuration file, or omit it to use the default one.", + "description": "Executes an Admin API GraphQL query or mutation on the specified store. Mutations are only allowed on dev stores.\n\n For operations that process large amounts of data, use \"`bulk execute`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) instead.", + "descriptionWithMarkdown": "Executes an Admin API GraphQL query or mutation on the specified store. Mutations are only allowed on dev stores.\n\n For operations that process large amounts of data, use [`bulk execute`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) instead.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -547,6 +3142,14 @@ "name": "no-color", "type": "boolean" }, + "output-file": { + "description": "The file name where results should be written, instead of STDOUT.", + "env": "SHOPIFY_FLAG_OUTPUT_FILE", + "hasDynamicHelp": false, + "multiple": false, + "name": "output-file", + "type": "option" + }, "path": { "description": "The path to your app directory.", "env": "SHOPIFY_FLAG_PATH", @@ -556,6 +3159,24 @@ "noCacheDefault": true, "type": "option" }, + "query": { + "char": "q", + "description": "The GraphQL query or mutation, as a string.", + "env": "SHOPIFY_FLAG_QUERY", + "hasDynamicHelp": false, + "multiple": false, + "name": "query", + "required": false, + "type": "option" + }, + "query-file": { + "description": "Path to a file containing the GraphQL query or mutation. Can't be used with --query.", + "env": "SHOPIFY_FLAG_QUERY_FILE", + "hasDynamicHelp": false, + "multiple": false, + "name": "query-file", + "type": "option" + }, "reset": { "allowNo": false, "description": "Reset all your settings.", @@ -567,6 +3188,38 @@ "name": "reset", "type": "boolean" }, + "store": { + "char": "s", + "description": "The myshopify.com domain of the store to execute against. The app must be installed on the store. If not specified, you will be prompted to select a store.", + "env": "SHOPIFY_FLAG_STORE", + "hasDynamicHelp": false, + "multiple": false, + "name": "store", + "type": "option" + }, + "variable-file": { + "description": "Path to a file containing GraphQL variables in JSON format. Can't be used with --variables.", + "env": "SHOPIFY_FLAG_VARIABLE_FILE", + "exclusive": [ + "variables" + ], + "hasDynamicHelp": false, + "multiple": false, + "name": "variable-file", + "type": "option" + }, + "variables": { + "char": "v", + "description": "The values for any GraphQL variables in your query or mutation, in JSON format.", + "env": "SHOPIFY_FLAG_VARIABLES", + "exclusive": [ + "variable-file" + ], + "hasDynamicHelp": false, + "multiple": false, + "name": "variables", + "type": "option" + }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -574,30 +3227,34 @@ "hidden": false, "name": "verbose", "type": "boolean" + }, + "version": { + "description": "The API version to use for the query or mutation. Defaults to the latest stable version.", + "env": "SHOPIFY_FLAG_VERSION", + "hasDynamicHelp": false, + "multiple": false, + "name": "version", + "type": "option" } }, "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:config:pull", + "id": "app:execute", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Refresh an already-linked app configuration without prompts." + "summary": "Execute GraphQL queries and mutations." }, - "app:config:use": { + "app:function:build": { "aliases": [ ], "args": { - "config": { - "description": "The name of the app configuration. Can be 'shopify.app.staging.toml' or simply 'staging'.", - "name": "config" - } }, "customPluginName": "@shopify/app", - "description": "Sets default configuration when you run app-related CLI commands. If you omit the `config-name` parameter, then you'll be prompted to choose from the configuration files in your project.", - "descriptionWithMarkdown": "Sets default configuration when you run app-related CLI commands. If you omit the `config-name` parameter, then you'll be prompted to choose from the configuration files in your project.", + "description": "Compiles the function in your current directory to WebAssembly (Wasm) for testing purposes.", + "descriptionWithMarkdown": "Compiles the function in your current directory to WebAssembly (Wasm) for testing purposes.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -611,6 +3268,16 @@ "name": "client-id", "type": "option" }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -620,9 +3287,10 @@ "type": "boolean" }, "path": { - "description": "The path to your app directory.", + "description": "The path to your function directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, + "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -651,22 +3319,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:config:use", + "id": "app:function:build", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Activate an app configuration.", - "usage": "app config use [config] [flags]" + "summary": "Compile a function to wasm." }, - "app:config:validate": { + "app:function:info": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", - "descriptionWithMarkdown": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", + "description": "The information returned includes the following:\n\n - The function handle\n - The function name\n - The function API version\n - The targeting configuration\n - The schema path\n - The WASM path\n - The function runner path", + "descriptionWithMarkdown": "The information returned includes the following:\n\n - The function handle\n - The function name\n - The function API version\n - The targeting configuration\n - The schema path\n - The WASM path\n - The function runner path", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -690,6 +3357,15 @@ "name": "config", "type": "option" }, + "json": { + "allowNo": false, + "char": "j", + "description": "Output the result as JSON.", + "env": "SHOPIFY_FLAG_JSON", + "hidden": false, + "name": "json", + "type": "boolean" + }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -699,9 +3375,10 @@ "type": "boolean" }, "path": { - "description": "The path to your app directory.", + "description": "The path to your function directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, + "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -730,38 +3407,22 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:config:validate", + "id": "app:function:info", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Validate your app configuration and extensions." + "summary": "Print basic information about your function." }, - "app:deploy": { + "app:function:replay": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "\"Builds the app\" (https://shopify.dev/docs/api/shopify-cli/app/app-build), then deploys your app configuration and extensions.\n\n This command creates an app version, which is a snapshot of your app configuration and all extensions. This version is then released to users.\n\n This command doesn't deploy your \"web app\" (https://shopify.dev/docs/apps/tools/cli/structure#web-components). You need to \"deploy your web app\" (https://shopify.dev/docs/apps/deployment/web) to your own hosting solution.\n ", - "descriptionWithMarkdown": "[Builds the app](https://shopify.dev/docs/api/shopify-cli/app/app-build), then deploys your app configuration and extensions.\n\n This command creates an app version, which is a snapshot of your app configuration and all extensions. This version is then released to users.\n\n This command doesn't deploy your [web app](https://shopify.dev/docs/apps/tools/cli/structure#web-components). You need to [deploy your web app](https://shopify.dev/docs/apps/deployment/web) to your own hosting solution.\n ", + "description": "Runs the function from your current directory for \"testing purposes\" (https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to \"Shopify Functions error handling\" (https://shopify.dev/docs/api/functions/errors).", + "descriptionWithMarkdown": "Runs the function from your current directory for [testing purposes](https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to [Shopify Functions error handling](https://shopify.dev/docs/api/functions/errors).", "flags": { - "allow-deletes": { - "allowNo": false, - "description": "Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.", - "env": "SHOPIFY_FLAG_ALLOW_DELETES", - "hidden": false, - "name": "allow-deletes", - "type": "boolean" - }, - "allow-updates": { - "allowNo": false, - "description": "Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.", - "env": "SHOPIFY_FLAG_ALLOW_UPDATES", - "hidden": false, - "name": "allow-updates", - "type": "boolean" - }, "client-id": { "description": "The Client ID of your app.", "env": "SHOPIFY_FLAG_CLIENT_ID", @@ -784,31 +3445,24 @@ "name": "config", "type": "option" }, - "force": { + "json": { "allowNo": false, - "char": "f", - "description": "[Deprecated] Deploy without asking for confirmation. Equivalent to --allow-updates --allow-deletes. Use --allow-updates for CI/CD environments instead.", - "env": "SHOPIFY_FLAG_FORCE", + "char": "j", + "description": "Output the result as JSON.", + "env": "SHOPIFY_FLAG_JSON", "hidden": false, - "name": "force", + "name": "json", "type": "boolean" }, - "message": { - "description": "Optional message that will be associated with this version. This is for internal use only and won't be available externally.", - "env": "SHOPIFY_FLAG_MESSAGE", + "log": { + "char": "l", + "description": "Specifies a log identifier to replay instead of selecting from a list. The identifier is provided in the output of `shopify app dev` and is the suffix of the log file name.", + "env": "SHOPIFY_FLAG_LOG", "hasDynamicHelp": false, - "hidden": false, "multiple": false, - "name": "message", + "name": "log", "type": "option" }, - "no-build": { - "allowNo": false, - "description": "Use with caution: Skips building any elements of the app that require building. You should ensure your app has been prepared in advance, such as by running `shopify app build` or by caching build artifacts.", - "env": "SHOPIFY_FLAG_NO_BUILD", - "name": "no-build", - "type": "boolean" - }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -817,22 +3471,11 @@ "name": "no-color", "type": "boolean" }, - "no-release": { - "allowNo": false, - "description": "Creates a version but doesn't release it - it's not made available to merchants. With this flag, a user confirmation is not required.", - "env": "SHOPIFY_FLAG_NO_RELEASE", - "exclusive": [ - "allow-updates", - "allow-deletes" - ], - "hidden": false, - "name": "no-release", - "type": "boolean" - }, "path": { - "description": "The path to your app directory.", + "description": "The path to your function directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, + "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -849,15 +3492,6 @@ "name": "reset", "type": "boolean" }, - "source-control-url": { - "description": "URL associated with the new app version.", - "env": "SHOPIFY_FLAG_SOURCE_CONTROL_URL", - "hasDynamicHelp": false, - "hidden": false, - "multiple": false, - "name": "source-control-url", - "type": "option" - }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -866,43 +3500,35 @@ "name": "verbose", "type": "boolean" }, - "version": { - "description": "Optional version tag that will be associated with this app version. If not provided, an auto-generated identifier will be generated for this app version.", - "env": "SHOPIFY_FLAG_VERSION", - "hasDynamicHelp": false, + "watch": { + "allowNo": true, + "char": "w", + "description": "Re-run the function when the source code changes.", + "env": "SHOPIFY_FLAG_WATCH", "hidden": false, - "multiple": false, - "name": "version", - "type": "option" + "name": "watch", + "type": "boolean" } }, "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:deploy", + "id": "app:function:replay", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Deploy your Shopify app." + "summary": "Replays a function run from an app log." }, - "app:dev": { + "app:function:run": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Builds and previews your app on a dev store, and watches for changes. \"Read more about testing apps locally\" (https://shopify.dev/docs/apps/build/cli-for-apps/test-apps-locally).", - "descriptionWithMarkdown": "Builds and previews your app on a dev store, and watches for changes. [Read more about testing apps locally](https://shopify.dev/docs/apps/build/cli-for-apps/test-apps-locally).", + "description": "Runs the function from your current directory for \"testing purposes\" (https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to \"Shopify Functions error handling\" (https://shopify.dev/docs/api/functions/errors).", + "descriptionWithMarkdown": "Runs the function from your current directory for [testing purposes](https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to [Shopify Functions error handling](https://shopify.dev/docs/api/functions/errors).", "flags": { - "checkout-cart-url": { - "description": "Resource URL for checkout UI extension. Format: \"/cart/{productVariantID}:{productQuantity}\"", - "env": "SHOPIFY_FLAG_CHECKOUT_CART_URL", - "hasDynamicHelp": false, - "multiple": false, - "name": "checkout-cart-url", - "type": "option" - }, "client-id": { "description": "The Client ID of your app.", "env": "SHOPIFY_FLAG_CLIENT_ID", @@ -925,32 +3551,34 @@ "name": "config", "type": "option" }, - "graphiql-key": { - "description": "Key used to authenticate GraphiQL requests. By default, a key is automatically derived from the app secret. Use this flag to override with a custom key.", - "env": "SHOPIFY_FLAG_GRAPHIQL_KEY", - "hasDynamicHelp": false, - "hidden": true, - "multiple": false, - "name": "graphiql-key", - "type": "option" - }, - "graphiql-port": { - "description": "Local port of the GraphiQL development server.", - "env": "SHOPIFY_FLAG_GRAPHIQL_PORT", + "export": { + "char": "e", + "description": "Name of the WebAssembly export to invoke.", + "env": "SHOPIFY_FLAG_EXPORT", "hasDynamicHelp": false, - "hidden": true, + "hidden": false, "multiple": false, - "name": "graphiql-port", + "name": "export", "type": "option" }, - "localhost-port": { - "description": "Port to use for localhost.", - "env": "SHOPIFY_FLAG_LOCALHOST_PORT", + "input": { + "char": "i", + "description": "The input JSON to pass to the function. If omitted, standard input is used.", + "env": "SHOPIFY_FLAG_INPUT", "hasDynamicHelp": false, "multiple": false, - "name": "localhost-port", + "name": "input", "type": "option" }, + "json": { + "allowNo": false, + "char": "j", + "description": "Output the result as JSON.", + "env": "SHOPIFY_FLAG_JSON", + "hidden": false, + "name": "json", + "type": "boolean" + }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -959,25 +3587,11 @@ "name": "no-color", "type": "boolean" }, - "no-update": { - "allowNo": false, - "description": "Uses the app URL from the toml file instead an autogenerated URL for dev.", - "env": "SHOPIFY_FLAG_NO_UPDATE", - "name": "no-update", - "type": "boolean" - }, - "notify": { - "description": "The file path or URL. The file path is to a file that you want updated on idle. The URL path is where you want a webhook posted to report on file changes.", - "env": "SHOPIFY_FLAG_NOTIFY", - "hasDynamicHelp": false, - "multiple": false, - "name": "notify", - "type": "option" - }, "path": { - "description": "The path to your app directory.", + "description": "The path to your function directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, + "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -994,68 +3608,6 @@ "name": "reset", "type": "boolean" }, - "skip-dependencies-installation": { - "allowNo": false, - "description": "Skips the installation of dependencies. Deprecated, use workspaces instead.", - "env": "SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION", - "name": "skip-dependencies-installation", - "type": "boolean" - }, - "store": { - "char": "s", - "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", - "env": "SHOPIFY_FLAG_STORE", - "hasDynamicHelp": false, - "multiple": false, - "name": "store", - "type": "option" - }, - "subscription-product-url": { - "description": "Resource URL for subscription UI extension. Format: \"/products/{productId}\"", - "env": "SHOPIFY_FLAG_SUBSCRIPTION_PRODUCT_URL", - "hasDynamicHelp": false, - "multiple": false, - "name": "subscription-product-url", - "type": "option" - }, - "theme": { - "char": "t", - "description": "Theme ID or name of the theme app extension host theme.", - "env": "SHOPIFY_FLAG_THEME", - "hasDynamicHelp": false, - "multiple": false, - "name": "theme", - "type": "option" - }, - "theme-app-extension-port": { - "description": "Local port of the theme app extension development server.", - "env": "SHOPIFY_FLAG_THEME_APP_EXTENSION_PORT", - "hasDynamicHelp": false, - "multiple": false, - "name": "theme-app-extension-port", - "type": "option" - }, - "tunnel-url": { - "description": "Use a custom tunnel, it must be running before executing dev. Format: \"https://my-tunnel-url:port\".", - "env": "SHOPIFY_FLAG_TUNNEL_URL", - "exclusive": [ - "tunnel" - ], - "hasDynamicHelp": false, - "multiple": false, - "name": "tunnel-url", - "type": "option" - }, - "use-localhost": { - "allowNo": false, - "description": "Service entry point will listen to localhost. A tunnel won't be used. Will work for testing many app features, but not those that directly invoke your app (E.g: Webhooks)", - "env": "SHOPIFY_FLAG_USE_LOCALHOST", - "exclusive": [ - "tunnel-url" - ], - "name": "use-localhost", - "type": "boolean" - }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -1068,21 +3620,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:dev", + "id": "app:function:run", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Run the app." + "summary": "Run a function locally for testing." }, - "app:dev:clean": { + "app:function:schema": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Stop the dev preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ", - "descriptionWithMarkdown": "Stop the dev preview that was started with `shopify app dev`.\n\n It restores the app's active version to the selected development store.\n ", + "description": "Generates the latest \"GraphQL schema\" (https://shopify.dev/docs/apps/functions/input-output#graphql-schema) for a function in your app. Run this command from the function directory.\n\n This command uses the API type and version of your function, as defined in your extension TOML file, to generate the latest GraphQL schema. The schema is written to the `schema.graphql` file.", + "descriptionWithMarkdown": "Generates the latest [GraphQL schema](https://shopify.dev/docs/apps/functions/input-output#graphql-schema) for a function in your app. Run this command from the function directory.\n\n This command uses the API type and version of your function, as defined in your extension TOML file, to generate the latest GraphQL schema. The schema is written to the `schema.graphql` file.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1115,9 +3667,10 @@ "type": "boolean" }, "path": { - "description": "The path to your app directory.", + "description": "The path to your function directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, + "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -1134,15 +3687,13 @@ "name": "reset", "type": "boolean" }, - "store": { - "char": "s", - "description": "Store URL. Must be an existing development store.", - "env": "SHOPIFY_FLAG_STORE", - "hasDynamicHelp": false, - "hidden": false, - "multiple": false, - "name": "store", - "type": "option" + "stdout": { + "allowNo": false, + "description": "Output the schema to stdout instead of writing to a file.", + "env": "SHOPIFY_FLAG_STDOUT", + "name": "stdout", + "required": false, + "type": "boolean" }, "verbose": { "allowNo": false, @@ -1156,21 +3707,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:dev:clean", + "id": "app:function:schema", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Cleans up the dev preview from the selected store." + "summary": "Fetch the latest GraphQL schema for a function." }, - "app:env:pull": { + "app:function:typegen": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Creates or updates an `.env` files that contains app and app extension environment variables.\n\n When an existing `.env` file is updated, changes to the variables are displayed in the terminal output. Existing variables and commented variables are preserved.", - "descriptionWithMarkdown": "Creates or updates an `.env` files that contains app and app extension environment variables.\n\n When an existing `.env` file is updated, changes to the variables are displayed in the terminal output. Existing variables and commented variables are preserved.", + "description": "Creates GraphQL types based on your \"input query\" (https://shopify.dev/docs/apps/functions/input-output#input) for a function. Supports JavaScript functions out of the box, or any language via the `build.typegen_command` configuration.", + "descriptionWithMarkdown": "Creates GraphQL types based on your [input query](https://shopify.dev/docs/apps/functions/input-output#input) for a function. Supports JavaScript functions out of the box, or any language via the `build.typegen_command` configuration.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1194,15 +3745,6 @@ "name": "config", "type": "option" }, - "env-file": { - "description": "Specify an environment file to update if the update flag is set", - "env": "SHOPIFY_FLAG_ENV_FILE", - "hasDynamicHelp": false, - "hidden": false, - "multiple": false, - "name": "env-file", - "type": "option" - }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -1212,9 +3754,10 @@ "type": "boolean" }, "path": { - "description": "The path to your app directory.", + "description": "The path to your function directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, + "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -1243,21 +3786,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:env:pull", + "id": "app:function:typegen", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Pull app and extensions environment variables." + "summary": "Generate GraphQL types for a function." }, - "app:env:show": { + "app:generate:extension": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Displays environment variables that can be used to deploy apps and app extensions.", - "descriptionWithMarkdown": "Displays environment variables that can be used to deploy apps and app extensions.", + "description": "Generates a new \"app extension\" (https://shopify.dev/docs/apps/build/app-extensions). For a list of app extensions that you can generate using this command, refer to \"Supported extensions\" (https://shopify.dev/docs/apps/build/app-extensions/list-of-app-extensions).\n\n Each new app extension is created in a folder under `extensions/`. To learn more about the extensions file structure, refer to \"App structure\" (https://shopify.dev/docs/apps/build/cli-for-apps/app-structure) and the documentation for your extension.\n ", + "descriptionWithMarkdown": "Generates a new [app extension](https://shopify.dev/docs/apps/build/app-extensions). For a list of app extensions that you can generate using this command, refer to [Supported extensions](https://shopify.dev/docs/apps/build/app-extensions/list-of-app-extensions).\n\n Each new app extension is created in a folder under `extensions/`. To learn more about the extensions file structure, refer to [App structure](https://shopify.dev/docs/apps/build/cli-for-apps/app-structure) and the documentation for your extension.\n ", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1271,6 +3814,16 @@ "name": "client-id", "type": "option" }, + "clone-url": { + "char": "u", + "description": "The Git URL to clone the function extensions templates from. Defaults to: https://github.com/Shopify/function-examples", + "env": "SHOPIFY_FLAG_CLONE_URL", + "hasDynamicHelp": false, + "hidden": true, + "multiple": false, + "name": "clone-url", + "type": "option" + }, "config": { "char": "c", "description": "The name of the app configuration.", @@ -1281,6 +3834,33 @@ "name": "config", "type": "option" }, + "flavor": { + "description": "Choose a starting template for your extension, where applicable", + "env": "SHOPIFY_FLAG_FLAVOR", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "flavor", + "options": [ + "vanilla-js", + "react", + "typescript", + "typescript-react", + "wasm", + "rust" + ], + "type": "option" + }, + "name": { + "char": "n", + "description": "name of your Extension", + "env": "SHOPIFY_FLAG_NAME", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "name", + "type": "option" + }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -1309,6 +3889,26 @@ "name": "reset", "type": "boolean" }, + "template": { + "char": "t", + "description": "Extension template", + "env": "SHOPIFY_FLAG_EXTENSION_TEMPLATE", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "template", + "type": "option" + }, + "type": { + "char": "t", + "description": "Deprecated. Please use --template", + "env": "SHOPIFY_FLAG_EXTENSION_TYPE", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "type", + "type": "option" + }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -1321,21 +3921,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:env:show", + "id": "app:generate:extension", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Display app and extensions environment variables." + "summary": "Generate a new app Extension." }, - "app:execute": { + "app:generate:schema": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Executes an Admin API GraphQL query or mutation on the specified store. Mutations are only allowed on dev stores.\n\n For operations that process large amounts of data, use \"`bulk execute`\" (https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) instead.", - "descriptionWithMarkdown": "Executes an Admin API GraphQL query or mutation on the specified store. Mutations are only allowed on dev stores.\n\n For operations that process large amounts of data, use [`bulk execute`](https://shopify.dev/docs/api/shopify-cli/app/app-bulk-execute) instead.", + "description": "\"DEPRECATED, use `app function schema`] Generates the latest [GraphQL schema\" (https://shopify.dev/docs/apps/functions/input-output#graphql-schema) for a function in your app. Run this command from the function directory.\n\n This command uses the API type and version of your function, as defined in your extension TOML file, to generate the latest GraphQL schema. The schema is written to the `schema.graphql` file.", + "descriptionWithMarkdown": "[DEPRECATED, use `app function schema`] Generates the latest [GraphQL schema](https://shopify.dev/docs/apps/functions/input-output#graphql-schema) for a function in your app. Run this command from the function directory.\n\n This command uses the API type and version of your function, as defined in your extension TOML file, to generate the latest GraphQL schema. The schema is written to the `schema.graphql` file.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1367,41 +3967,16 @@ "name": "no-color", "type": "boolean" }, - "output-file": { - "description": "The file name where results should be written, instead of STDOUT.", - "env": "SHOPIFY_FLAG_OUTPUT_FILE", - "hasDynamicHelp": false, - "multiple": false, - "name": "output-file", - "type": "option" - }, "path": { - "description": "The path to your app directory.", + "description": "The path to your function directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, + "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, "type": "option" }, - "query": { - "char": "q", - "description": "The GraphQL query or mutation, as a string.", - "env": "SHOPIFY_FLAG_QUERY", - "hasDynamicHelp": false, - "multiple": false, - "name": "query", - "required": false, - "type": "option" - }, - "query-file": { - "description": "Path to a file containing the GraphQL query or mutation. Can't be used with --query.", - "env": "SHOPIFY_FLAG_QUERY_FILE", - "hasDynamicHelp": false, - "multiple": false, - "name": "query-file", - "type": "option" - }, "reset": { "allowNo": false, "description": "Reset all your settings.", @@ -1413,37 +3988,13 @@ "name": "reset", "type": "boolean" }, - "store": { - "char": "s", - "description": "The myshopify.com domain of the store to execute against. The app must be installed on the store. If not specified, you will be prompted to select a store.", - "env": "SHOPIFY_FLAG_STORE", - "hasDynamicHelp": false, - "multiple": false, - "name": "store", - "type": "option" - }, - "variable-file": { - "description": "Path to a file containing GraphQL variables in JSON format. Can't be used with --variables.", - "env": "SHOPIFY_FLAG_VARIABLE_FILE", - "exclusive": [ - "variables" - ], - "hasDynamicHelp": false, - "multiple": false, - "name": "variable-file", - "type": "option" - }, - "variables": { - "char": "v", - "description": "The values for any GraphQL variables in your query or mutation, in JSON format.", - "env": "SHOPIFY_FLAG_VARIABLES", - "exclusive": [ - "variable-file" - ], - "hasDynamicHelp": false, - "multiple": false, - "name": "variables", - "type": "option" + "stdout": { + "allowNo": false, + "description": "Output the schema to stdout instead of writing to a file.", + "env": "SHOPIFY_FLAG_STDOUT", + "name": "stdout", + "required": false, + "type": "boolean" }, "verbose": { "allowNo": false, @@ -1452,34 +4003,26 @@ "hidden": false, "name": "verbose", "type": "boolean" - }, - "version": { - "description": "The API version to use for the query or mutation. Defaults to the latest stable version.", - "env": "SHOPIFY_FLAG_VERSION", - "hasDynamicHelp": false, - "multiple": false, - "name": "version", - "type": "option" } }, "hasDynamicHelp": false, + "hidden": true, "hiddenAliases": [ ], - "id": "app:execute", + "id": "app:generate:schema", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", - "strict": true, - "summary": "Execute GraphQL queries and mutations." + "summary": "Fetch the latest GraphQL schema for a function." }, - "app:function:build": { + "app:import-custom-data-definitions": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Compiles the function in your current directory to WebAssembly (Wasm) for testing purposes.", - "descriptionWithMarkdown": "Compiles the function in your current directory to WebAssembly (Wasm) for testing purposes.", + "description": "Import metafield and metaobject definitions from your development store. \"Read more about declarative custom data definitions\" (https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions).", + "descriptionWithMarkdown": "Import metafield and metaobject definitions from your development store. [Read more about declarative custom data definitions](https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions).", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1503,6 +4046,13 @@ "name": "config", "type": "option" }, + "include-existing": { + "allowNo": false, + "description": "Include existing declared definitions in the output.", + "env": "SHOPIFY_FLAG_INCLUDE_EXISTING", + "name": "include-existing", + "type": "boolean" + }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -1512,10 +4062,9 @@ "type": "boolean" }, "path": { - "description": "The path to your function directory.", + "description": "The path to your app directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, - "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -1532,6 +4081,15 @@ "name": "reset", "type": "boolean" }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", + "env": "SHOPIFY_FLAG_STORE", + "hasDynamicHelp": false, + "multiple": false, + "name": "store", + "type": "option" + }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -1544,21 +4102,20 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:function:build", + "id": "app:import-custom-data-definitions", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Compile a function to wasm." + "summary": "Import metafield and metaobject definitions." }, - "app:function:info": { + "app:import-extensions": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "The information returned includes the following:\n\n - The function handle\n - The function name\n - The function API version\n - The targeting configuration\n - The schema path\n - The WASM path\n - The function runner path", - "descriptionWithMarkdown": "The information returned includes the following:\n\n - The function handle\n - The function name\n - The function API version\n - The targeting configuration\n - The schema path\n - The WASM path\n - The function runner path", + "description": "Import dashboard-managed extensions into your app.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1582,15 +4139,6 @@ "name": "config", "type": "option" }, - "json": { - "allowNo": false, - "char": "j", - "description": "Output the result as JSON.", - "env": "SHOPIFY_FLAG_JSON", - "hidden": false, - "name": "json", - "type": "boolean" - }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -1600,10 +4148,9 @@ "type": "boolean" }, "path": { - "description": "The path to your function directory.", + "description": "The path to your app directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, - "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -1632,21 +4179,20 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:function:info", + "id": "app:import-extensions", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", - "strict": true, - "summary": "Print basic information about your function." + "strict": true }, - "app:function:replay": { + "app:info": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Runs the function from your current directory for \"testing purposes\" (https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to \"Shopify Functions error handling\" (https://shopify.dev/docs/api/functions/errors).", - "descriptionWithMarkdown": "Runs the function from your current directory for [testing purposes](https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to [Shopify Functions error handling](https://shopify.dev/docs/api/functions/errors).", + "description": "The information returned includes the following:\n\n - The app and dev store that's used when you run the \"dev\" (https://shopify.dev/docs/api/shopify-cli/app/app-dev) command. You can reset these configurations using \"`dev --reset`\" (https://shopify.dev/docs/api/shopify-cli/app/app-dev#flags-propertydetail-reset).\n - The \"structure\" (https://shopify.dev/docs/apps/tools/cli/structure) of your app project.\n - The \"access scopes\" (https://shopify.dev/docs/api/usage) your app has requested.\n - System information, including the package manager and version of Shopify CLI used in the project.", + "descriptionWithMarkdown": "The information returned includes the following:\n\n - The app and dev store that's used when you run the [dev](https://shopify.dev/docs/api/shopify-cli/app/app-dev) command. You can reset these configurations using [`dev --reset`](https://shopify.dev/docs/api/shopify-cli/app/app-dev#flags-propertydetail-reset).\n - The [structure](https://shopify.dev/docs/apps/tools/cli/structure) of your app project.\n - The [access scopes](https://shopify.dev/docs/api/usage) your app has requested.\n - System information, including the package manager and version of Shopify CLI used in the project.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1679,15 +4225,6 @@ "name": "json", "type": "boolean" }, - "log": { - "char": "l", - "description": "Specifies a log identifier to replay instead of selecting from a list. The identifier is provided in the output of `shopify app dev` and is the suffix of the log file name.", - "env": "SHOPIFY_FLAG_LOG", - "hasDynamicHelp": false, - "multiple": false, - "name": "log", - "type": "option" - }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -1697,10 +4234,9 @@ "type": "boolean" }, "path": { - "description": "The path to your function directory.", + "description": "The path to your app directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, - "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -1725,37 +4261,34 @@ "name": "verbose", "type": "boolean" }, - "watch": { - "allowNo": true, - "char": "w", - "description": "Re-run the function when the source code changes.", - "env": "SHOPIFY_FLAG_WATCH", + "web-env": { + "allowNo": false, + "description": "Outputs environment variables necessary for running and deploying web/.", + "env": "SHOPIFY_FLAG_OUTPUT_WEB_ENV", "hidden": false, - "name": "watch", + "name": "web-env", "type": "boolean" } }, "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:function:replay", + "id": "app:info", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Replays a function run from an app log." + "summary": "Print basic information about your app and extensions." }, - "app:function:run": { + "app:init": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Runs the function from your current directory for \"testing purposes\" (https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to \"Shopify Functions error handling\" (https://shopify.dev/docs/api/functions/errors).", - "descriptionWithMarkdown": "Runs the function from your current directory for [testing purposes](https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to [Shopify Functions error handling](https://shopify.dev/docs/api/functions/errors).", "flags": { "client-id": { - "description": "The Client ID of your app.", + "description": "The Client ID of your app. Use this to automatically link your new project to an existing app. Using this flag avoids the app selection prompt.", "env": "SHOPIFY_FLAG_CLIENT_ID", "exclusive": [ "config" @@ -1766,44 +4299,32 @@ "name": "client-id", "type": "option" }, - "config": { - "char": "c", - "description": "The name of the app configuration.", - "env": "SHOPIFY_FLAG_APP_CONFIG", + "flavor": { + "description": "Which flavor of the given template to use.", + "env": "SHOPIFY_FLAG_TEMPLATE_FLAVOR", "hasDynamicHelp": false, - "hidden": false, "multiple": false, - "name": "config", + "name": "flavor", "type": "option" }, - "export": { - "char": "e", - "description": "Name of the WebAssembly export to invoke.", - "env": "SHOPIFY_FLAG_EXPORT", - "hasDynamicHelp": false, - "hidden": false, - "multiple": false, - "name": "export", - "type": "option" + "local": { + "allowNo": false, + "char": "l", + "env": "SHOPIFY_FLAG_LOCAL", + "hidden": true, + "name": "local", + "type": "boolean" }, - "input": { - "char": "i", - "description": "The input JSON to pass to the function. If omitted, standard input is used.", - "env": "SHOPIFY_FLAG_INPUT", + "name": { + "char": "n", + "description": "The name for the new app. When provided, skips the app selection prompt and creates a new app with this name.", + "env": "SHOPIFY_FLAG_NAME", "hasDynamicHelp": false, + "hidden": false, "multiple": false, - "name": "input", + "name": "name", "type": "option" }, - "json": { - "allowNo": false, - "char": "j", - "description": "Output the result as JSON.", - "env": "SHOPIFY_FLAG_JSON", - "hidden": false, - "name": "json", - "type": "boolean" - }, "no-color": { "allowNo": false, "description": "Disable color output.", @@ -1812,26 +4333,50 @@ "name": "no-color", "type": "boolean" }, + "organization-id": { + "description": "The organization ID. Your organization ID can be found in your Dev Dashboard URL: https://dev.shopify.com/dashboard/", + "env": "SHOPIFY_FLAG_ORGANIZATION_ID", + "exclusive": [ + "client-id" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "organization-id", + "type": "option" + }, + "package-manager": { + "char": "d", + "env": "SHOPIFY_FLAG_PACKAGE_MANAGER", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "package-manager", + "options": [ + "npm", + "yarn", + "pnpm", + "bun" + ], + "type": "option" + }, "path": { - "description": "The path to your function directory.", + "char": "p", + "default": ".", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, "hidden": false, "multiple": false, "name": "path", - "noCacheDefault": true, "type": "option" }, - "reset": { - "allowNo": false, - "description": "Reset all your settings.", - "env": "SHOPIFY_FLAG_RESET", - "exclusive": [ - "config" - ], - "hidden": false, - "name": "reset", - "type": "boolean" + "template": { + "description": "The app template. Accepts one of the following:\n - \n - Any GitHub repo with optional branch and subpath, e.g., https://github.com/Shopify//[subpath]#[branch]", + "env": "SHOPIFY_FLAG_TEMPLATE", + "hasDynamicHelp": false, + "multiple": false, + "name": "template", + "type": "option" }, "verbose": { "allowNo": false, @@ -1845,21 +4390,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:function:run", + "id": "app:init", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Run a function locally for testing." + "summary": "Create a new app project" }, - "app:function:schema": { + "app:logs": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Generates the latest \"GraphQL schema\" (https://shopify.dev/docs/apps/functions/input-output#graphql-schema) for a function in your app. Run this command from the function directory.\n\n This command uses the API type and version of your function, as defined in your extension TOML file, to generate the latest GraphQL schema. The schema is written to the `schema.graphql` file.", - "descriptionWithMarkdown": "Generates the latest [GraphQL schema](https://shopify.dev/docs/apps/functions/input-output#graphql-schema) for a function in your app. Run this command from the function directory.\n\n This command uses the API type and version of your function, as defined in your extension TOML file, to generate the latest GraphQL schema. The schema is written to the `schema.graphql` file.", + "description": "\n Opens a real-time stream of detailed app logs from the selected app and store.\n Use the `--source` argument to limit output to a particular log source, such as a specific Shopify Function handle. Use the `shopify app logs sources` command to view a list of sources.\n Use the `--status` argument to filter on status, either `success` or `failure`.\n ```\n shopify app logs --status=success --source=extension.discount-function\n ```\n ", + "descriptionWithMarkdown": "\n Opens a real-time stream of detailed app logs from the selected app and store.\n Use the `--source` argument to limit output to a particular log source, such as a specific Shopify Function handle. Use the `shopify app logs sources` command to view a list of sources.\n Use the `--status` argument to filter on status, either `success` or `failure`.\n ```\n shopify app logs --status=success --source=extension.discount-function\n ```\n ", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1879,9 +4424,18 @@ "env": "SHOPIFY_FLAG_APP_CONFIG", "hasDynamicHelp": false, "hidden": false, - "multiple": false, - "name": "config", - "type": "option" + "multiple": false, + "name": "config", + "type": "option" + }, + "json": { + "allowNo": false, + "char": "j", + "description": "Output the result as JSON.", + "env": "SHOPIFY_FLAG_JSON", + "hidden": false, + "name": "json", + "type": "boolean" }, "no-color": { "allowNo": false, @@ -1892,10 +4446,9 @@ "type": "boolean" }, "path": { - "description": "The path to your function directory.", + "description": "The path to your app directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, - "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -1912,13 +4465,34 @@ "name": "reset", "type": "boolean" }, - "stdout": { - "allowNo": false, - "description": "Output the schema to stdout instead of writing to a file.", - "env": "SHOPIFY_FLAG_STDOUT", - "name": "stdout", - "required": false, - "type": "boolean" + "source": { + "description": "Filters output to the specified log source.", + "env": "SHOPIFY_FLAG_SOURCE", + "hasDynamicHelp": false, + "multiple": true, + "name": "source", + "type": "option" + }, + "status": { + "description": "Filters output to the specified status (success or failure).", + "env": "SHOPIFY_FLAG_STATUS", + "hasDynamicHelp": false, + "multiple": false, + "name": "status", + "options": [ + "success", + "failure" + ], + "type": "option" + }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", + "env": "SHOPIFY_FLAG_STORE", + "hasDynamicHelp": false, + "multiple": true, + "name": "store", + "type": "option" }, "verbose": { "allowNo": false, @@ -1932,21 +4506,21 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:function:schema", + "id": "app:logs", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Fetch the latest GraphQL schema for a function." + "summary": "Stream detailed logs for your Shopify app." }, - "app:function:typegen": { + "app:logs:sources": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Creates GraphQL types based on your \"input query\" (https://shopify.dev/docs/apps/functions/input-output#input) for a function. Supports JavaScript functions out of the box, or any language via the `build.typegen_command` configuration.", - "descriptionWithMarkdown": "Creates GraphQL types based on your [input query](https://shopify.dev/docs/apps/functions/input-output#input) for a function. Supports JavaScript functions out of the box, or any language via the `build.typegen_command` configuration.", + "description": "The output source names can be used with the `--source` argument of `shopify app logs` to filter log output. Currently only function extensions are supported as sources.", + "descriptionWithMarkdown": "The output source names can be used with the `--source` argument of `shopify app logs` to filter log output. Currently only function extensions are supported as sources.", "flags": { "client-id": { "description": "The Client ID of your app.", @@ -1979,10 +4553,9 @@ "type": "boolean" }, "path": { - "description": "The path to your function directory.", + "description": "The path to your app directory.", "env": "SHOPIFY_FLAG_PATH", "hasDynamicHelp": false, - "hidden": false, "multiple": false, "name": "path", "noCacheDefault": true, @@ -2011,22 +4584,38 @@ "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:function:typegen", + "id": "app:logs:sources", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Generate GraphQL types for a function." + "summary": "Print out a list of sources that may be used with the logs command." }, - "app:generate:extension": { + "app:release": { "aliases": [ ], "args": { }, "customPluginName": "@shopify/app", - "description": "Generates a new \"app extension\" (https://shopify.dev/docs/apps/build/app-extensions). For a list of app extensions that you can generate using this command, refer to \"Supported extensions\" (https://shopify.dev/docs/apps/build/app-extensions/list-of-app-extensions).\n\n Each new app extension is created in a folder under `extensions/`. To learn more about the extensions file structure, refer to \"App structure\" (https://shopify.dev/docs/apps/build/cli-for-apps/app-structure) and the documentation for your extension.\n ", - "descriptionWithMarkdown": "Generates a new [app extension](https://shopify.dev/docs/apps/build/app-extensions). For a list of app extensions that you can generate using this command, refer to [Supported extensions](https://shopify.dev/docs/apps/build/app-extensions/list-of-app-extensions).\n\n Each new app extension is created in a folder under `extensions/`. To learn more about the extensions file structure, refer to [App structure](https://shopify.dev/docs/apps/build/cli-for-apps/app-structure) and the documentation for your extension.\n ", + "description": "Releases an existing app version. Pass the name of the version that you want to release using the `--version` flag.", + "descriptionWithMarkdown": "Releases an existing app version. Pass the name of the version that you want to release using the `--version` flag.", "flags": { + "allow-deletes": { + "allowNo": false, + "description": "Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.", + "env": "SHOPIFY_FLAG_ALLOW_DELETES", + "hidden": false, + "name": "allow-deletes", + "type": "boolean" + }, + "allow-updates": { + "allowNo": false, + "description": "Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.", + "env": "SHOPIFY_FLAG_ALLOW_UPDATES", + "hidden": false, + "name": "allow-updates", + "type": "boolean" + }, "client-id": { "description": "The Client ID of your app.", "env": "SHOPIFY_FLAG_CLIENT_ID", @@ -2039,16 +4628,6 @@ "name": "client-id", "type": "option" }, - "clone-url": { - "char": "u", - "description": "The Git URL to clone the function extensions templates from. Defaults to: https://github.com/Shopify/function-examples", - "env": "SHOPIFY_FLAG_CLONE_URL", - "hasDynamicHelp": false, - "hidden": true, - "multiple": false, - "name": "clone-url", - "type": "option" - }, "config": { "char": "c", "description": "The name of the app configuration.", @@ -2059,32 +4638,14 @@ "name": "config", "type": "option" }, - "flavor": { - "description": "Choose a starting template for your extension, where applicable", - "env": "SHOPIFY_FLAG_FLAVOR", - "hasDynamicHelp": false, - "hidden": false, - "multiple": false, - "name": "flavor", - "options": [ - "vanilla-js", - "react", - "typescript", - "typescript-react", - "wasm", - "rust" - ], - "type": "option" - }, - "name": { - "char": "n", - "description": "name of your Extension", - "env": "SHOPIFY_FLAG_NAME", - "hasDynamicHelp": false, + "force": { + "allowNo": false, + "char": "f", + "description": "[Deprecated] Release without asking for confirmation. Equivalent to --allow-updates --allow-deletes. Use --allow-updates for CI/CD environments instead.", + "env": "SHOPIFY_FLAG_FORCE", "hidden": false, - "multiple": false, - "name": "name", - "type": "option" + "name": "force", + "type": "boolean" }, "no-color": { "allowNo": false, @@ -2114,26 +4675,6 @@ "name": "reset", "type": "boolean" }, - "template": { - "char": "t", - "description": "Extension template", - "env": "SHOPIFY_FLAG_EXTENSION_TEMPLATE", - "hasDynamicHelp": false, - "hidden": false, - "multiple": false, - "name": "template", - "type": "option" - }, - "type": { - "char": "t", - "description": "Deprecated. Please use --template", - "env": "SHOPIFY_FLAG_EXTENSION_TYPE", - "hasDynamicHelp": false, - "hidden": false, - "multiple": false, - "name": "type", - "type": "option" - }, "verbose": { "allowNo": false, "description": "Increase the verbosity of the output.", @@ -2141,17 +4682,28 @@ "hidden": false, "name": "verbose", "type": "boolean" + }, + "version": { + "description": "The name of the app version to release.", + "env": "SHOPIFY_FLAG_VERSION", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "version", + "required": true, + "type": "option" } }, "hasDynamicHelp": false, "hiddenAliases": [ ], - "id": "app:generate:extension", + "id": "app:release", "pluginAlias": "@shopify/cli", "pluginName": "@shopify/cli", "pluginType": "core", "strict": true, - "summary": "Generate a new app Extension." + "summary": "Release an app version.", + "usage": "app release --version " }, "app:generate:schema": { "aliases": [ @@ -2930,6 +5482,84 @@ "summary": "Release an app version.", "usage": "app release --version " }, + "app:validate": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", + "descriptionWithMarkdown": "Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:validate", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Validate your app configuration and extensions." + }, "app:versions:list": { "aliases": [ ], @@ -3168,6 +5798,20 @@ "multiple": false, "name": "alias", "type": "option" + }, + "no-polling": { + "allowNo": false, + "description": "Start the login flow without polling. Prints the auth URL and exits immediately.", + "env": "SHOPIFY_FLAG_AUTH_NO_POLLING", + "name": "no-polling", + "type": "boolean" + }, + "resume": { + "allowNo": false, + "description": "Resume a previously started login flow.", + "env": "SHOPIFY_FLAG_AUTH_RESUME", + "name": "resume", + "type": "boolean" } }, "hasDynamicHelp": false, @@ -3197,6 +5841,24 @@ "pluginType": "core", "strict": true }, + "auth:whoami": { + "aliases": [ + ], + "args": { + }, + "description": "Displays the currently logged-in Shopify account.", + "enableJsonFlag": false, + "flags": { + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "auth:whoami", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true + }, "cache:clear": { "aliases": [ ], diff --git a/packages/cli/src/cli/commands/auth/login.test.ts b/packages/cli/src/cli/commands/auth/login.test.ts index 29401713c58..845945d0ee2 100644 --- a/packages/cli/src/cli/commands/auth/login.test.ts +++ b/packages/cli/src/cli/commands/auth/login.test.ts @@ -1,9 +1,11 @@ import Login from './login.js' import {describe, expect, vi, test} from 'vitest' import {promptSessionSelect} from '@shopify/cli-kit/node/session-prompt' +import {startDeviceAuthNoPolling, resumeDeviceAuth} from '@shopify/cli-kit/node/session' import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' vi.mock('@shopify/cli-kit/node/session-prompt') +vi.mock('@shopify/cli-kit/node/session') describe('Login command', () => { test('runs login without alias flag', async () => { @@ -40,5 +42,81 @@ describe('Login command', () => { expect(flags.alias).toBeDefined() expect(flags.alias.description).toBe('Alias of the session you want to login to.') expect(flags.alias.env).toBe('SHOPIFY_FLAG_AUTH_ALIAS') + expect(flags['no-polling']).toBeDefined() + expect(flags.resume).toBeDefined() + }) + + test('--no-polling starts device auth and prints URL', async () => { + // Given + const outputMock = mockAndCaptureOutput() + vi.mocked(startDeviceAuthNoPolling).mockResolvedValue({ + verificationUriComplete: 'https://accounts.shopify.com/activate?user_code=ABCD-EFGH', + }) + + // When + await Login.run(['--no-polling']) + + // Then + expect(startDeviceAuthNoPolling).toHaveBeenCalledOnce() + expect(outputMock.info()).toMatch('shopify auth login --resume') + expect(promptSessionSelect).not.toHaveBeenCalled() + }) + + test('--resume succeeds and outputs alias', async () => { + // Given + const outputMock = mockAndCaptureOutput() + vi.mocked(resumeDeviceAuth).mockResolvedValue({status: 'success', alias: 'user@example.com'}) + + // When + await Login.run(['--resume']) + + // Then + expect(resumeDeviceAuth).toHaveBeenCalledOnce() + expect(outputMock.output()).toMatch('Logged in as: user@example.com') + }) + + test('--resume exits with error when authorization is still pending', async () => { + // Given + const outputMock = mockAndCaptureOutput() + vi.mocked(resumeDeviceAuth).mockResolvedValue({ + status: 'pending', + verificationUriComplete: 'https://accounts.shopify.com/activate?user_code=ABCD-EFGH', + }) + + // When + await expect(Login.run(['--resume'])).rejects.toThrow() + + // Then + expect(outputMock.error()).toMatch('Authorization is still pending.') + }) + + test('--resume exits with error when no pending auth exists', async () => { + // Given + const outputMock = mockAndCaptureOutput() + vi.mocked(resumeDeviceAuth).mockResolvedValue({ + status: 'no_pending', + message: 'No pending login flow. Run `shopify auth login --no-polling` first.', + }) + + // When + await expect(Login.run(['--resume'])).rejects.toThrow() + + // Then + expect(outputMock.error()).toMatch('No pending login flow.') + }) + + test('--resume exits with error when auth has expired', async () => { + // Given + const outputMock = mockAndCaptureOutput() + vi.mocked(resumeDeviceAuth).mockResolvedValue({ + status: 'expired', + message: 'The login flow has expired. Run `shopify auth login --no-polling` again.', + }) + + // When + await expect(Login.run(['--resume'])).rejects.toThrow() + + // Then + expect(outputMock.error()).toMatch('The login flow has expired.') }) }) diff --git a/packages/cli/src/cli/commands/auth/login.ts b/packages/cli/src/cli/commands/auth/login.ts index 992b311dd26..2a70790c613 100644 --- a/packages/cli/src/cli/commands/auth/login.ts +++ b/packages/cli/src/cli/commands/auth/login.ts @@ -1,7 +1,9 @@ import Command from '@shopify/cli-kit/node/base-command' import {promptSessionSelect} from '@shopify/cli-kit/node/session-prompt' +import {startDeviceAuthNoPolling, resumeDeviceAuth} from '@shopify/cli-kit/node/session' import {Flags} from '@oclif/core' -import {outputCompleted} from '@shopify/cli-kit/node/output' +import {outputCompleted, outputInfo} from '@shopify/cli-kit/node/output' +import {AbortError} from '@shopify/cli-kit/node/error' export default class Login extends Command { static description = 'Logs you in to your Shopify account.' @@ -11,10 +13,46 @@ export default class Login extends Command { description: 'Alias of the session you want to login to.', env: 'SHOPIFY_FLAG_AUTH_ALIAS', }), + 'no-polling': Flags.boolean({ + description: 'Start the login flow without polling. Prints the auth URL and exits immediately.', + default: false, + env: 'SHOPIFY_FLAG_AUTH_NO_POLLING', + }), + resume: Flags.boolean({ + description: 'Resume a previously started login flow.', + default: false, + env: 'SHOPIFY_FLAG_AUTH_RESUME', + }), } async run(): Promise { const {flags} = await this.parse(Login) + + if (flags['no-polling']) { + await startDeviceAuthNoPolling() + outputInfo('Run `shopify auth login --resume` to complete login after authorizing.') + return + } + + if (flags.resume) { + const result = await resumeDeviceAuth() + switch (result.status) { + case 'success': + outputCompleted(`Logged in as: ${result.alias}`) + return + case 'pending': + throw new AbortError( + 'Authorization is still pending.', + `Open ${result.verificationUriComplete} to authorize, then run \`shopify auth login --resume\` again.`, + ) + case 'expired': + case 'denied': + case 'no_pending': + throw new AbortError(result.message) + } + } + + // Default: interactive flow const result = await promptSessionSelect(flags.alias) outputCompleted(`Current account: ${result}.`) } diff --git a/packages/cli/src/cli/commands/auth/whoami.test.ts b/packages/cli/src/cli/commands/auth/whoami.test.ts new file mode 100644 index 00000000000..e87c2b32098 --- /dev/null +++ b/packages/cli/src/cli/commands/auth/whoami.test.ts @@ -0,0 +1,32 @@ +import Whoami from './whoami.js' +import {describe, expect, vi, test} from 'vitest' +import {getCurrentUserInfo} from '@shopify/cli-kit/node/session' +import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' + +vi.mock('@shopify/cli-kit/node/session') + +describe('Whoami command', () => { + test('outputs account alias when logged in', async () => { + // Given + const outputMock = mockAndCaptureOutput() + vi.mocked(getCurrentUserInfo).mockResolvedValue({alias: 'user@example.com'}) + + // When + await Whoami.run([]) + + // Then + expect(outputMock.info()).toMatch('Logged in as: user@example.com') + }) + + test('exits with error when not logged in', async () => { + // Given + const outputMock = mockAndCaptureOutput() + vi.mocked(getCurrentUserInfo).mockResolvedValue(undefined) + + // When + await expect(Whoami.run([])).rejects.toThrow() + + // Then + expect(outputMock.error()).toMatch('Not logged in.') + }) +}) diff --git a/packages/cli/src/cli/commands/auth/whoami.ts b/packages/cli/src/cli/commands/auth/whoami.ts new file mode 100644 index 00000000000..d2e035aa008 --- /dev/null +++ b/packages/cli/src/cli/commands/auth/whoami.ts @@ -0,0 +1,17 @@ +import Command from '@shopify/cli-kit/node/base-command' +import {getCurrentUserInfo} from '@shopify/cli-kit/node/session' +import {outputInfo} from '@shopify/cli-kit/node/output' +import {AbortError} from '@shopify/cli-kit/node/error' + +export default class Whoami extends Command { + static description = 'Displays the currently logged-in Shopify account.' + + async run(): Promise { + const userInfo = await getCurrentUserInfo() + if (userInfo) { + outputInfo(`Logged in as: ${userInfo.alias}`) + } else { + throw new AbortError('Not logged in.', 'Run `shopify auth login` to log in.') + } + } +} diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 4e762b6067d..3ec298714a4 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -4,6 +4,7 @@ import Search from './cli/commands/search.js' import Upgrade from './cli/commands/upgrade.js' import Logout from './cli/commands/auth/logout.js' import Login from './cli/commands/auth/login.js' +import Whoami from './cli/commands/auth/whoami.js' import CommandFlags from './cli/commands/debug/command-flags.js' import KitchenSinkAsync from './cli/commands/kitchen-sink/async.js' import KitchenSinkPrompts from './cli/commands/kitchen-sink/prompts.js' @@ -140,6 +141,7 @@ export const COMMANDS: any = { help: HelpCommand, 'auth:logout': Logout, 'auth:login': Login, + 'auth:whoami': Whoami, 'debug:command-flags': CommandFlags, 'kitchen-sink': KitchenSink, 'kitchen-sink:async': KitchenSinkAsync, diff --git a/packages/e2e/data/snapshots/commands.txt b/packages/e2e/data/snapshots/commands.txt index 0c727fc0868..b6c8a291c98 100644 --- a/packages/e2e/data/snapshots/commands.txt +++ b/packages/e2e/data/snapshots/commands.txt @@ -38,7 +38,8 @@ │ └─ trigger ├─ auth │ ├─ login -│ └─ logout +│ ├─ logout +│ └─ whoami ├─ commands ├─ config │ └─ autocorrect