diff --git a/.changeset/app-config-link-flags.md b/.changeset/app-config-link-flags.md new file mode 100644 index 00000000000..92080fe1041 --- /dev/null +++ b/.changeset/app-config-link-flags.md @@ -0,0 +1,5 @@ +--- +'@shopify/app': patch +--- + +Add `--client-id` and `--file-name` options to `app config link`. diff --git a/.changeset/auth-alias-command-context.md b/.changeset/auth-alias-command-context.md new file mode 100644 index 00000000000..6531170a092 --- /dev/null +++ b/.changeset/auth-alias-command-context.md @@ -0,0 +1,7 @@ +--- +'@shopify/app': patch +'@shopify/cli-kit': patch +'@shopify/theme': patch +--- + +Allow app and theme commands to authenticate with a Shopify account alias without changing the current CLI session. diff --git a/.changeset/friendly-theme-create-access-error.md b/.changeset/friendly-theme-create-access-error.md new file mode 100644 index 00000000000..3a0a35384da --- /dev/null +++ b/.changeset/friendly-theme-create-access-error.md @@ -0,0 +1,5 @@ +--- +'@shopify/cli-kit': patch +--- + +Show a friendly error when theme creation is denied by missing theme write access diff --git a/.changeset/unhide-store-auth-list.md b/.changeset/unhide-store-auth-list.md new file mode 100644 index 00000000000..a0ec18b0fe2 --- /dev/null +++ b/.changeset/unhide-store-auth-list.md @@ -0,0 +1,6 @@ +--- +'@shopify/cli': minor +'@shopify/store': minor +--- + +Add `shopify store auth list` to list stores authenticated on this machine with `shopify store auth`. diff --git a/.changeset/unhide-store-create-preview.md b/.changeset/unhide-store-create-preview.md new file mode 100644 index 00000000000..2d70e4f6600 --- /dev/null +++ b/.changeset/unhide-store-create-preview.md @@ -0,0 +1,6 @@ +--- +'@shopify/cli': minor +'@shopify/store': minor +--- + +Add `shopify store create preview` to create a preview Shopify store with no existing account required. diff --git a/.changeset/unhide-store-list.md b/.changeset/unhide-store-list.md new file mode 100644 index 00000000000..7f6546b85fd --- /dev/null +++ b/.changeset/unhide-store-list.md @@ -0,0 +1,6 @@ +--- +'@shopify/cli': minor +'@shopify/store': minor +--- + +Add `shopify store list` to list stores in a Shopify organization. diff --git a/.changeset/unhide-store-open.md b/.changeset/unhide-store-open.md new file mode 100644 index 00000000000..e825b3a3b96 --- /dev/null +++ b/.changeset/unhide-store-open.md @@ -0,0 +1,6 @@ +--- +'@shopify/cli': minor +'@shopify/store': minor +--- + +Add `shopify store open` to open a store's storefront in your default web browser. diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index b9571f8d97f..9bb47fa61d1 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,3 +1 @@ See @../AGENTS.md for repository-specific agent instructions. -See @../.cursor/rules/base.mdc for information on your desired behavior. -See @../.cursor/rules/docs.mdc for details on Shopify CLI architecture and conventions. diff --git a/.cursor/rules/base.mdc b/.cursor/rules/base.mdc index b71a2c4c08a..72181aab1cb 100644 --- a/.cursor/rules/base.mdc +++ b/.cursor/rules/base.mdc @@ -3,40 +3,4 @@ description: globs: alwaysApply: true --- -As a Principal Developer, the highest ranking engineer at our company, you are tasked with creating clear, readable code in Typescript. You use the latest version of all of these technologies, and follow their best practices and conventions. - -When responding to questions, follow the Chain of Thought method. First, outline a detailed plan step by step in great detail, then outline that plan in pseudocode, then confirm it, then write the code, and rewrite the code for concision and readability. - -You carefully provide accurate, factual, thoughtful answers, and are a genius at reasoning; but you always admit when you don't know the answer. - -Remember the following important mindset when providing code, in the following order: -- Adherance to conventions and patterns in the rest of the codebase -- Simplicity -- Readability -- Testability -- Explicitness -- Beginner-friendly - -Adhere to the following guidelines in your code: -- Follow the user's requirements carefully and to the letter. -- Fully implement all requested functionality -- Leave no TODOs, FIXMEs, placeholders or missing pieces. -- Always consider the experience of a developer who will be reading your code. -- Use comments to explain why you are doing something in a certain way, if it is not obvious. If unsure, leave a comment. -- Employ descriptive, human-readable variable and function/const names. -- Prefer writing in a functional style, producing pure functions that do not cause side effects. -- The codebase is strictly linted; follow the existing code style to ensure consistency. -- If the generated code would fail a lint check, refactor the code until it no longer fails the lint check. -- Search hard to find an existing function where possible. These are often in the @shopify/cli-kit library. -- Be sure to reference file names -- Be concise. Minimize any prose other than code. -- If you think there might not be a correct answer, say so. If you do not know the answer, say so instead of guessing. -- In tests, always avoid mocking the filesystem. Use real files and directories, in temporary directories if needed. -- In tests, prefer to have as little shared state between tests as possible. Avoid beforeAll and afterAll. - -Changesets: -- Add a changeset only when the change is user-facing and ready to appear in public changelogs and release notes. -- Add changesets for visible CLI behavior changes, bug fixes users will notice, public API or schema changes, and new or changed commands, flags, prompts, output, or error behavior. -- Keep changeset summaries short: one line maximum. -- Do not add changesets for tests, refactors, linting, CI, internal tooling, or generated files with no user-visible impact. -- If the change is not ready to be public, do not add a changeset. +See [AGENTS.md](mdc:AGENTS.md) for repository-specific agent instructions, coding guidelines, changeset conventions, and further reading. diff --git a/.cursor/rules/docs.mdc b/.cursor/rules/docs.mdc deleted file mode 100644 index d89157d02dc..00000000000 --- a/.cursor/rules/docs.mdc +++ /dev/null @@ -1,30 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- -### CLI - -[README.md](mdc:docs/README.md) -[architecture.md](mdc:docs/cli/architecture.md) -[conventions.md](mdc:docs/cli/conventions.md) -[cross-os-compatibility.md](mdc:docs/cli/cross-os-compatibility.md) -[debugging.md](mdc:docs/cli/debugging.md) -[eslint-rules.md](mdc:docs/cli/eslint-rules.md) -[faq.md](mdc:docs/cli/faq.md) -[get-started.md](mdc:docs/cli/get-started.md) -[naming-conventions.md](mdc:docs/cli/naming-conventions.md) -[performance.md](mdc:docs/cli/performance.md) -[testing-strategy.md](mdc:docs/cli/testing-strategy.md) -[troubleshooting.md](mdc:docs/cli/troubleshooting.md) - -### CLI kit - -[command-guidelines.md](mdc:docs/cli-kit/command-guidelines.md) -[errors.md](mdc:docs/cli-kit/errors.md) -[README.md](mdc:packages/cli/README.md) - -### UI kit -[contributing.md](mdc:docs/cli-kit/ui-kit/contributing.md) -[guidelines.md](mdc:docs/cli-kit/ui-kit/guidelines.md) -[readme.md](mdc:docs/cli-kit/ui-kit/readme.md) diff --git a/.gitignore b/.gitignore index 5bee3d7cdab..84de6f089f3 100644 --- a/.gitignore +++ b/.gitignore @@ -180,11 +180,11 @@ eslint-report.json # Generated docs docs/api +docs-shopify.dev/commands/interfaces/ vite.config.ts.timestamp* # from nested gitignores -packages/app/assets/dev-console packages/ui-extensions-server-kit/*.d.ts packages/ui-extensions-server-kit/!typings.d.ts packages/ui-extensions-server-kit/index.* @@ -195,12 +195,6 @@ packages/store/src/cli/api/graphql/business-platform-organizations/organizations packages/ui-extensions-test-utils/*.d.ts packages/ui-extensions-test-utils/!typings.d.ts packages/ui-extensions-test-utils/dist -packages/ui-extensions-dev-console/*.js -packages/ui-extensions-dev-console/*.d.ts -packages/ui-extensions-dev-console/!typings.d.ts -packages/ui-extensions-dev-console/.eslintrc.js -packages/ui-extensions-dev-console/css-transform.js -packages/ui-extensions-dev-console/dist packages/cli-kit/src/cli/api/graphql/*/*_schema.graphql packages/organizations/src/cli/api/graphql/*/*_schema.graphql packages/store/src/cli/api/graphql/*/*_schema.graphql diff --git a/AGENTS.md b/AGENTS.md index 39dc28408f7..3103b5ae408 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,38 @@ # Agent Instructions +As a Principal Developer, the highest ranking engineer at our company, you are tasked with creating clear, readable code in TypeScript. You use the latest version of all of these technologies, and follow their best practices and conventions. + +Match your planning to the complexity of the task. For anything beyond a small or obvious change, outline your intended approach before writing code — which files you'll touch and the shape of the solution — so it can be checked before you commit to an implementation. Keep this to a few sentences or bullets. For trivial changes, skip straight to the implementation. + +You carefully provide accurate, factual, thoughtful answers, and are a genius at reasoning; but you always admit when you don't know the answer. + +Remember the following important mindset when providing code, in the following order: +- Adherence to conventions and patterns in the rest of the codebase +- Simplicity +- Readability +- Testability +- Explicitness +- Beginner-friendly + +## Guidelines + +Adhere to the following guidelines in your code: +- Follow the user's requirements carefully and to the letter. +- Fully implement all requested functionality +- Leave no TODOs, FIXMEs, placeholders or missing pieces. +- Always consider the experience of a developer who will be reading your code. +- Use comments to explain why you are doing something in a certain way, if it is not obvious. If unsure, leave a comment. +- Employ descriptive, human-readable variable and function/const names. +- Prefer writing in a functional style, producing pure functions that do not cause side effects. +- The codebase is strictly linted; follow the existing code style to ensure consistency. +- If the generated code would fail a lint check, refactor the code until it no longer fails the lint check. +- Search hard to find an existing function where possible. These are often in the @shopify/cli-kit library. +- Be sure to reference file names +- Be concise. Minimize any prose other than code. +- If you think there might not be a correct answer, say so. If you do not know the answer, say so instead of guessing. +- In tests, always avoid mocking the filesystem. Use real files and directories, in temporary directories if needed. +- In tests, prefer to have as little shared state between tests as possible. Avoid beforeAll and afterAll. + ## Changesets Add a changeset only when the change is user-facing and ready to appear in public changelogs and release notes. @@ -11,3 +44,32 @@ Keep changeset summaries short: one line maximum. Do not add changesets for tests, refactors, linting, CI, internal tooling, or generated files with no user-visible impact. If the change is not ready to be public, do not add a changeset. + +## Further reading + +### CLI + +- [docs/README.md](docs/README.md) +- [docs/cli/architecture.md](docs/cli/architecture.md) +- [docs/cli/conventions.md](docs/cli/conventions.md) +- [docs/cli/cross-os-compatibility.md](docs/cli/cross-os-compatibility.md) +- [docs/cli/debugging.md](docs/cli/debugging.md) +- [docs/cli/eslint-rules.md](docs/cli/eslint-rules.md) +- [docs/cli/faq.md](docs/cli/faq.md) +- [docs/cli/get-started.md](docs/cli/get-started.md) +- [docs/cli/naming-conventions.md](docs/cli/naming-conventions.md) +- [docs/cli/performance.md](docs/cli/performance.md) +- [docs/cli/testing-strategy.md](docs/cli/testing-strategy.md) +- [docs/cli/troubleshooting.md](docs/cli/troubleshooting.md) + +### CLI kit + +- [docs/cli-kit/command-guidelines.md](docs/cli-kit/command-guidelines.md) +- [docs/cli-kit/errors.md](docs/cli-kit/errors.md) +- [packages/cli/README.md](packages/cli/README.md) + +### UI kit + +- [docs/cli-kit/ui-kit/contributing.md](docs/cli-kit/ui-kit/contributing.md) +- [docs/cli-kit/ui-kit/guidelines.md](docs/cli-kit/ui-kit/guidelines.md) +- [docs/cli-kit/ui-kit/readme.md](docs/cli-kit/ui-kit/readme.md) diff --git a/docs-shopify.dev/commands/interfaces/app-build.interface.ts b/docs-shopify.dev/commands/interfaces/app-build.interface.ts deleted file mode 100644 index b49ee1cf21c..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-build.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app build` command: - * @publicDocs - */ -export interface appbuild { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Skips the installation of dependencies. Deprecated, use workspaces instead. - * @environment SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION - */ - '--skip-dependencies-installation'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-bulk-cancel.interface.ts b/docs-shopify.dev/commands/interfaces/app-bulk-cancel.interface.ts deleted file mode 100644 index 35af820689f..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-bulk-cancel.interface.ts +++ /dev/null @@ -1,54 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app bulk cancel` command: - * @publicDocs - */ -export interface appbulkcancel { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * The bulk operation ID to cancel (numeric ID or full GID). - * @environment SHOPIFY_FLAG_ID - */ - '--id ': string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * The store domain. Must be an existing dev store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-bulk-execute.interface.ts b/docs-shopify.dev/commands/interfaces/app-bulk-execute.interface.ts deleted file mode 100644 index 20287c13968..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-bulk-execute.interface.ts +++ /dev/null @@ -1,90 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app bulk execute` command: - * @publicDocs - */ -export interface appbulkexecute { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The file path where results should be written if --watch is specified. If not specified, results will be written to STDOUT. - * @environment SHOPIFY_FLAG_OUTPUT_FILE - */ - '--output-file '?: string - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * The GraphQL query or mutation to run as a bulk operation. - * @environment SHOPIFY_FLAG_QUERY - */ - '-q, --query '?: string - - /** - * Path to a file containing the GraphQL query or mutation. Can't be used with --query. - * @environment SHOPIFY_FLAG_QUERY_FILE - */ - '--query-file '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * The store domain. Must be an existing dev store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Path to a file containing GraphQL variables in JSONL format (one JSON object per line). Can't be used with --variables. - * @environment SHOPIFY_FLAG_VARIABLE_FILE - */ - '--variable-file '?: string - - /** - * The values for any GraphQL variables in your mutation, in JSON format. Can be specified multiple times. - * @environment SHOPIFY_FLAG_VARIABLES - */ - '-v, --variables '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * The API version to use for the bulk operation. If not specified, uses the latest stable version. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version '?: string - - /** - * Wait for bulk operation results before exiting. Defaults to false. - * @environment SHOPIFY_FLAG_WATCH - */ - '--watch'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-bulk-status.interface.ts b/docs-shopify.dev/commands/interfaces/app-bulk-status.interface.ts deleted file mode 100644 index 51f7be3a0fa..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-bulk-status.interface.ts +++ /dev/null @@ -1,54 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app bulk status` command: - * @publicDocs - */ -export interface appbulkstatus { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * 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. - * @environment SHOPIFY_FLAG_ID - */ - '--id '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * The store domain. Must be an existing dev store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-config-link.interface.ts b/docs-shopify.dev/commands/interfaces/app-config-link.interface.ts deleted file mode 100644 index 61612d1b815..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-config-link.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app config link` command: - * @publicDocs - */ -export interface appconfiglink { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-config-pull.interface.ts b/docs-shopify.dev/commands/interfaces/app-config-pull.interface.ts deleted file mode 100644 index b536b11053b..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-config-pull.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app config pull` command: - * @publicDocs - */ -export interface appconfigpull { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-config-use.interface.ts b/docs-shopify.dev/commands/interfaces/app-config-use.interface.ts deleted file mode 100644 index baff1d18848..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-config-use.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app config use` command: - * @publicDocs - */ -export interface appconfiguse { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts b/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts deleted file mode 100644 index 3d8d00ad456..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app config validate` command: - * @publicDocs - */ -export interface appconfigvalidate { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-deploy.interface.ts b/docs-shopify.dev/commands/interfaces/app-deploy.interface.ts deleted file mode 100644 index e7d9472cfaf..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-deploy.interface.ts +++ /dev/null @@ -1,84 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app deploy` command: - * @publicDocs - */ -export interface appdeploy { - /** - * Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates. - * @environment SHOPIFY_FLAG_ALLOW_DELETES - */ - '--allow-deletes'?: '' - - /** - * Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments. - * @environment SHOPIFY_FLAG_ALLOW_UPDATES - */ - '--allow-updates'?: '' - - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Optional message that will be associated with this version. This is for internal use only and won't be available externally. - * @environment SHOPIFY_FLAG_MESSAGE - */ - '--message '?: string - - /** - * 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. - * @environment SHOPIFY_FLAG_NO_BUILD - */ - '--no-build'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Creates a version but doesn't release it - it's not made available to merchants. With this flag, a user confirmation is not required. - * @environment SHOPIFY_FLAG_NO_RELEASE - */ - '--no-release'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * URL associated with the new app version. - * @environment SHOPIFY_FLAG_SOURCE_CONTROL_URL - */ - '--source-control-url '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * 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. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/app-dev-clean.interface.ts b/docs-shopify.dev/commands/interfaces/app-dev-clean.interface.ts deleted file mode 100644 index 4f40193eeca..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-dev-clean.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app dev clean` command: - * @publicDocs - */ -export interface appdevclean { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Store URL. Must be an existing development store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-dev.interface.ts b/docs-shopify.dev/commands/interfaces/app-dev.interface.ts deleted file mode 100644 index 82bc41c8b3f..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-dev.interface.ts +++ /dev/null @@ -1,108 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app dev` command: - * @publicDocs - */ -export interface appdev { - /** - * Resource URL for checkout UI extension. Format: "/cart/{productVariantID}:{productQuantity}" - * @environment SHOPIFY_FLAG_CHECKOUT_CART_URL - */ - '--checkout-cart-url '?: string - - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Port to use for localhost. Must be between 1 and 65535. - * @environment SHOPIFY_FLAG_LOCALHOST_PORT - */ - '--localhost-port '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Uses the app URL from the toml file instead an autogenerated URL for dev. - * @environment SHOPIFY_FLAG_NO_UPDATE - */ - '--no-update'?: '' - - /** - * 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. - * @environment SHOPIFY_FLAG_NOTIFY - */ - '--notify '?: string - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Skips the installation of dependencies. Deprecated, use workspaces instead. - * @environment SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION - */ - '--skip-dependencies-installation'?: '' - - /** - * Store URL. Must be an existing development or Shopify Plus sandbox store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Resource URL for subscription UI extension. Format: "/products/{productId}" - * @environment SHOPIFY_FLAG_SUBSCRIPTION_PRODUCT_URL - */ - '--subscription-product-url '?: string - - /** - * Theme ID or name of the theme app extension host theme. - * @environment SHOPIFY_FLAG_THEME - */ - '-t, --theme '?: string - - /** - * Local port of the theme app extension development server. Must be between 1 and 65535. - * @environment SHOPIFY_FLAG_THEME_APP_EXTENSION_PORT - */ - '--theme-app-extension-port '?: string - - /** - * Use a custom tunnel, it must be running before executing dev. Format: "https://my-tunnel-url:port". - * @environment SHOPIFY_FLAG_TUNNEL_URL - */ - '--tunnel-url '?: string - - /** - * 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) - * @environment SHOPIFY_FLAG_USE_LOCALHOST - */ - '--use-localhost'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-env-pull.interface.ts b/docs-shopify.dev/commands/interfaces/app-env-pull.interface.ts deleted file mode 100644 index b1955be10b3..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-env-pull.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app env pull` command: - * @publicDocs - */ -export interface appenvpull { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Specify an environment file to update if the update flag is set - * @environment SHOPIFY_FLAG_ENV_FILE - */ - '--env-file '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-env-show.interface.ts b/docs-shopify.dev/commands/interfaces/app-env-show.interface.ts deleted file mode 100644 index 22922d457f7..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-env-show.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app env show` command: - * @publicDocs - */ -export interface appenvshow { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-execute.interface.ts b/docs-shopify.dev/commands/interfaces/app-execute.interface.ts deleted file mode 100644 index 6579aacae38..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-execute.interface.ts +++ /dev/null @@ -1,84 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app execute` command: - * @publicDocs - */ -export interface appexecute { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The file name where results should be written, instead of STDOUT. - * @environment SHOPIFY_FLAG_OUTPUT_FILE - */ - '--output-file '?: string - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * The GraphQL query or mutation, as a string. - * @environment SHOPIFY_FLAG_QUERY - */ - '-q, --query '?: string - - /** - * Path to a file containing the GraphQL query or mutation. Can't be used with --query. - * @environment SHOPIFY_FLAG_QUERY_FILE - */ - '--query-file '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * 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. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Path to a file containing GraphQL variables in JSON format. Can't be used with --variables. - * @environment SHOPIFY_FLAG_VARIABLE_FILE - */ - '--variable-file '?: string - - /** - * The values for any GraphQL variables in your query or mutation, in JSON format. - * @environment SHOPIFY_FLAG_VARIABLES - */ - '-v, --variables '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * The API version to use for the query or mutation. Defaults to the latest stable version. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/app-function-build.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-build.interface.ts deleted file mode 100644 index 48fa548058c..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-function-build.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app function build` command: - * @publicDocs - */ -export interface appfunctionbuild { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your function directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-function-info.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-info.interface.ts deleted file mode 100644 index 1a63189a074..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-function-info.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app function info` command: - * @publicDocs - */ -export interface appfunctioninfo { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your function directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts deleted file mode 100644 index 09917f4c3c5..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app function replay` command: - * @publicDocs - */ -export interface appfunctionreplay { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * 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. - * @environment SHOPIFY_FLAG_LOG - */ - '-l, --log '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your function directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * Re-run the function when the source code changes. - * @environment SHOPIFY_FLAG_WATCH - */ - '-w, --watch'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-function-run.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-run.interface.ts deleted file mode 100644 index 266a8f4bc56..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-function-run.interface.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app function run` command: - * @publicDocs - */ -export interface appfunctionrun { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Name of the WebAssembly export to invoke. - * @environment SHOPIFY_FLAG_EXPORT - */ - '-e, --export '?: string - - /** - * The input JSON to pass to the function. If omitted, standard input is used. - * @environment SHOPIFY_FLAG_INPUT - */ - '-i, --input '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your function directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-function-schema.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-schema.interface.ts deleted file mode 100644 index 184f8c2dd10..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-function-schema.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app function schema` command: - * @publicDocs - */ -export interface appfunctionschema { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your function directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Output the schema to stdout instead of writing to a file. - * @environment SHOPIFY_FLAG_STDOUT - */ - '--stdout'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-function-typegen.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-typegen.interface.ts deleted file mode 100644 index 26e4b821ad3..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-function-typegen.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app function typegen` command: - * @publicDocs - */ -export interface appfunctiontypegen { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your function directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-generate-extension.interface.ts b/docs-shopify.dev/commands/interfaces/app-generate-extension.interface.ts deleted file mode 100644 index f5b91df900e..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-generate-extension.interface.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app generate extension` command: - * @publicDocs - */ -export interface appgenerateextension { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Choose a starting template for your extension, where applicable - * @environment SHOPIFY_FLAG_FLAVOR - */ - '--flavor '?: string - - /** - * name of your Extension - * @environment SHOPIFY_FLAG_NAME - */ - '-n, --name '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Extension template - * @environment SHOPIFY_FLAG_EXTENSION_TEMPLATE - */ - '-t, --template '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-graphiql.interface.ts b/docs-shopify.dev/commands/interfaces/app-graphiql.interface.ts deleted file mode 100644 index 8a650167e23..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-graphiql.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app graphiql` command: - * @publicDocs - */ -export interface appgraphiql { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Local port for the GraphiQL server. Must be between 1 and 65535. - * @environment SHOPIFY_FLAG_PORT - */ - '--port '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * The myshopify.com domain of the store to open GraphiQL against. The app must be installed on the store. If not specified, you will be prompted to select a store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * The values for any GraphQL variables in your query or mutation, in JSON format. - * @environment SHOPIFY_FLAG_VARIABLES - */ - '-v, --variables '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * The API version to use in GraphiQL. Defaults to the latest stable version. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts b/docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts deleted file mode 100644 index eadb26647eb..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts +++ /dev/null @@ -1,54 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app import-custom-data-definitions` command: - * @publicDocs - */ -export interface appimportcustomdatadefinitions { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Include existing declared definitions in the output. - * @environment SHOPIFY_FLAG_INCLUDE_EXISTING - */ - '--include-existing'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Store URL. Must be an existing development or Shopify Plus sandbox store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-import-extensions.interface.ts b/docs-shopify.dev/commands/interfaces/app-import-extensions.interface.ts deleted file mode 100644 index 29b7f26fe74..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-import-extensions.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app import-extensions` command: - * @publicDocs - */ -export interface appimportextensions { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-info.interface.ts b/docs-shopify.dev/commands/interfaces/app-info.interface.ts deleted file mode 100644 index fe05159c10f..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-info.interface.ts +++ /dev/null @@ -1,54 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app info` command: - * @publicDocs - */ -export interface appinfo { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * Outputs environment variables necessary for running and deploying web/. - * @environment SHOPIFY_FLAG_OUTPUT_WEB_ENV - */ - '--web-env'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-init.interface.ts b/docs-shopify.dev/commands/interfaces/app-init.interface.ts deleted file mode 100644 index 5a894ab5af6..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-init.interface.ts +++ /dev/null @@ -1,62 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app init` command: - * @publicDocs - */ -export interface appinit { - /** - * 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. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * Which flavor of the given template to use. - * @environment SHOPIFY_FLAG_TEMPLATE_FLAVOR - */ - '--flavor '?: string - - /** - * The name for the new app. When provided, skips the app selection prompt and creates a new app with this name. - * @environment SHOPIFY_FLAG_NAME - */ - '-n, --name '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The organization ID. Your organization ID can be found in your Dev Dashboard URL: https://dev.shopify.com/dashboard/ - * @environment SHOPIFY_FLAG_ORGANIZATION_ID - */ - '--organization-id '?: string - - /** - * - * @environment SHOPIFY_FLAG_PACKAGE_MANAGER - */ - '-d, --package-manager '?: string - - /** - * - * @environment SHOPIFY_FLAG_PATH - */ - '-p, --path '?: string - - /** - * The app template. Accepts one of the following: - - - - Any GitHub repo with optional branch and subpath, e.g., https://github.com/Shopify//[subpath]#[branch] - * @environment SHOPIFY_FLAG_TEMPLATE - */ - '--template '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-logs-sources.interface.ts b/docs-shopify.dev/commands/interfaces/app-logs-sources.interface.ts deleted file mode 100644 index 1ce5188ffd7..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-logs-sources.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app logs sources` command: - * @publicDocs - */ -export interface applogssources { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-logs.interface.ts b/docs-shopify.dev/commands/interfaces/app-logs.interface.ts deleted file mode 100644 index 8498e2ac7fb..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-logs.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app logs` command: - * @publicDocs - */ -export interface applogs { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Filters output to the specified log source. - * @environment SHOPIFY_FLAG_SOURCE - */ - '--source '?: string - - /** - * Filters output to the specified status (success or failure). - * @environment SHOPIFY_FLAG_STATUS - */ - '--status '?: string - - /** - * Store URL. Must be an existing development or Shopify Plus sandbox store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-release.interface.ts b/docs-shopify.dev/commands/interfaces/app-release.interface.ts deleted file mode 100644 index ea024422430..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-release.interface.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app release` command: - * @publicDocs - */ -export interface apprelease { - /** - * Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates. - * @environment SHOPIFY_FLAG_ALLOW_DELETES - */ - '--allow-deletes'?: '' - - /** - * Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments. - * @environment SHOPIFY_FLAG_ALLOW_UPDATES - */ - '--allow-updates'?: '' - - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * The name of the app version to release. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version ': string -} diff --git a/docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts b/docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts deleted file mode 100644 index d4c6ca406cd..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app versions list` command: - * @publicDocs - */ -export interface appversionslist { - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/app-webhook-trigger.interface.ts b/docs-shopify.dev/commands/interfaces/app-webhook-trigger.interface.ts deleted file mode 100644 index fe488bf5f68..00000000000 --- a/docs-shopify.dev/commands/interfaces/app-webhook-trigger.interface.ts +++ /dev/null @@ -1,71 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `app webhook trigger` command: - * @publicDocs - */ -export interface appwebhooktrigger { - /** - * The URL where the webhook payload should be sent. - You will need a different address type for each delivery-method: - · For remote HTTP testing, use a URL that starts with https:// - · For local HTTP testing, use http://localhost:{port}/{url-path} - · For Google Pub/Sub, use pubsub://{project-id}:{topic-id} - · For Amazon EventBridge, use an Amazon Resource Name (ARN) starting with arn:aws:events: - * @environment SHOPIFY_FLAG_ADDRESS - */ - '--address '?: string - - /** - * The API Version of the webhook topic. - * @environment SHOPIFY_FLAG_API_VERSION - */ - '--api-version '?: string - - /** - * The Client ID of your app. - * @environment SHOPIFY_FLAG_CLIENT_ID - */ - '--client-id '?: string - - /** - * Your app's client secret. This secret allows us to return the X-Shopify-Hmac-SHA256 header that lets you validate the origin of the response that you receive. - * @environment SHOPIFY_FLAG_CLIENT_SECRET - */ - '--client-secret '?: string - - /** - * The name of the app configuration. - * @environment SHOPIFY_FLAG_APP_CONFIG - */ - '-c, --config '?: string - - /** - * Method chosen to deliver the topic payload. If not passed, it's inferred from the address. - * @environment SHOPIFY_FLAG_DELIVERY_METHOD - */ - '--delivery-method '?: string - - /** - * This help. When you run the trigger command the CLI will prompt you for any information that isn't passed using flags. - * @environment SHOPIFY_FLAG_HELP - */ - '--help'?: '' - - /** - * The path to your app directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Reset all your settings. - * @environment SHOPIFY_FLAG_RESET - */ - '--reset'?: '' - - /** - * The requested webhook topic. - * @environment SHOPIFY_FLAG_TOPIC - */ - '--topic '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/auth-login.interface.ts b/docs-shopify.dev/commands/interfaces/auth-login.interface.ts deleted file mode 100644 index d6c9bd440ba..00000000000 --- a/docs-shopify.dev/commands/interfaces/auth-login.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `auth login` command: - * @publicDocs - */ -export interface authlogin { - /** - * Alias of the session you want to login to. - * @environment SHOPIFY_FLAG_AUTH_ALIAS - */ - '--alias '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/auth-logout.interface.ts b/docs-shopify.dev/commands/interfaces/auth-logout.interface.ts deleted file mode 100644 index 56e9f9b6fbb..00000000000 --- a/docs-shopify.dev/commands/interfaces/auth-logout.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `auth logout` command: - * @publicDocs - */ -export interface authlogout { - -} diff --git a/docs-shopify.dev/commands/interfaces/commands.interface.ts b/docs-shopify.dev/commands/interfaces/commands.interface.ts deleted file mode 100644 index ddda337cb85..00000000000 --- a/docs-shopify.dev/commands/interfaces/commands.interface.ts +++ /dev/null @@ -1,54 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `commands` command: - * @publicDocs - */ -export interface commands { - /** - * Only show provided columns (comma-separated). - * - */ - '-c, --columns '?: string - - /** - * Show deprecated commands. - * - */ - '--deprecated'?: '' - - /** - * Show extra columns. - * - */ - '-x, --extended'?: '' - - /** - * Show hidden commands. - * - */ - '--hidden'?: '' - - /** - * Format output as json. - * - */ - '--json'?: '' - - /** - * Do not truncate output. - * - */ - '--no-truncate'?: '' - - /** - * Property to sort by. - * - */ - '--sort '?: string - - /** - * Show tree of commands. - * - */ - '--tree'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/config-autocorrect-off.interface.ts b/docs-shopify.dev/commands/interfaces/config-autocorrect-off.interface.ts deleted file mode 100644 index f1f6dd00516..00000000000 --- a/docs-shopify.dev/commands/interfaces/config-autocorrect-off.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `config autocorrect off` command: - * @publicDocs - */ -export interface configautocorrectoff { - -} diff --git a/docs-shopify.dev/commands/interfaces/config-autocorrect-on.interface.ts b/docs-shopify.dev/commands/interfaces/config-autocorrect-on.interface.ts deleted file mode 100644 index 5d6f2f54aa8..00000000000 --- a/docs-shopify.dev/commands/interfaces/config-autocorrect-on.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `config autocorrect on` command: - * @publicDocs - */ -export interface configautocorrecton { - -} diff --git a/docs-shopify.dev/commands/interfaces/config-autocorrect-status.interface.ts b/docs-shopify.dev/commands/interfaces/config-autocorrect-status.interface.ts deleted file mode 100644 index a64952654ad..00000000000 --- a/docs-shopify.dev/commands/interfaces/config-autocorrect-status.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `config autocorrect status` command: - * @publicDocs - */ -export interface configautocorrectstatus { - -} diff --git a/docs-shopify.dev/commands/interfaces/config-autoupgrade-off.interface.ts b/docs-shopify.dev/commands/interfaces/config-autoupgrade-off.interface.ts deleted file mode 100644 index 515307131ea..00000000000 --- a/docs-shopify.dev/commands/interfaces/config-autoupgrade-off.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `config autoupgrade off` command: - * @publicDocs - */ -export interface configautoupgradeoff { - -} diff --git a/docs-shopify.dev/commands/interfaces/config-autoupgrade-on.interface.ts b/docs-shopify.dev/commands/interfaces/config-autoupgrade-on.interface.ts deleted file mode 100644 index 9b2d007ecf3..00000000000 --- a/docs-shopify.dev/commands/interfaces/config-autoupgrade-on.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `config autoupgrade on` command: - * @publicDocs - */ -export interface configautoupgradeon { - -} diff --git a/docs-shopify.dev/commands/interfaces/config-autoupgrade-status.interface.ts b/docs-shopify.dev/commands/interfaces/config-autoupgrade-status.interface.ts deleted file mode 100644 index c6d74fb288b..00000000000 --- a/docs-shopify.dev/commands/interfaces/config-autoupgrade-status.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `config autoupgrade status` command: - * @publicDocs - */ -export interface configautoupgradestatus { - -} diff --git a/docs-shopify.dev/commands/interfaces/doc-fetch.interface.ts b/docs-shopify.dev/commands/interfaces/doc-fetch.interface.ts deleted file mode 100644 index 5137929f611..00000000000 --- a/docs-shopify.dev/commands/interfaces/doc-fetch.interface.ts +++ /dev/null @@ -1,30 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `doc fetch` command: - * @publicDocs - */ -export interface docfetch { - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Write the document to this file path instead of printing it to stdout. - * @environment SHOPIFY_FLAG_OUTPUT - */ - '--output '?: string - - /** - * The shopify.dev URL to fetch. - * @environment SHOPIFY_FLAG_URL - */ - '--url ': string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/doc-search.interface.ts b/docs-shopify.dev/commands/interfaces/doc-search.interface.ts deleted file mode 100644 index c153524f8d5..00000000000 --- a/docs-shopify.dev/commands/interfaces/doc-search.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `doc search` command: - * @publicDocs - */ -export interface docsearch { - /** - * Limit results to a specific API (for example: admin, storefront, hydrogen, functions). Unrecognized values are ignored. - * @environment SHOPIFY_FLAG_API_NAME - */ - '--api-name '?: string - - /** - * Limit results to a specific API version (for example: 2025-10, latest, current). - * @environment SHOPIFY_FLAG_API_VERSION - */ - '--api-version '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The search query. - * @environment SHOPIFY_FLAG_QUERY - */ - '--query ': string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/help.interface.ts b/docs-shopify.dev/commands/interfaces/help.interface.ts deleted file mode 100644 index afab36201fb..00000000000 --- a/docs-shopify.dev/commands/interfaces/help.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `help` command: - * @publicDocs - */ -export interface help { - /** - * Include all nested commands in the output. - * @environment SHOPIFY_FLAG_CLI_NESTED_COMMANDS - */ - '-n, --nested-commands'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-build.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-build.interface.ts deleted file mode 100644 index 2468bc8aa47..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-build.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen build` command: - * @publicDocs - */ -export interface hydrogenbuild { - /** - * Show a bundle size summary after building. Defaults to true, use `--no-bundle-stats` to disable. - * - */ - '--bundle-stats'?: '' - - /** - * Automatically generates GraphQL types for your project’s Storefront API queries. - * - */ - '--codegen'?: '' - - /** - * Specifies a path to a codegen configuration file. Defaults to `/codegen.ts` if this file exists. - * - */ - '--codegen-config-path '?: string - - /** - * Disables any warnings about missing standard routes. - * @environment SHOPIFY_HYDROGEN_FLAG_DISABLE_ROUTE_WARNING - */ - '--disable-route-warning'?: '' - - /** - * Entry file for the worker. Defaults to `./server`. - * @environment SHOPIFY_HYDROGEN_FLAG_ENTRY - */ - '--entry '?: string - - /** - * Client sourcemapping is avoided by default because it makes backend code visible in the browser. Use this flag to force enabling it. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE_CLIENT_SOURCEMAP - */ - '--force-client-sourcemap'?: '' - - /** - * Checks that there is exactly one valid lockfile in the project. Defaults to `true`. Deactivate with `--no-lockfile-check`. - * @environment SHOPIFY_HYDROGEN_FLAG_LOCKFILE_CHECK - */ - '--lockfile-check'?: '' - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Controls whether server sourcemaps are generated. Default to `true`. Deactivate `--no-sourcemaps`. - * @environment SHOPIFY_HYDROGEN_FLAG_SOURCEMAP - */ - '--sourcemap'?: '' - - /** - * Watches for changes and rebuilds the project writing output to disk. - * @environment SHOPIFY_HYDROGEN_FLAG_WATCH - */ - '--watch'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-check.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-check.interface.ts deleted file mode 100644 index 215b394d831..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-check.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen check` command: - * @publicDocs - */ -export interface hydrogencheck { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-codegen.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-codegen.interface.ts deleted file mode 100644 index d5a7ede458f..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-codegen.interface.ts +++ /dev/null @@ -1,24 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen codegen` command: - * @publicDocs - */ -export interface hydrogencodegen { - /** - * Specify a path to a codegen configuration file. Defaults to `/codegen.ts` if it exists. - * - */ - '--codegen-config-path '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Watch the project for changes to update types on file save. - * - */ - '--watch'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-customer-account-push.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-customer-account-push.interface.ts deleted file mode 100644 index 2ee45a3b69d..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-customer-account-push.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen customer-account-push` command: - * @publicDocs - */ -export interface hydrogencustomeraccountpush { - /** - * The development domain of your application. - * - */ - '--dev-origin ': string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * The relative url of allowed url that will be redirected to post-logout for Customer Account API OAuth flow. Default to nothing. - * - */ - '--relative-logout-uri '?: string - - /** - * The relative url of allowed callback url for Customer Account API OAuth flow. Default is '/account/authorize' - * - */ - '--relative-redirect-uri '?: string - - /** - * The id of the storefront the configuration should be pushed to. Must start with 'gid://shopify/HydrogenStorefront/' - * - */ - '--storefront-id '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-debug-cpu.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-debug-cpu.interface.ts deleted file mode 100644 index d1f5cea39e7..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-debug-cpu.interface.ts +++ /dev/null @@ -1,24 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen debug cpu` command: - * @publicDocs - */ -export interface hydrogendebugcpu { - /** - * Entry file for the worker. Defaults to `./server`. - * @environment SHOPIFY_HYDROGEN_FLAG_ENTRY - */ - '--entry '?: string - - /** - * Specify a path to generate the profile file. Defaults to "startup.cpuprofile". - * - */ - '--output '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-deploy.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-deploy.interface.ts deleted file mode 100644 index 7696a3feb2d..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-deploy.interface.ts +++ /dev/null @@ -1,126 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen deploy` command: - * @publicDocs - */ -export interface hydrogendeploy { - /** - * Directory containing the client assets to deploy, relative to the project root. Defaults to the detected Vite client output directory, then falls back to `dist/client`. - * @environment SHOPIFY_HYDROGEN_FLAG_ASSETS_DIR - */ - '--assets-dir '?: string - - /** - * Generate an authentication bypass token, which can be used to perform end-to-end tests against the deployment. - * @environment AUTH_BYPASS_TOKEN - */ - '--auth-bypass-token'?: '' - - /** - * Specify the duration (in hours) up to 12 hours for the authentication bypass token. Defaults to `2` - * @environment AUTH_BYPASS_TOKEN_DURATION - */ - '--auth-bypass-token-duration '?: string - - /** - * Specify a build command to run before deploying. If not specified, the Hydrogen build pipeline will be used. When custom output directories are configured, defaults to `node --run build`. - * - */ - '--build-command '?: string - - /** - * Entry file for the worker. Defaults to `./server`. - * @environment SHOPIFY_HYDROGEN_FLAG_ENTRY - */ - '--entry '?: string - - /** - * Specifies the environment to perform the operation using its handle. Fetch the handle using the `env list` command. - * - */ - '--env '?: string - - /** - * Specifies the environment to perform the operation using its Git branch name. - * @environment SHOPIFY_HYDROGEN_ENVIRONMENT_BRANCH - */ - '--env-branch '?: string - - /** - * Path to an environment file to override existing environment variables for the deployment. - * - */ - '--env-file '?: string - - /** - * Forces a deployment to proceed if there are uncommitted changes in its Git repository. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * Client sourcemapping is avoided by default because it makes backend code visible in the browser. Use this flag to force enabling it. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE_CLIENT_SOURCEMAP - */ - '--force-client-sourcemap'?: '' - - /** - * Create a JSON file containing the deployment details in CI environments. Defaults to true, use `--no-json-output` to disable. - * - */ - '--json-output'?: '' - - /** - * Checks that there is exactly one valid lockfile in the project. Defaults to `true`. Deactivate with `--no-lockfile-check`. - * @environment SHOPIFY_HYDROGEN_FLAG_LOCKFILE_CHECK - */ - '--lockfile-check'?: '' - - /** - * Description of the changes in the deployment. Defaults to the commit message of the latest commit if there are no uncommitted changes. - * @environment SHOPIFY_HYDROGEN_FLAG_METADATA_DESCRIPTION - */ - '--metadata-description '?: string - - /** - * User that initiated the deployment. Will be saved and displayed in the Shopify admin - * @environment SHOPIFY_HYDROGEN_FLAG_METADATA_USER - */ - '--metadata-user '?: string - - /** - * Skip the routability verification step after deployment. - * - */ - '--no-verify'?: '' - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Deploys to the Preview environment. - * - */ - '--preview'?: '' - - /** - * Shop URL. It can be the shop prefix (janes-apparel) or the full myshopify.com URL (janes-apparel.myshopify.com, https://janes-apparel.myshopify.com). - * @environment SHOPIFY_SHOP - */ - '-s, --shop '?: string - - /** - * Oxygen deployment token. Defaults to the linked storefront's token if available. - * @environment SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN - */ - '-t, --token '?: string - - /** - * Directory containing the Oxygen worker entry point (`index.js` or `index.mjs`), relative to the project root. Defaults to the detected Vite server output directory, then falls back to `dist/server`. - * @environment SHOPIFY_HYDROGEN_FLAG_WORKER_DIR - */ - '--worker-dir '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-dev.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-dev.interface.ts deleted file mode 100644 index ce17a2ef9a9..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-dev.interface.ts +++ /dev/null @@ -1,102 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen dev` command: - * @publicDocs - */ -export interface hydrogendev { - /** - * Automatically generates GraphQL types for your project’s Storefront API queries. - * - */ - '--codegen'?: '' - - /** - * Specifies a path to a codegen configuration file. Defaults to `/codegen.ts` if this file exists. - * - */ - '--codegen-config-path '?: string - - /** - * Use tunneling for local development and push the tunneling domain to admin. Required to use Customer Account API's OAuth flow - * @environment SHOPIFY_HYDROGEN_FLAG_CUSTOMER_ACCOUNT_PUSH - */ - '--customer-account-push'?: '' - - /** - * Enables inspector connections to the server with a debugger such as Visual Studio Code or Chrome DevTools. - * @environment SHOPIFY_HYDROGEN_FLAG_DEBUG - */ - '--debug'?: '' - - /** - * Disable adding dependencies to Vite's `ssr.optimizeDeps.include` automatically - * @environment SHOPIFY_HYDROGEN_FLAG_DISABLE_DEPS_OPTIMIZER - */ - '--disable-deps-optimizer'?: '' - - /** - * Skip the version check when running `hydrogen dev` - * - */ - '--disable-version-check'?: '' - - /** - * Disable rendering fallback routes when a route file doesn't exist. - * @environment SHOPIFY_HYDROGEN_FLAG_DISABLE_VIRTUAL_ROUTES - */ - '--disable-virtual-routes'?: '' - - /** - * Entry file for the worker. Defaults to `./server`. - * @environment SHOPIFY_HYDROGEN_FLAG_ENTRY - */ - '--entry '?: string - - /** - * Specifies the environment to perform the operation using its handle. Fetch the handle using the `env list` command. - * - */ - '--env '?: string - - /** - * Specifies the environment to perform the operation using its Git branch name. - * @environment SHOPIFY_HYDROGEN_ENVIRONMENT_BRANCH - */ - '--env-branch '?: string - - /** - * Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`. - * - */ - '--env-file '?: string - - /** - * Expose the server to the local network - * - */ - '--host'?: '' - - /** - * The port where the inspector is available. Defaults to 9229. - * @environment SHOPIFY_HYDROGEN_FLAG_INSPECTOR_PORT - */ - '--inspector-port '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * The port to run the server on. Defaults to 3000. - * @environment SHOPIFY_HYDROGEN_FLAG_PORT - */ - '--port '?: string - - /** - * Outputs more information about the command's execution. - * @environment SHOPIFY_HYDROGEN_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-env-list.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-env-list.interface.ts deleted file mode 100644 index de896f7f239..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-env-list.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen env list` command: - * @publicDocs - */ -export interface hydrogenenvlist { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-env-pull.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-env-pull.interface.ts deleted file mode 100644 index 57fb69c2be0..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-env-pull.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen env pull` command: - * @publicDocs - */ -export interface hydrogenenvpull { - /** - * Specifies the environment to perform the operation using its handle. Fetch the handle using the `env list` command. - * - */ - '--env '?: string - - /** - * Specifies the environment to perform the operation using its Git branch name. - * @environment SHOPIFY_HYDROGEN_ENVIRONMENT_BRANCH - */ - '--env-branch '?: string - - /** - * Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`. - * - */ - '--env-file '?: string - - /** - * Overwrites the destination directory and files if they already exist. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-env-push.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-env-push.interface.ts deleted file mode 100644 index eb9c80c1095..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-env-push.interface.ts +++ /dev/null @@ -1,24 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen env push` command: - * @publicDocs - */ -export interface hydrogenenvpush { - /** - * Specifies the environment to perform the operation using its handle. Fetch the handle using the `env list` command. - * - */ - '--env '?: string - - /** - * Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`. - * - */ - '--env-file '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-generate-route.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-generate-route.interface.ts deleted file mode 100644 index da80cec7602..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-generate-route.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen generate route` command: - * @publicDocs - */ -export interface hydrogengenerateroute { - /** - * React Router adapter used in the route. The default is `react-router`. - * @environment SHOPIFY_HYDROGEN_FLAG_ADAPTER - */ - '--adapter '?: string - - /** - * Overwrites the destination directory and files if they already exist. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * The param name in Remix routes for the i18n locale, if any. Example: `locale` becomes ($locale). - * @environment SHOPIFY_HYDROGEN_FLAG_ADAPTER - */ - '--locale-param '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Generate TypeScript files - * @environment SHOPIFY_HYDROGEN_FLAG_TYPESCRIPT - */ - '--typescript'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-generate-routes.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-generate-routes.interface.ts deleted file mode 100644 index 7536d57c962..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-generate-routes.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen generate routes` command: - * @publicDocs - */ -export interface hydrogengenerateroutes { - /** - * React Router adapter used in the route. The default is `react-router`. - * @environment SHOPIFY_HYDROGEN_FLAG_ADAPTER - */ - '--adapter '?: string - - /** - * Overwrites the destination directory and files if they already exist. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * The param name in Remix routes for the i18n locale, if any. Example: `locale` becomes ($locale). - * @environment SHOPIFY_HYDROGEN_FLAG_ADAPTER - */ - '--locale-param '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Generate TypeScript files - * @environment SHOPIFY_HYDROGEN_FLAG_TYPESCRIPT - */ - '--typescript'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-init.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-init.interface.ts deleted file mode 100644 index 4226e609035..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-init.interface.ts +++ /dev/null @@ -1,72 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen init` command: - * @publicDocs - */ -export interface hydrogeninit { - /** - * Overwrites the destination directory and files if they already exist. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * Init Git and create initial commits. - * @environment SHOPIFY_HYDROGEN_FLAG_GIT - */ - '--git'?: '' - - /** - * Auto installs dependencies using the active package manager. - * @environment SHOPIFY_HYDROGEN_FLAG_INSTALL_DEPS - */ - '--install-deps'?: '' - - /** - * Sets the template language to use. One of `js` or `ts`. - * @environment SHOPIFY_HYDROGEN_FLAG_LANGUAGE - */ - '--language '?: string - - /** - * Sets the URL structure to support multiple markets. Must be one of: `subfolders`, `domains`, `subdomains`, `none`. Example: `--markets subfolders`. - * @environment SHOPIFY_HYDROGEN_FLAG_I18N - */ - '--markets '?: string - - /** - * Use mock.shop as the data source for the storefront. - * @environment SHOPIFY_HYDROGEN_FLAG_MOCK_DATA - */ - '--mock-shop'?: '' - - /** - * The path to the directory of the new Hydrogen storefront. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Scaffolds a new Hydrogen project with a set of sensible defaults. Equivalent to `shopify hydrogen init --path hydrogen-quickstart --mock-shop --language js --shortcut --markets none` - * @environment SHOPIFY_HYDROGEN_FLAG_QUICKSTART - */ - '--quickstart'?: '' - - /** - * Creates a global h2 shortcut for Shopify CLI using shell aliases. Deactivate with `--no-shortcut`. - * @environment SHOPIFY_HYDROGEN_FLAG_SHORTCUT - */ - '--shortcut'?: '' - - /** - * Sets the styling strategy to use. One of `tailwind`, `vanilla-extract`, `css-modules`, `postcss`, `none`. - * @environment SHOPIFY_HYDROGEN_FLAG_STYLING - */ - '--styling '?: string - - /** - * Scaffolds project based on an existing template or example from the Hydrogen repository. - * @environment SHOPIFY_HYDROGEN_FLAG_TEMPLATE - */ - '--template '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-link.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-link.interface.ts deleted file mode 100644 index aea69b1bcc3..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-link.interface.ts +++ /dev/null @@ -1,24 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen link` command: - * @publicDocs - */ -export interface hydrogenlink { - /** - * Overwrites the destination directory and files if they already exist. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * The name of a Hydrogen Storefront (e.g. "Jane's Apparel") - * @environment SHOPIFY_HYDROGEN_STOREFRONT - */ - '--storefront '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-list.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-list.interface.ts deleted file mode 100644 index f8a211bf9b0..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-list.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen list` command: - * @publicDocs - */ -export interface hydrogenlist { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-login.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-login.interface.ts deleted file mode 100644 index 99cba513f04..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-login.interface.ts +++ /dev/null @@ -1,18 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen login` command: - * @publicDocs - */ -export interface hydrogenlogin { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Shop URL. It can be the shop prefix (janes-apparel) or the full myshopify.com URL (janes-apparel.myshopify.com, https://janes-apparel.myshopify.com). - * @environment SHOPIFY_SHOP - */ - '-s, --shop '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-logout.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-logout.interface.ts deleted file mode 100644 index 8e48b80b12f..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-logout.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen logout` command: - * @publicDocs - */ -export interface hydrogenlogout { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-preview.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-preview.interface.ts deleted file mode 100644 index f3ef485494b..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-preview.interface.ts +++ /dev/null @@ -1,84 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen preview` command: - * @publicDocs - */ -export interface hydrogenpreview { - /** - * Builds the app before starting the preview server. - * - */ - '--build'?: '' - - /** - * Automatically generates GraphQL types for your project’s Storefront API queries. - * - */ - '--codegen'?: '' - - /** - * Specifies a path to a codegen configuration file. Defaults to `/codegen.ts` if this file exists. - * - */ - '--codegen-config-path '?: string - - /** - * Enables inspector connections to the server with a debugger such as Visual Studio Code or Chrome DevTools. - * @environment SHOPIFY_HYDROGEN_FLAG_DEBUG - */ - '--debug'?: '' - - /** - * Entry file for the worker. Defaults to `./server`. - * @environment SHOPIFY_HYDROGEN_FLAG_ENTRY - */ - '--entry '?: string - - /** - * Specifies the environment to perform the operation using its handle. Fetch the handle using the `env list` command. - * - */ - '--env '?: string - - /** - * Specifies the environment to perform the operation using its Git branch name. - * @environment SHOPIFY_HYDROGEN_ENVIRONMENT_BRANCH - */ - '--env-branch '?: string - - /** - * Path to an environment file to override existing environment variables. Defaults to the '.env' located in your project path `--path`. - * - */ - '--env-file '?: string - - /** - * The port where the inspector is available. Defaults to 9229. - * @environment SHOPIFY_HYDROGEN_FLAG_INSPECTOR_PORT - */ - '--inspector-port '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * The port to run the server on. Defaults to 3000. - * @environment SHOPIFY_HYDROGEN_FLAG_PORT - */ - '--port '?: string - - /** - * Outputs more information about the command's execution. - * @environment SHOPIFY_HYDROGEN_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * Watches for changes and rebuilds the project. - * - */ - '--watch'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-setup-css.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-setup-css.interface.ts deleted file mode 100644 index 04edbd37548..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-setup-css.interface.ts +++ /dev/null @@ -1,24 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen setup css` command: - * @publicDocs - */ -export interface hydrogensetupcss { - /** - * Overwrites the destination directory and files if they already exist. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * Auto installs dependencies using the active package manager. - * @environment SHOPIFY_HYDROGEN_FLAG_INSTALL_DEPS - */ - '--install-deps'?: '' - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-setup-markets.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-setup-markets.interface.ts deleted file mode 100644 index fad3107502e..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-setup-markets.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen setup markets` command: - * @publicDocs - */ -export interface hydrogensetupmarkets { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-setup-vite.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-setup-vite.interface.ts deleted file mode 100644 index 6798b9ed876..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-setup-vite.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen setup vite` command: - * @publicDocs - */ -export interface hydrogensetupvite { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-setup.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-setup.interface.ts deleted file mode 100644 index d26b9c1e602..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-setup.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen setup` command: - * @publicDocs - */ -export interface hydrogensetup { - /** - * Overwrites the destination directory and files if they already exist. - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * Auto installs dependencies using the active package manager. - * @environment SHOPIFY_HYDROGEN_FLAG_INSTALL_DEPS - */ - '--install-deps'?: '' - - /** - * Sets the URL structure to support multiple markets. Must be one of: `subfolders`, `domains`, `subdomains`, `none`. Example: `--markets subfolders`. - * @environment SHOPIFY_HYDROGEN_FLAG_I18N - */ - '--markets '?: string - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * Creates a global h2 shortcut for Shopify CLI using shell aliases. Deactivate with `--no-shortcut`. - * @environment SHOPIFY_HYDROGEN_FLAG_SHORTCUT - */ - '--shortcut'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-shortcut.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-shortcut.interface.ts deleted file mode 100644 index a0e9671f9fe..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-shortcut.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen shortcut` command: - * @publicDocs - */ -export interface hydrogenshortcut { - -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-unlink.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-unlink.interface.ts deleted file mode 100644 index 605127feb0e..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-unlink.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen unlink` command: - * @publicDocs - */ -export interface hydrogenunlink { - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/hydrogen-upgrade.interface.ts b/docs-shopify.dev/commands/interfaces/hydrogen-upgrade.interface.ts deleted file mode 100644 index bd42eafa30f..00000000000 --- a/docs-shopify.dev/commands/interfaces/hydrogen-upgrade.interface.ts +++ /dev/null @@ -1,24 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `hydrogen upgrade` command: - * @publicDocs - */ -export interface hydrogenupgrade { - /** - * Ignore warnings and force the upgrade to the target version - * @environment SHOPIFY_HYDROGEN_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * The path to the directory of the Hydrogen storefront. Defaults to the current directory where the command is run. - * @environment SHOPIFY_HYDROGEN_FLAG_PATH - */ - '--path '?: string - - /** - * A target hydrogen version to update to - * - */ - '-v, --version '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/search.interface.ts b/docs-shopify.dev/commands/interfaces/search.interface.ts deleted file mode 100644 index 618c86f1f7f..00000000000 --- a/docs-shopify.dev/commands/interfaces/search.interface.ts +++ /dev/null @@ -1,18 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `search` command: - * @publicDocs - */ -export interface search { - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/organization-list.interface.ts b/docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts similarity index 80% rename from docs-shopify.dev/commands/interfaces/organization-list.interface.ts rename to docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts index 9fa9df1b83c..de54cbdae2e 100644 --- a/docs-shopify.dev/commands/interfaces/organization-list.interface.ts +++ b/docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts @@ -1,9 +1,9 @@ // This is an autogenerated file. Don't edit this file manually. /** - * The following flags are available for the `organization list` command: + * The following flags are available for the `store auth list` command: * @publicDocs */ -export interface organizationlist { +export interface storeauthlist { /** * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON diff --git a/docs-shopify.dev/commands/interfaces/store-bulk-cancel.interface.ts b/docs-shopify.dev/commands/interfaces/store-bulk-cancel.interface.ts deleted file mode 100644 index 4bf9a360d8b..00000000000 --- a/docs-shopify.dev/commands/interfaces/store-bulk-cancel.interface.ts +++ /dev/null @@ -1,30 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `store bulk cancel` command: - * @publicDocs - */ -export interface storebulkcancel { - /** - * The bulk operation ID to cancel (numeric ID or full GID). - * @environment SHOPIFY_FLAG_ID - */ - '--id ': string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The myshopify.com domain of the store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store ': string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/store-bulk-execute.interface.ts b/docs-shopify.dev/commands/interfaces/store-bulk-execute.interface.ts deleted file mode 100644 index c9444aa3e55..00000000000 --- a/docs-shopify.dev/commands/interfaces/store-bulk-execute.interface.ts +++ /dev/null @@ -1,72 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `store bulk execute` command: - * @publicDocs - */ -export interface storebulkexecute { - /** - * Allow GraphQL mutations to run against the target store. - * @environment SHOPIFY_FLAG_ALLOW_MUTATIONS - */ - '--allow-mutations'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The file path where results should be written if --watch is specified. If not specified, results will be written to STDOUT. - * @environment SHOPIFY_FLAG_OUTPUT_FILE - */ - '--output-file '?: string - - /** - * The GraphQL query or mutation to run as a bulk operation. - * @environment SHOPIFY_FLAG_QUERY - */ - '-q, --query '?: string - - /** - * Path to a file containing the GraphQL query or mutation. Can't be used with --query. - * @environment SHOPIFY_FLAG_QUERY_FILE - */ - '--query-file '?: string - - /** - * The myshopify.com domain of the store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store ': string - - /** - * Path to a file containing GraphQL variables in JSONL format (one JSON object per line). Can't be used with --variables. - * @environment SHOPIFY_FLAG_VARIABLE_FILE - */ - '--variable-file '?: string - - /** - * The values for any GraphQL variables in your mutation, in JSON format. Can be specified multiple times. - * @environment SHOPIFY_FLAG_VARIABLES - */ - '-v, --variables '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * The API version to use for the bulk operation. If not specified, uses the latest stable version. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version '?: string - - /** - * Wait for bulk operation results before exiting. Defaults to false. - * @environment SHOPIFY_FLAG_WATCH - */ - '--watch'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/store-bulk-status.interface.ts b/docs-shopify.dev/commands/interfaces/store-bulk-status.interface.ts deleted file mode 100644 index 0564a6ee9e6..00000000000 --- a/docs-shopify.dev/commands/interfaces/store-bulk-status.interface.ts +++ /dev/null @@ -1,30 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `store bulk status` command: - * @publicDocs - */ -export interface storebulkstatus { - /** - * The bulk operation ID (numeric ID or full GID). If not provided, lists all bulk operations on this store in the last 7 days. - * @environment SHOPIFY_FLAG_ID - */ - '--id '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The myshopify.com domain of the store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store ': string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts b/docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts new file mode 100644 index 00000000000..4b7cdae1c44 --- /dev/null +++ b/docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts @@ -0,0 +1,36 @@ +// This is an autogenerated file. Don't edit this file manually. +/** + * The following flags are available for the `store create preview` command: + * @publicDocs + */ +export interface storecreatepreview { + /** + * Two-letter country code for the store, such as US, CA, or GB. + * @environment SHOPIFY_FLAG_STORE_COUNTRY + */ + '--country '?: string + + /** + * Output the result as JSON. Automatically disables color output. + * @environment SHOPIFY_FLAG_JSON + */ + '-j, --json'?: '' + + /** + * The name of the store. + * @environment SHOPIFY_FLAG_PREVIEW_STORE_NAME + */ + '--name '?: string + + /** + * Disable color output. + * @environment SHOPIFY_FLAG_NO_COLOR + */ + '--no-color'?: '' + + /** + * Increase the verbosity of the output. + * @environment SHOPIFY_FLAG_VERBOSE + */ + '--verbose'?: '' +} diff --git a/docs-shopify.dev/commands/interfaces/store-execute.interface.ts b/docs-shopify.dev/commands/interfaces/store-execute.interface.ts deleted file mode 100644 index 5897fffbb58..00000000000 --- a/docs-shopify.dev/commands/interfaces/store-execute.interface.ts +++ /dev/null @@ -1,72 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `store execute` command: - * @publicDocs - */ -export interface storeexecute { - /** - * Allow GraphQL mutations to run against the target store. - * @environment SHOPIFY_FLAG_ALLOW_MUTATIONS - */ - '--allow-mutations'?: '' - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The file name where results should be written, instead of STDOUT. - * @environment SHOPIFY_FLAG_OUTPUT_FILE - */ - '--output-file '?: string - - /** - * The GraphQL query or mutation, as a string. - * @environment SHOPIFY_FLAG_QUERY - */ - '-q, --query '?: string - - /** - * Path to a file containing the GraphQL query or mutation. Can't be used with --query. - * @environment SHOPIFY_FLAG_QUERY_FILE - */ - '--query-file '?: string - - /** - * The myshopify.com domain of the store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store ': string - - /** - * Path to a file containing GraphQL variables in JSON format. Can't be used with --variables. - * @environment SHOPIFY_FLAG_VARIABLE_FILE - */ - '--variable-file '?: string - - /** - * The values for any GraphQL variables in your query or mutation, in JSON format. - * @environment SHOPIFY_FLAG_VARIABLES - */ - '-v, --variables '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * The API version to use for the query or mutation. Defaults to the latest stable version. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/store-graphiql.interface.ts b/docs-shopify.dev/commands/interfaces/store-graphiql.interface.ts deleted file mode 100644 index cb3cf73c449..00000000000 --- a/docs-shopify.dev/commands/interfaces/store-graphiql.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `store graphiql` command: - * @publicDocs - */ -export interface storegraphiql { - /** - * Allow GraphQL mutations to run against the target store. - * @environment SHOPIFY_FLAG_ALLOW_MUTATIONS - */ - '--allow-mutations'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Local port for the GraphiQL server. Must be between 1 and 65535. - * @environment SHOPIFY_FLAG_PORT - */ - '--port '?: string - - /** - * The myshopify.com domain of the store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store ': string - - /** - * The values for any GraphQL variables in your query or mutation, in JSON format. - * @environment SHOPIFY_FLAG_VARIABLES - */ - '-v, --variables '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * The API version to use in GraphiQL. Defaults to the latest stable version. - * @environment SHOPIFY_FLAG_VERSION - */ - '--version '?: string -} diff --git a/docs-shopify.dev/commands/interfaces/store-auth.interface.ts b/docs-shopify.dev/commands/interfaces/store-list.interface.ts similarity index 56% rename from docs-shopify.dev/commands/interfaces/store-auth.interface.ts rename to docs-shopify.dev/commands/interfaces/store-list.interface.ts index 16f479cc306..674f068aaec 100644 --- a/docs-shopify.dev/commands/interfaces/store-auth.interface.ts +++ b/docs-shopify.dev/commands/interfaces/store-list.interface.ts @@ -1,9 +1,9 @@ // This is an autogenerated file. Don't edit this file manually. /** - * The following flags are available for the `store auth` command: + * The following flags are available for the `store list` command: * @publicDocs */ -export interface storeauth { +export interface storelist { /** * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON @@ -17,16 +17,10 @@ export interface storeauth { '--no-color'?: '' /** - * Comma-separated Admin API scopes to request for the app. - * @environment SHOPIFY_FLAG_SCOPES + * The numeric organization ID. Auto-selects if you belong to a single organization. + * @environment SHOPIFY_FLAG_ORGANIZATION_ID */ - '--scopes ': string - - /** - * The myshopify.com domain of the store. - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store ': string + '--organization-id '?: string /** * Increase the verbosity of the output. diff --git a/docs-shopify.dev/commands/interfaces/store-info.interface.ts b/docs-shopify.dev/commands/interfaces/store-open.interface.ts similarity index 65% rename from docs-shopify.dev/commands/interfaces/store-info.interface.ts rename to docs-shopify.dev/commands/interfaces/store-open.interface.ts index 01c264dca63..a6eb0aeb6c8 100644 --- a/docs-shopify.dev/commands/interfaces/store-info.interface.ts +++ b/docs-shopify.dev/commands/interfaces/store-open.interface.ts @@ -1,15 +1,9 @@ // This is an autogenerated file. Don't edit this file manually. /** - * The following flags are available for the `store info` command: + * The following flags are available for the `store open` command: * @publicDocs */ -export interface storeinfo { - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - +export interface storeopen { /** * Disable color output. * @environment SHOPIFY_FLAG_NO_COLOR diff --git a/docs-shopify.dev/commands/interfaces/theme-check.interface.ts b/docs-shopify.dev/commands/interfaces/theme-check.interface.ts deleted file mode 100644 index 905df2bf20e..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-check.interface.ts +++ /dev/null @@ -1,81 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme check` command: - * @publicDocs - */ -export interface themecheck { - /** - * Automatically fix offenses - * @environment SHOPIFY_FLAG_AUTO_CORRECT - */ - '-a, --auto-correct'?: '' - - /** - * Use the config provided, overriding .theme-check.yml if present - Supports all theme-check: config values, e.g., theme-check:theme-app-extension, - theme-check:recommended, theme-check:all - For backwards compatibility, :theme_app_extension is also supported - * @environment SHOPIFY_FLAG_CONFIG - */ - '-C, --config '?: string - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Minimum severity for exit with error code - * @environment SHOPIFY_FLAG_FAIL_LEVEL - */ - '--fail-level '?: string - - /** - * Generate a .theme-check.yml file - * @environment SHOPIFY_FLAG_INIT - */ - '--init'?: '' - - /** - * List enabled checks - * @environment SHOPIFY_FLAG_LIST - */ - '--list'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The output format to use - * @environment SHOPIFY_FLAG_OUTPUT - */ - '-o, --output '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Output active config to STDOUT - * @environment SHOPIFY_FLAG_PRINT - */ - '--print'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' - - /** - * Print Theme Check version - * @environment SHOPIFY_FLAG_VERSION - */ - '-v, --version'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-console.interface.ts b/docs-shopify.dev/commands/interfaces/theme-console.interface.ts deleted file mode 100644 index 2bb63673dae..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-console.interface.ts +++ /dev/null @@ -1,54 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme console` command: - * @publicDocs - */ -export interface themeconsole { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * The password for storefronts with password protection. - * @environment SHOPIFY_FLAG_STORE_PASSWORD - */ - '--store-password '?: string - - /** - * The url to be used as context - * @environment SHOPIFY_FLAG_URL - */ - '--url '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-delete.interface.ts b/docs-shopify.dev/commands/interfaces/theme-delete.interface.ts deleted file mode 100644 index 16ce3004333..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-delete.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme delete` command: - * @publicDocs - */ -export interface themedelete { - /** - * Delete your development theme. - * @environment SHOPIFY_FLAG_DEVELOPMENT - */ - '-d, --development'?: '' - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Skip confirmation. - * @environment SHOPIFY_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Include others development themes in theme list. - * @environment SHOPIFY_FLAG_SHOW_ALL - */ - '-a, --show-all'?: '' - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-dev.interface.ts b/docs-shopify.dev/commands/interfaces/theme-dev.interface.ts deleted file mode 100644 index 6cca4461c16..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-dev.interface.ts +++ /dev/null @@ -1,138 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme dev` command: - * @publicDocs - */ -export interface themedev { - /** - * Allow development on a live theme. - * @environment SHOPIFY_FLAG_ALLOW_LIVE - */ - '-a, --allow-live'?: '' - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Controls the visibility of the error overlay when an theme asset upload fails: -- silent Prevents the error overlay from appearing. -- default Displays the error overlay. - - * @environment SHOPIFY_FLAG_ERROR_OVERLAY - */ - '--error-overlay '?: string - - /** - * Set which network interface the web server listens on. The default value is 127.0.0.1. - * @environment SHOPIFY_FLAG_HOST - */ - '--host '?: string - - /** - * Skip hot reloading any files that match the specified pattern. - * @environment SHOPIFY_FLAG_IGNORE - */ - '-x, --ignore '?: string - - /** - * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory. - * @environment SHOPIFY_FLAG_LISTING - */ - '--listing '?: string - - /** - * The live reload mode switches the server behavior when a file is modified: -- hot-reload Hot reloads local changes to CSS and sections (default) -- full-page Always refreshes the entire page -- off Deactivate live reload - * @environment SHOPIFY_FLAG_LIVE_RELOAD - */ - '--live-reload '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Prevents files from being deleted in the remote theme when a file has been deleted locally. This applies to files that are deleted while the command is running, and files that have been deleted locally before the command is run. - * @environment SHOPIFY_FLAG_NODELETE - */ - '-n, --nodelete'?: '' - - /** - * 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. - * @environment SHOPIFY_FLAG_NOTIFY - */ - '--notify '?: string - - /** - * Hot reload only files that match the specified pattern. - * @environment SHOPIFY_FLAG_ONLY - */ - '-o, --only '?: string - - /** - * Automatically launch the theme preview in your default web browser. - * @environment SHOPIFY_FLAG_OPEN - */ - '--open'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Local port to serve theme preview from. Must be between 1 and 65535. - * @environment SHOPIFY_FLAG_PORT - */ - '--port '?: string - - /** - * Inject the standard events inspector into storefront HTML. - * @environment SHOPIFY_FLAG_STANDARD_EVENTS_INSPECTOR - */ - '--standard-events-inspector'?: '' - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * The password for storefronts with password protection. - * @environment SHOPIFY_FLAG_STORE_PASSWORD - */ - '--store-password '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Synchronize Theme Editor updates in the local theme files. - * @environment SHOPIFY_FLAG_THEME_EDITOR_SYNC - */ - '--theme-editor-sync'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts b/docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts deleted file mode 100644 index 87cac1ae070..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme duplicate` command: - * @publicDocs - */ -export interface themeduplicate { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Force the duplicate operation to run without prompts or confirmations. - * @environment SHOPIFY_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Name of the newly duplicated theme. - * @environment SHOPIFY_FLAG_NAME - */ - '-n, --name '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-info.interface.ts b/docs-shopify.dev/commands/interfaces/theme-info.interface.ts deleted file mode 100644 index 13626fc21b1..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-info.interface.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme info` command: - * @publicDocs - */ -export interface themeinfo { - /** - * Retrieve info from your development theme. - * @environment SHOPIFY_FLAG_DEVELOPMENT - */ - '-d, --development'?: '' - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-init.interface.ts b/docs-shopify.dev/commands/interfaces/theme-init.interface.ts deleted file mode 100644 index 3b1d36e131b..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-init.interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme init` command: - * @publicDocs - */ -export interface themeinit { - /** - * The Git URL to clone from. Defaults to Shopify's Skeleton theme. - * @environment SHOPIFY_FLAG_CLONE_URL - */ - '-u, --clone-url '?: string - - /** - * Downloads the latest release of the `clone-url` - * @environment SHOPIFY_FLAG_LATEST - */ - '-l, --latest'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-language-server.interface.ts b/docs-shopify.dev/commands/interfaces/theme-language-server.interface.ts deleted file mode 100644 index eba537a449e..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-language-server.interface.ts +++ /dev/null @@ -1,18 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme language-server` command: - * @publicDocs - */ -export interface themelanguageserver { - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-list.interface.ts b/docs-shopify.dev/commands/interfaces/theme-list.interface.ts deleted file mode 100644 index 3915ac72a84..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-list.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme list` command: - * @publicDocs - */ -export interface themelist { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Only list theme with the given ID. - * @environment SHOPIFY_FLAG_ID - */ - '--id '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Only list themes that contain the given name. - * @environment SHOPIFY_FLAG_NAME - */ - '--name '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Only list themes with the given role. - * @environment SHOPIFY_FLAG_ROLE - */ - '--role '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-metafields-pull.interface.ts b/docs-shopify.dev/commands/interfaces/theme-metafields-pull.interface.ts deleted file mode 100644 index fa2d7ed2443..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-metafields-pull.interface.ts +++ /dev/null @@ -1,42 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme metafields pull` command: - * @publicDocs - */ -export interface thememetafieldspull { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-open.interface.ts b/docs-shopify.dev/commands/interfaces/theme-open.interface.ts deleted file mode 100644 index ad278be9e01..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-open.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme open` command: - * @publicDocs - */ -export interface themeopen { - /** - * Open your development theme. - * @environment SHOPIFY_FLAG_DEVELOPMENT - */ - '-d, --development'?: '' - - /** - * Open the theme editor for the specified theme in the browser. - * @environment SHOPIFY_FLAG_EDITOR - */ - '-E, --editor'?: '' - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Open your live (published) theme. - * @environment SHOPIFY_FLAG_LIVE - */ - '-l, --live'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-package.interface.ts b/docs-shopify.dev/commands/interfaces/theme-package.interface.ts deleted file mode 100644 index 8fa0f536a79..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-package.interface.ts +++ /dev/null @@ -1,24 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme package` command: - * @publicDocs - */ -export interface themepackage { - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-preview.interface.ts b/docs-shopify.dev/commands/interfaces/theme-preview.interface.ts deleted file mode 100644 index 57f05a11f23..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-preview.interface.ts +++ /dev/null @@ -1,72 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme preview` command: - * @publicDocs - */ -export interface themepreview { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Output the preview URL and identifier as JSON. - * @environment SHOPIFY_FLAG_JSON - */ - '--json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Automatically launch the theme preview in your default web browser. - * @environment SHOPIFY_FLAG_OPEN - */ - '--open'?: '' - - /** - * Path to a JSON overrides file. - * @environment SHOPIFY_FLAG_OVERRIDES - */ - '--overrides ': string - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * An existing preview identifier to update instead of creating a new preview. - * @environment SHOPIFY_FLAG_PREVIEW_ID - */ - '--preview-id '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme ': string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-profile.interface.ts b/docs-shopify.dev/commands/interfaces/theme-profile.interface.ts deleted file mode 100644 index 27cc8a0ebd2..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-profile.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme profile` command: - * @publicDocs - */ -export interface themeprofile { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * The password for storefronts with password protection. - * @environment SHOPIFY_FLAG_STORE_PASSWORD - */ - '--store-password '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * The url to be used as context - * @environment SHOPIFY_FLAG_URL - */ - '--url '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-publish.interface.ts b/docs-shopify.dev/commands/interfaces/theme-publish.interface.ts deleted file mode 100644 index d040efd5a9a..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-publish.interface.ts +++ /dev/null @@ -1,54 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme publish` command: - * @publicDocs - */ -export interface themepublish { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Skip confirmation. - * @environment SHOPIFY_FLAG_FORCE - */ - '-f, --force'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-pull.interface.ts b/docs-shopify.dev/commands/interfaces/theme-pull.interface.ts deleted file mode 100644 index 227338fca0a..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-pull.interface.ts +++ /dev/null @@ -1,78 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme pull` command: - * @publicDocs - */ -export interface themepull { - /** - * Pull theme files from your remote development theme. - * @environment SHOPIFY_FLAG_DEVELOPMENT - */ - '-d, --development'?: '' - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Skip downloading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards. - * @environment SHOPIFY_FLAG_IGNORE - */ - '-x, --ignore '?: string - - /** - * Pull theme files from your remote live theme. - * @environment SHOPIFY_FLAG_LIVE - */ - '-l, --live'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Prevent deleting local files that don't exist remotely. - * @environment SHOPIFY_FLAG_NODELETE - */ - '-n, --nodelete'?: '' - - /** - * Download only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards. - * @environment SHOPIFY_FLAG_ONLY - */ - '-o, --only '?: string - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-push.interface.ts b/docs-shopify.dev/commands/interfaces/theme-push.interface.ts deleted file mode 100644 index 3abaa13038d..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-push.interface.ts +++ /dev/null @@ -1,120 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme push` command: - * @publicDocs - */ -export interface themepush { - /** - * Allow push to a live theme. - * @environment SHOPIFY_FLAG_ALLOW_LIVE - */ - '-a, --allow-live'?: '' - - /** - * Push theme files from your remote development theme. - * @environment SHOPIFY_FLAG_DEVELOPMENT - */ - '-d, --development'?: '' - - /** - * Unique identifier for a development theme context (e.g., PR number, branch name). Reuses an existing development theme with this context name, or creates one if none exists. - * @environment SHOPIFY_FLAG_DEVELOPMENT_CONTEXT - */ - '-c, --development-context '?: string - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Skip uploading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards. - * @environment SHOPIFY_FLAG_IGNORE - */ - '-x, --ignore '?: string - - /** - * Output the result as JSON. Automatically disables color output. - * @environment SHOPIFY_FLAG_JSON - */ - '-j, --json'?: '' - - /** - * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory. - * @environment SHOPIFY_FLAG_LISTING - */ - '--listing '?: string - - /** - * Push theme files from your remote live theme. - * @environment SHOPIFY_FLAG_LIVE - */ - '-l, --live'?: '' - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Prevent deleting remote files that don't exist locally. - * @environment SHOPIFY_FLAG_NODELETE - */ - '-n, --nodelete'?: '' - - /** - * Upload only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards. - * @environment SHOPIFY_FLAG_ONLY - */ - '-o, --only '?: string - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Publish as the live theme after uploading. - * @environment SHOPIFY_FLAG_PUBLISH - */ - '-p, --publish'?: '' - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Require theme check to pass without errors before pushing. Warnings are allowed. - * @environment SHOPIFY_FLAG_STRICT_PUSH - */ - '--strict'?: '' - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Create a new unpublished theme and push to it. - * @environment SHOPIFY_FLAG_UNPUBLISHED - */ - '-u, --unpublished'?: '' - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-rename.interface.ts b/docs-shopify.dev/commands/interfaces/theme-rename.interface.ts deleted file mode 100644 index b1eea93668e..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-rename.interface.ts +++ /dev/null @@ -1,66 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme rename` command: - * @publicDocs - */ -export interface themerename { - /** - * Rename your development theme. - * @environment SHOPIFY_FLAG_DEVELOPMENT - */ - '-d, --development'?: '' - - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * Rename your remote live theme. - * @environment SHOPIFY_FLAG_LIVE - */ - '-l, --live'?: '' - - /** - * The new name for the theme. - * @environment SHOPIFY_FLAG_NEW_NAME - */ - '-n, --name '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Theme ID or name of the remote theme. - * @environment SHOPIFY_FLAG_THEME_ID - */ - '-t, --theme '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/theme-share.interface.ts b/docs-shopify.dev/commands/interfaces/theme-share.interface.ts deleted file mode 100644 index 468f14844d4..00000000000 --- a/docs-shopify.dev/commands/interfaces/theme-share.interface.ts +++ /dev/null @@ -1,48 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `theme share` command: - * @publicDocs - */ -export interface themeshare { - /** - * The environment to apply to the current command. - * @environment SHOPIFY_FLAG_ENVIRONMENT - */ - '-e, --environment '?: string - - /** - * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory. - * @environment SHOPIFY_FLAG_LISTING - */ - '--listing '?: string - - /** - * Disable color output. - * @environment SHOPIFY_FLAG_NO_COLOR - */ - '--no-color'?: '' - - /** - * Password generated from the Theme Access app or an Admin API token. - * @environment SHOPIFY_CLI_THEME_TOKEN - */ - '--password '?: string - - /** - * The path where you want to run the command. Defaults to the current working directory. - * @environment SHOPIFY_FLAG_PATH - */ - '--path '?: string - - /** - * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). - * @environment SHOPIFY_FLAG_STORE - */ - '-s, --store '?: string - - /** - * Increase the verbosity of the output. - * @environment SHOPIFY_FLAG_VERBOSE - */ - '--verbose'?: '' -} diff --git a/docs-shopify.dev/commands/interfaces/upgrade.interface.ts b/docs-shopify.dev/commands/interfaces/upgrade.interface.ts deleted file mode 100644 index d443d280fae..00000000000 --- a/docs-shopify.dev/commands/interfaces/upgrade.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `upgrade` command: - * @publicDocs - */ -export interface upgrade { - -} diff --git a/docs-shopify.dev/commands/interfaces/version.interface.ts b/docs-shopify.dev/commands/interfaces/version.interface.ts deleted file mode 100644 index a97fd522fb1..00000000000 --- a/docs-shopify.dev/commands/interfaces/version.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an autogenerated file. Don't edit this file manually. -/** - * The following flags are available for the `version` command: - * @publicDocs - */ -export interface version { - -} diff --git a/docs-shopify.dev/generated/generated_docs_data_v2.json b/docs-shopify.dev/generated/generated_docs_data_v2.json index 493572e967a..d2157241446 100644 --- a/docs-shopify.dev/generated/generated_docs_data_v2.json +++ b/docs-shopify.dev/generated/generated_docs_data_v2.json @@ -6,6 +6,15 @@ "description": "The following flags are available for the `app build` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-build.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-build.interface.ts", "syntaxKind": "PropertySignature", @@ -70,7 +79,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appbuild {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Skips the installation of dependencies. Deprecated, use workspaces instead.\n * @environment SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION\n */\n '--skip-dependencies-installation'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appbuild {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Skips the installation of dependencies. Deprecated, use workspaces instead.\n * @environment SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION\n */\n '--skip-dependencies-installation'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appbulkcancel": { @@ -80,6 +89,15 @@ "description": "The following flags are available for the `app bulk cancel` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-bulk-cancel.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-bulk-cancel.interface.ts", "syntaxKind": "PropertySignature", @@ -152,7 +170,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface appbulkcancel {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * The bulk operation ID to cancel (numeric ID or full GID).\n * @environment SHOPIFY_FLAG_ID\n */\n '--id ': string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The store domain. Must be an existing dev store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appbulkcancel {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * The bulk operation ID to cancel (numeric ID or full GID).\n * @environment SHOPIFY_FLAG_ID\n */\n '--id ': string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The store domain. Must be an existing dev store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appbulkexecute": { @@ -162,6 +180,15 @@ "description": "The following flags are available for the `app bulk execute` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-bulk-execute.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-bulk-execute.interface.ts", "syntaxKind": "PropertySignature", @@ -289,7 +316,7 @@ "environmentValue": "SHOPIFY_FLAG_VARIABLES" } ], - "value": "export interface appbulkexecute {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The file path where results should be written if --watch is specified. If not specified, results will be written to STDOUT.\n * @environment SHOPIFY_FLAG_OUTPUT_FILE\n */\n '--output-file '?: string\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * The GraphQL query or mutation to run as a bulk operation.\n * @environment SHOPIFY_FLAG_QUERY\n */\n '-q, --query '?: string\n\n /**\n * Path to a file containing the GraphQL query or mutation. Can't be used with --query.\n * @environment SHOPIFY_FLAG_QUERY_FILE\n */\n '--query-file '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The store domain. Must be an existing dev store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Path to a file containing GraphQL variables in JSONL format (one JSON object per line). Can't be used with --variables.\n * @environment SHOPIFY_FLAG_VARIABLE_FILE\n */\n '--variable-file '?: string\n\n /**\n * The values for any GraphQL variables in your mutation, in JSON format. Can be specified multiple times.\n * @environment SHOPIFY_FLAG_VARIABLES\n */\n '-v, --variables '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The API version to use for the bulk operation. If not specified, uses the latest stable version.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n\n /**\n * Wait for bulk operation results before exiting. Defaults to false.\n * @environment SHOPIFY_FLAG_WATCH\n */\n '--watch'?: ''\n}" + "value": "export interface appbulkexecute {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The file path where results should be written if --watch is specified. If not specified, results will be written to STDOUT.\n * @environment SHOPIFY_FLAG_OUTPUT_FILE\n */\n '--output-file '?: string\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * The GraphQL query or mutation to run as a bulk operation.\n * @environment SHOPIFY_FLAG_QUERY\n */\n '-q, --query '?: string\n\n /**\n * Path to a file containing the GraphQL query or mutation. Can't be used with --query.\n * @environment SHOPIFY_FLAG_QUERY_FILE\n */\n '--query-file '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The store domain. Must be an existing dev store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Path to a file containing GraphQL variables in JSONL format (one JSON object per line). Can't be used with --variables.\n * @environment SHOPIFY_FLAG_VARIABLE_FILE\n */\n '--variable-file '?: string\n\n /**\n * The values for any GraphQL variables in your mutation, in JSON format. Can be specified multiple times.\n * @environment SHOPIFY_FLAG_VARIABLES\n */\n '-v, --variables '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The API version to use for the bulk operation. If not specified, uses the latest stable version.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n\n /**\n * Wait for bulk operation results before exiting. Defaults to false.\n * @environment SHOPIFY_FLAG_WATCH\n */\n '--watch'?: ''\n}" } }, "appbulkstatus": { @@ -299,6 +326,15 @@ "description": "The following flags are available for the `app bulk status` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-bulk-status.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-bulk-status.interface.ts", "syntaxKind": "PropertySignature", @@ -372,7 +408,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface appbulkstatus {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_ID\n */\n '--id '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The store domain. Must be an existing dev store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appbulkstatus {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_ID\n */\n '--id '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The store domain. Must be an existing dev store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appconfiglink": { @@ -382,6 +418,15 @@ "description": "The following flags are available for the `app config link` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-config-link.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-config-link.interface.ts", "syntaxKind": "PropertySignature", @@ -391,6 +436,24 @@ "isOptional": true, "environmentValue": "SHOPIFY_FLAG_CLIENT_ID" }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-config-link.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--file-name ", + "value": "string", + "description": "The name of the app configuration file to create or overwrite.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_CONFIG_FILE_NAME" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-config-link.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--force", + "value": "''", + "description": "Overwrite an existing configuration file without prompting.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_FORCE" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-config-link.interface.ts", "syntaxKind": "PropertySignature", @@ -437,7 +500,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appconfiglink {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appconfiglink {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * The name of the app configuration file to create or overwrite.\n * @environment SHOPIFY_FLAG_APP_CONFIG_FILE_NAME\n */\n '--file-name '?: string\n\n /**\n * Overwrite an existing configuration file without prompting.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '--force'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appconfigpull": { @@ -447,6 +510,15 @@ "description": "The following flags are available for the `app config pull` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-config-pull.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-config-pull.interface.ts", "syntaxKind": "PropertySignature", @@ -502,7 +574,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appconfigpull {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appconfigpull {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appconfiguse": { @@ -512,6 +584,15 @@ "description": "The following flags are available for the `app config use` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-config-use.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-config-use.interface.ts", "syntaxKind": "PropertySignature", @@ -558,7 +639,7 @@ "environmentValue": "SHOPIFY_FLAG_VERBOSE" } ], - "value": "export interface appconfiguse {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appconfiguse {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appconfigvalidate": { @@ -568,6 +649,15 @@ "description": "The following flags are available for the `app config validate` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts", "syntaxKind": "PropertySignature", @@ -632,7 +722,7 @@ "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appconfigvalidate {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appconfigvalidate {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appdeploy": { @@ -660,6 +750,15 @@ "isOptional": true, "environmentValue": "SHOPIFY_FLAG_ALLOW_UPDATES" }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-deploy.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-deploy.interface.ts", "syntaxKind": "PropertySignature", @@ -760,7 +859,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appdeploy {\n /**\n * Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.\n * @environment SHOPIFY_FLAG_ALLOW_DELETES\n */\n '--allow-deletes'?: ''\n\n /**\n * Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.\n * @environment SHOPIFY_FLAG_ALLOW_UPDATES\n */\n '--allow-updates'?: ''\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Optional message that will be associated with this version. This is for internal use only and won't be available externally.\n * @environment SHOPIFY_FLAG_MESSAGE\n */\n '--message '?: string\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_NO_BUILD\n */\n '--no-build'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Creates a version but doesn't release it - it's not made available to merchants. With this flag, a user confirmation is not required.\n * @environment SHOPIFY_FLAG_NO_RELEASE\n */\n '--no-release'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * URL associated with the new app version.\n * @environment SHOPIFY_FLAG_SOURCE_CONTROL_URL\n */\n '--source-control-url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n}" + "value": "export interface appdeploy {\n /**\n * Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.\n * @environment SHOPIFY_FLAG_ALLOW_DELETES\n */\n '--allow-deletes'?: ''\n\n /**\n * Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.\n * @environment SHOPIFY_FLAG_ALLOW_UPDATES\n */\n '--allow-updates'?: ''\n\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Optional message that will be associated with this version. This is for internal use only and won't be available externally.\n * @environment SHOPIFY_FLAG_MESSAGE\n */\n '--message '?: string\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_NO_BUILD\n */\n '--no-build'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Creates a version but doesn't release it - it's not made available to merchants. With this flag, a user confirmation is not required.\n * @environment SHOPIFY_FLAG_NO_RELEASE\n */\n '--no-release'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * URL associated with the new app version.\n * @environment SHOPIFY_FLAG_SOURCE_CONTROL_URL\n */\n '--source-control-url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n}" } }, "appdevclean": { @@ -770,6 +869,15 @@ "description": "The following flags are available for the `app dev clean` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-dev-clean.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-dev-clean.interface.ts", "syntaxKind": "PropertySignature", @@ -834,7 +942,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface appdevclean {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Store URL. Must be an existing development store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appdevclean {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Store URL. Must be an existing development store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appdev": { @@ -844,6 +952,15 @@ "description": "The following flags are available for the `app dev` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-dev.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-dev.interface.ts", "syntaxKind": "PropertySignature", @@ -998,7 +1115,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME" } ], - "value": "export interface appdev {\n /**\n * Resource URL for checkout UI extension. Format: \"/cart/{productVariantID}:{productQuantity}\"\n * @environment SHOPIFY_FLAG_CHECKOUT_CART_URL\n */\n '--checkout-cart-url '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Port to use for localhost. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_LOCALHOST_PORT\n */\n '--localhost-port '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Uses the app URL from the toml file instead an autogenerated URL for dev.\n * @environment SHOPIFY_FLAG_NO_UPDATE\n */\n '--no-update'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_NOTIFY\n */\n '--notify '?: string\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Skips the installation of dependencies. Deprecated, use workspaces instead.\n * @environment SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION\n */\n '--skip-dependencies-installation'?: ''\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Resource URL for subscription UI extension. Format: \"/products/{productId}\"\n * @environment SHOPIFY_FLAG_SUBSCRIPTION_PRODUCT_URL\n */\n '--subscription-product-url '?: string\n\n /**\n * Theme ID or name of the theme app extension host theme.\n * @environment SHOPIFY_FLAG_THEME\n */\n '-t, --theme '?: string\n\n /**\n * Local port of the theme app extension development server. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_THEME_APP_EXTENSION_PORT\n */\n '--theme-app-extension-port '?: string\n\n /**\n * Use a custom tunnel, it must be running before executing dev. Format: \"https://my-tunnel-url:port\".\n * @environment SHOPIFY_FLAG_TUNNEL_URL\n */\n '--tunnel-url '?: string\n\n /**\n * 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)\n * @environment SHOPIFY_FLAG_USE_LOCALHOST\n */\n '--use-localhost'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appdev {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Resource URL for checkout UI extension. Format: \"/cart/{productVariantID}:{productQuantity}\"\n * @environment SHOPIFY_FLAG_CHECKOUT_CART_URL\n */\n '--checkout-cart-url '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Port to use for localhost. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_LOCALHOST_PORT\n */\n '--localhost-port '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Uses the app URL from the toml file instead an autogenerated URL for dev.\n * @environment SHOPIFY_FLAG_NO_UPDATE\n */\n '--no-update'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_NOTIFY\n */\n '--notify '?: string\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Skips the installation of dependencies. Deprecated, use workspaces instead.\n * @environment SHOPIFY_FLAG_SKIP_DEPENDENCIES_INSTALLATION\n */\n '--skip-dependencies-installation'?: ''\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Resource URL for subscription UI extension. Format: \"/products/{productId}\"\n * @environment SHOPIFY_FLAG_SUBSCRIPTION_PRODUCT_URL\n */\n '--subscription-product-url '?: string\n\n /**\n * Theme ID or name of the theme app extension host theme.\n * @environment SHOPIFY_FLAG_THEME\n */\n '-t, --theme '?: string\n\n /**\n * Local port of the theme app extension development server. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_THEME_APP_EXTENSION_PORT\n */\n '--theme-app-extension-port '?: string\n\n /**\n * Use a custom tunnel, it must be running before executing dev. Format: \"https://my-tunnel-url:port\".\n * @environment SHOPIFY_FLAG_TUNNEL_URL\n */\n '--tunnel-url '?: string\n\n /**\n * 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)\n * @environment SHOPIFY_FLAG_USE_LOCALHOST\n */\n '--use-localhost'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appenvpull": { @@ -1008,6 +1125,15 @@ "description": "The following flags are available for the `app env pull` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-env-pull.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-env-pull.interface.ts", "syntaxKind": "PropertySignature", @@ -1072,7 +1198,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appenvpull {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Specify an environment file to update if the update flag is set\n * @environment SHOPIFY_FLAG_ENV_FILE\n */\n '--env-file '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appenvpull {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Specify an environment file to update if the update flag is set\n * @environment SHOPIFY_FLAG_ENV_FILE\n */\n '--env-file '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appenvshow": { @@ -1082,6 +1208,15 @@ "description": "The following flags are available for the `app env show` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-env-show.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-env-show.interface.ts", "syntaxKind": "PropertySignature", @@ -1137,7 +1272,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appenvshow {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appenvshow {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appexecute": { @@ -1147,6 +1282,15 @@ "description": "The following flags are available for the `app execute` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-execute.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-execute.interface.ts", "syntaxKind": "PropertySignature", @@ -1265,7 +1409,7 @@ "environmentValue": "SHOPIFY_FLAG_VARIABLES" } ], - "value": "export interface appexecute {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The file name where results should be written, instead of STDOUT.\n * @environment SHOPIFY_FLAG_OUTPUT_FILE\n */\n '--output-file '?: string\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * The GraphQL query or mutation, as a string.\n * @environment SHOPIFY_FLAG_QUERY\n */\n '-q, --query '?: string\n\n /**\n * Path to a file containing the GraphQL query or mutation. Can't be used with --query.\n * @environment SHOPIFY_FLAG_QUERY_FILE\n */\n '--query-file '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Path to a file containing GraphQL variables in JSON format. Can't be used with --variables.\n * @environment SHOPIFY_FLAG_VARIABLE_FILE\n */\n '--variable-file '?: string\n\n /**\n * The values for any GraphQL variables in your query or mutation, in JSON format.\n * @environment SHOPIFY_FLAG_VARIABLES\n */\n '-v, --variables '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The API version to use for the query or mutation. Defaults to the latest stable version.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n}" + "value": "export interface appexecute {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The file name where results should be written, instead of STDOUT.\n * @environment SHOPIFY_FLAG_OUTPUT_FILE\n */\n '--output-file '?: string\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * The GraphQL query or mutation, as a string.\n * @environment SHOPIFY_FLAG_QUERY\n */\n '-q, --query '?: string\n\n /**\n * Path to a file containing the GraphQL query or mutation. Can't be used with --query.\n * @environment SHOPIFY_FLAG_QUERY_FILE\n */\n '--query-file '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Path to a file containing GraphQL variables in JSON format. Can't be used with --variables.\n * @environment SHOPIFY_FLAG_VARIABLE_FILE\n */\n '--variable-file '?: string\n\n /**\n * The values for any GraphQL variables in your query or mutation, in JSON format.\n * @environment SHOPIFY_FLAG_VARIABLES\n */\n '-v, --variables '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The API version to use for the query or mutation. Defaults to the latest stable version.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n}" } }, "appfunctionbuild": { @@ -1275,6 +1419,15 @@ "description": "The following flags are available for the `app function build` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-function-build.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-function-build.interface.ts", "syntaxKind": "PropertySignature", @@ -1330,7 +1483,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appfunctionbuild {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appfunctionbuild {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appfunctioninfo": { @@ -1340,6 +1493,15 @@ "description": "The following flags are available for the `app function info` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-function-info.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-function-info.interface.ts", "syntaxKind": "PropertySignature", @@ -1404,7 +1566,7 @@ "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appfunctioninfo {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appfunctioninfo {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appfunctionreplay": { @@ -1414,6 +1576,15 @@ "description": "The following flags are available for the `app function replay` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts", "syntaxKind": "PropertySignature", @@ -1496,7 +1667,7 @@ "environmentValue": "SHOPIFY_FLAG_WATCH" } ], - "value": "export interface appfunctionreplay {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_LOG\n */\n '-l, --log '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Re-run the function when the source code changes.\n * @environment SHOPIFY_FLAG_WATCH\n */\n '-w, --watch'?: ''\n}" + "value": "export interface appfunctionreplay {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_LOG\n */\n '-l, --log '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Re-run the function when the source code changes.\n * @environment SHOPIFY_FLAG_WATCH\n */\n '-w, --watch'?: ''\n}" } }, "appfunctionrun": { @@ -1506,6 +1677,15 @@ "description": "The following flags are available for the `app function run` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-function-run.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-function-run.interface.ts", "syntaxKind": "PropertySignature", @@ -1588,7 +1768,7 @@ "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appfunctionrun {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Name of the WebAssembly export to invoke.\n * @environment SHOPIFY_FLAG_EXPORT\n */\n '-e, --export '?: string\n\n /**\n * The input JSON to pass to the function. If omitted, standard input is used.\n * @environment SHOPIFY_FLAG_INPUT\n */\n '-i, --input '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appfunctionrun {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Name of the WebAssembly export to invoke.\n * @environment SHOPIFY_FLAG_EXPORT\n */\n '-e, --export '?: string\n\n /**\n * The input JSON to pass to the function. If omitted, standard input is used.\n * @environment SHOPIFY_FLAG_INPUT\n */\n '-i, --input '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appfunctionschema": { @@ -1598,6 +1778,15 @@ "description": "The following flags are available for the `app function schema` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-function-schema.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-function-schema.interface.ts", "syntaxKind": "PropertySignature", @@ -1662,7 +1851,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appfunctionschema {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Output the schema to stdout instead of writing to a file.\n * @environment SHOPIFY_FLAG_STDOUT\n */\n '--stdout'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appfunctionschema {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Output the schema to stdout instead of writing to a file.\n * @environment SHOPIFY_FLAG_STDOUT\n */\n '--stdout'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appfunctiontypegen": { @@ -1672,6 +1861,15 @@ "description": "The following flags are available for the `app function typegen` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-function-typegen.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-function-typegen.interface.ts", "syntaxKind": "PropertySignature", @@ -1727,7 +1925,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appfunctiontypegen {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appfunctiontypegen {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appgenerateextension": { @@ -1737,6 +1935,15 @@ "description": "The following flags are available for the `app generate extension` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-generate-extension.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-generate-extension.interface.ts", "syntaxKind": "PropertySignature", @@ -1819,7 +2026,7 @@ "environmentValue": "SHOPIFY_FLAG_EXTENSION_TEMPLATE" } ], - "value": "export interface appgenerateextension {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Choose a starting template for your extension, where applicable\n * @environment SHOPIFY_FLAG_FLAVOR\n */\n '--flavor '?: string\n\n /**\n * name of your Extension\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Extension template\n * @environment SHOPIFY_FLAG_EXTENSION_TEMPLATE\n */\n '-t, --template '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appgenerateextension {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Choose a starting template for your extension, where applicable\n * @environment SHOPIFY_FLAG_FLAVOR\n */\n '--flavor '?: string\n\n /**\n * name of your Extension\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Extension template\n * @environment SHOPIFY_FLAG_EXTENSION_TEMPLATE\n */\n '-t, --template '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appgraphiql": { @@ -1829,6 +2036,15 @@ "description": "The following flags are available for the `app graphiql` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-graphiql.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-graphiql.interface.ts", "syntaxKind": "PropertySignature", @@ -1920,7 +2136,7 @@ "environmentValue": "SHOPIFY_FLAG_VARIABLES" } ], - "value": "export interface appgraphiql {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Local port for the GraphiQL server. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_PORT\n */\n '--port '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The myshopify.com domain of the store to open GraphiQL against. The app must be installed on the store. If not specified, you will be prompted to select a store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The values for any GraphQL variables in your query or mutation, in JSON format.\n * @environment SHOPIFY_FLAG_VARIABLES\n */\n '-v, --variables '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The API version to use in GraphiQL. Defaults to the latest stable version.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n}" + "value": "export interface appgraphiql {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Local port for the GraphiQL server. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_PORT\n */\n '--port '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The myshopify.com domain of the store to open GraphiQL against. The app must be installed on the store. If not specified, you will be prompted to select a store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The values for any GraphQL variables in your query or mutation, in JSON format.\n * @environment SHOPIFY_FLAG_VARIABLES\n */\n '-v, --variables '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The API version to use in GraphiQL. Defaults to the latest stable version.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version '?: string\n}" } }, "appimportcustomdatadefinitions": { @@ -1930,6 +2146,15 @@ "description": "The following flags are available for the `app import-custom-data-definitions` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", "syntaxKind": "PropertySignature", @@ -2003,7 +2228,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface appimportcustomdatadefinitions {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Include existing declared definitions in the output.\n * @environment SHOPIFY_FLAG_INCLUDE_EXISTING\n */\n '--include-existing'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appimportcustomdatadefinitions {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Include existing declared definitions in the output.\n * @environment SHOPIFY_FLAG_INCLUDE_EXISTING\n */\n '--include-existing'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appimportextensions": { @@ -2013,6 +2238,15 @@ "description": "The following flags are available for the `app import-extensions` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-extensions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-import-extensions.interface.ts", "syntaxKind": "PropertySignature", @@ -2068,7 +2302,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appimportextensions {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appimportextensions {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appinfo": { @@ -2078,6 +2312,15 @@ "description": "The following flags are available for the `app info` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-info.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-info.interface.ts", "syntaxKind": "PropertySignature", @@ -2151,7 +2394,7 @@ "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appinfo {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Outputs environment variables necessary for running and deploying web/.\n * @environment SHOPIFY_FLAG_OUTPUT_WEB_ENV\n */\n '--web-env'?: ''\n}" + "value": "export interface appinfo {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Outputs environment variables necessary for running and deploying web/.\n * @environment SHOPIFY_FLAG_OUTPUT_WEB_ENV\n */\n '--web-env'?: ''\n}" } }, "appinit": { @@ -2161,6 +2404,15 @@ "description": "The following flags are available for the `app init` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-init.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-init.interface.ts", "syntaxKind": "PropertySignature", @@ -2243,7 +2495,7 @@ "environmentValue": "SHOPIFY_FLAG_PATH" } ], - "value": "export interface appinit {\n /**\n * 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.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * Which flavor of the given template to use.\n * @environment SHOPIFY_FLAG_TEMPLATE_FLAVOR\n */\n '--flavor '?: string\n\n /**\n * The name for the new app. When provided, skips the app selection prompt and creates a new app with this name.\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The organization ID. Your organization ID can be found in your Dev Dashboard URL: https://dev.shopify.com/dashboard/\n * @environment SHOPIFY_FLAG_ORGANIZATION_ID\n */\n '--organization-id '?: string\n\n /**\n * \n * @environment SHOPIFY_FLAG_PACKAGE_MANAGER\n */\n '-d, --package-manager '?: string\n\n /**\n * \n * @environment SHOPIFY_FLAG_PATH\n */\n '-p, --path '?: string\n\n /**\n * 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]\n * @environment SHOPIFY_FLAG_TEMPLATE\n */\n '--template '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appinit {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * Which flavor of the given template to use.\n * @environment SHOPIFY_FLAG_TEMPLATE_FLAVOR\n */\n '--flavor '?: string\n\n /**\n * The name for the new app. When provided, skips the app selection prompt and creates a new app with this name.\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The organization ID. Your organization ID can be found in your Dev Dashboard URL: https://dev.shopify.com/dashboard/\n * @environment SHOPIFY_FLAG_ORGANIZATION_ID\n */\n '--organization-id '?: string\n\n /**\n * \n * @environment SHOPIFY_FLAG_PACKAGE_MANAGER\n */\n '-d, --package-manager '?: string\n\n /**\n * \n * @environment SHOPIFY_FLAG_PATH\n */\n '-p, --path '?: string\n\n /**\n * 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]\n * @environment SHOPIFY_FLAG_TEMPLATE\n */\n '--template '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "applogssources": { @@ -2253,6 +2505,15 @@ "description": "The following flags are available for the `app logs sources` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-logs-sources.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-logs-sources.interface.ts", "syntaxKind": "PropertySignature", @@ -2308,7 +2569,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface applogssources {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface applogssources {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "applogs": { @@ -2318,6 +2579,15 @@ "description": "The following flags are available for the `app logs` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-logs.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-logs.interface.ts", "syntaxKind": "PropertySignature", @@ -2409,7 +2679,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface applogs {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Filters output to the specified log source.\n * @environment SHOPIFY_FLAG_SOURCE\n */\n '--source '?: string\n\n /**\n * Filters output to the specified status (success or failure).\n * @environment SHOPIFY_FLAG_STATUS\n */\n '--status '?: string\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface applogs {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Filters output to the specified log source.\n * @environment SHOPIFY_FLAG_SOURCE\n */\n '--source '?: string\n\n /**\n * Filters output to the specified status (success or failure).\n * @environment SHOPIFY_FLAG_STATUS\n */\n '--status '?: string\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "apprelease": { @@ -2437,6 +2707,15 @@ "isOptional": true, "environmentValue": "SHOPIFY_FLAG_ALLOW_UPDATES" }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-release.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-release.interface.ts", "syntaxKind": "PropertySignature", @@ -2500,7 +2779,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface apprelease {\n /**\n * Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.\n * @environment SHOPIFY_FLAG_ALLOW_DELETES\n */\n '--allow-deletes'?: ''\n\n /**\n * Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.\n * @environment SHOPIFY_FLAG_ALLOW_UPDATES\n */\n '--allow-updates'?: ''\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The name of the app version to release.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version ': string\n}" + "value": "export interface apprelease {\n /**\n * Allows removing extensions and configuration without requiring user confirmation. For CI/CD environments, the recommended flag is --allow-updates.\n * @environment SHOPIFY_FLAG_ALLOW_DELETES\n */\n '--allow-deletes'?: ''\n\n /**\n * Allows adding and updating extensions and configuration without requiring user confirmation. Recommended option for CI/CD environments.\n * @environment SHOPIFY_FLAG_ALLOW_UPDATES\n */\n '--allow-updates'?: ''\n\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * The name of the app version to release.\n * @environment SHOPIFY_FLAG_VERSION\n */\n '--version ': string\n}" } }, "appversionslist": { @@ -2510,6 +2789,15 @@ "description": "The following flags are available for the `app versions list` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts", "syntaxKind": "PropertySignature", @@ -2574,7 +2862,7 @@ "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appversionslist {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appversionslist {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "appwebhooktrigger": { @@ -2602,6 +2890,15 @@ "isOptional": true, "environmentValue": "SHOPIFY_FLAG_API_VERSION" }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-webhook-trigger.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/app-webhook-trigger.interface.ts", "syntaxKind": "PropertySignature", @@ -2675,7 +2972,7 @@ "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" } ], - "value": "export interface appwebhooktrigger {\n /**\n * The URL where the webhook payload should be sent.\n You will need a different address type for each delivery-method:\n · For remote HTTP testing, use a URL that starts with https://\n · For local HTTP testing, use http://localhost:{port}/{url-path}\n · For Google Pub/Sub, use pubsub://{project-id}:{topic-id}\n · For Amazon EventBridge, use an Amazon Resource Name (ARN) starting with arn:aws:events:\n * @environment SHOPIFY_FLAG_ADDRESS\n */\n '--address '?: string\n\n /**\n * The API Version of the webhook topic.\n * @environment SHOPIFY_FLAG_API_VERSION\n */\n '--api-version '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * Your app's client secret. This secret allows us to return the X-Shopify-Hmac-SHA256 header that lets you validate the origin of the response that you receive.\n * @environment SHOPIFY_FLAG_CLIENT_SECRET\n */\n '--client-secret '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Method chosen to deliver the topic payload. If not passed, it's inferred from the address.\n * @environment SHOPIFY_FLAG_DELIVERY_METHOD\n */\n '--delivery-method '?: string\n\n /**\n * This help. When you run the trigger command the CLI will prompt you for any information that isn't passed using flags.\n * @environment SHOPIFY_FLAG_HELP\n */\n '--help'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The requested webhook topic.\n * @environment SHOPIFY_FLAG_TOPIC\n */\n '--topic '?: string\n}" + "value": "export interface appwebhooktrigger {\n /**\n * The URL where the webhook payload should be sent.\n You will need a different address type for each delivery-method:\n · For remote HTTP testing, use a URL that starts with https://\n · For local HTTP testing, use http://localhost:{port}/{url-path}\n · For Google Pub/Sub, use pubsub://{project-id}:{topic-id}\n · For Amazon EventBridge, use an Amazon Resource Name (ARN) starting with arn:aws:events:\n * @environment SHOPIFY_FLAG_ADDRESS\n */\n '--address '?: string\n\n /**\n * The API Version of the webhook topic.\n * @environment SHOPIFY_FLAG_API_VERSION\n */\n '--api-version '?: string\n\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * Your app's client secret. This secret allows us to return the X-Shopify-Hmac-SHA256 header that lets you validate the origin of the response that you receive.\n * @environment SHOPIFY_FLAG_CLIENT_SECRET\n */\n '--client-secret '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Method chosen to deliver the topic payload. If not passed, it's inferred from the address.\n * @environment SHOPIFY_FLAG_DELIVERY_METHOD\n */\n '--delivery-method '?: string\n\n /**\n * This help. When you run the trigger command the CLI will prompt you for any information that isn't passed using flags.\n * @environment SHOPIFY_FLAG_HELP\n */\n '--help'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * The requested webhook topic.\n * @environment SHOPIFY_FLAG_TOPIC\n */\n '--topic '?: string\n}" } }, "authlogin": { @@ -4309,6 +4606,15 @@ "description": "The following flags are available for the `organization list` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/organization-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/organization-list.interface.ts", "syntaxKind": "PropertySignature", @@ -4337,7 +4643,7 @@ "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface organizationlist {\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface organizationlist {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "search": { @@ -4369,6 +4675,44 @@ "value": "export interface search {\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, + "storeauthlist": { + "docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts", + "name": "storeauthlist", + "description": "The following flags are available for the `store auth list` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-auth-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-j, --json", + "value": "''", + "description": "Output the result as JSON. Automatically disables color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON" + } + ], + "value": "export interface storeauthlist {\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + } + }, "storeauth": { "docs-shopify.dev/commands/interfaces/store-auth.interface.ts": { "filePath": "docs-shopify.dev/commands/interfaces/store-auth.interface.ts", @@ -4623,6 +4967,62 @@ "value": "export interface storebulkstatus {\n /**\n * The bulk operation ID (numeric ID or full GID). If not provided, lists all bulk operations on this store in the last 7 days.\n * @environment SHOPIFY_FLAG_ID\n */\n '--id '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The myshopify.com domain of the store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store ': string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, + "storecreatepreview": { + "docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts", + "name": "storecreatepreview", + "description": "The following flags are available for the `store create preview` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--country ", + "value": "string", + "description": "Two-letter country code for the store, such as US, CA, or GB.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_STORE_COUNTRY" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--name ", + "value": "string", + "description": "The name of the store.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_PREVIEW_STORE_NAME" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-create-preview.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-j, --json", + "value": "''", + "description": "Output the result as JSON. Automatically disables color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON" + } + ], + "value": "export interface storecreatepreview {\n /**\n * Two-letter country code for the store, such as US, CA, or GB.\n * @environment SHOPIFY_FLAG_STORE_COUNTRY\n */\n '--country '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * The name of the store.\n * @environment SHOPIFY_FLAG_PREVIEW_STORE_NAME\n */\n '--name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + } + }, "storeexecute": { "docs-shopify.dev/commands/interfaces/store-execute.interface.ts": { "filePath": "docs-shopify.dev/commands/interfaces/store-execute.interface.ts", @@ -4851,6 +5251,90 @@ "value": "export interface storeinfo {\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The myshopify.com domain of the store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store ': string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, + "storelist": { + "docs-shopify.dev/commands/interfaces/store-list.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/store-list.interface.ts", + "name": "storelist", + "description": "The following flags are available for the `store list` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/store-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--organization-id ", + "value": "string", + "description": "The numeric organization ID. Auto-selects if you belong to a single organization.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_ORGANIZATION_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-j, --json", + "value": "''", + "description": "Output the result as JSON. Automatically disables color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON" + } + ], + "value": "export interface storelist {\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The numeric organization ID. Auto-selects if you belong to a single organization.\n * @environment SHOPIFY_FLAG_ORGANIZATION_ID\n */\n '--organization-id '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + } + }, + "storeopen": { + "docs-shopify.dev/commands/interfaces/store-open.interface.ts": { + "filePath": "docs-shopify.dev/commands/interfaces/store-open.interface.ts", + "name": "storeopen", + "description": "The following flags are available for the `store open` command:", + "isPublicDocs": true, + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/store-open.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "''", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-open.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/store-open.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-s, --store ", + "value": "string", + "description": "The myshopify.com domain of the store.", + "environmentValue": "SHOPIFY_FLAG_STORE" + } + ], + "value": "export interface storeopen {\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The myshopify.com domain of the store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store ': string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + } + }, "themecheck": { "docs-shopify.dev/commands/interfaces/theme-check.interface.ts": { "filePath": "docs-shopify.dev/commands/interfaces/theme-check.interface.ts", @@ -4858,6 +5342,15 @@ "description": "The following flags are available for the `theme check` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-check.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-check.interface.ts", "syntaxKind": "PropertySignature", @@ -4967,7 +5460,7 @@ "environmentValue": "SHOPIFY_FLAG_VERSION" } ], - "value": "export interface themecheck {\n /**\n * Automatically fix offenses\n * @environment SHOPIFY_FLAG_AUTO_CORRECT\n */\n '-a, --auto-correct'?: ''\n\n /**\n * Use the config provided, overriding .theme-check.yml if present\n Supports all theme-check: config values, e.g., theme-check:theme-app-extension,\n theme-check:recommended, theme-check:all\n For backwards compatibility, :theme_app_extension is also supported \n * @environment SHOPIFY_FLAG_CONFIG\n */\n '-C, --config '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Minimum severity for exit with error code\n * @environment SHOPIFY_FLAG_FAIL_LEVEL\n */\n '--fail-level '?: string\n\n /**\n * Generate a .theme-check.yml file\n * @environment SHOPIFY_FLAG_INIT\n */\n '--init'?: ''\n\n /**\n * List enabled checks\n * @environment SHOPIFY_FLAG_LIST\n */\n '--list'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The output format to use\n * @environment SHOPIFY_FLAG_OUTPUT\n */\n '-o, --output '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Output active config to STDOUT\n * @environment SHOPIFY_FLAG_PRINT\n */\n '--print'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Print Theme Check version\n * @environment SHOPIFY_FLAG_VERSION\n */\n '-v, --version'?: ''\n}" + "value": "export interface themecheck {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Automatically fix offenses\n * @environment SHOPIFY_FLAG_AUTO_CORRECT\n */\n '-a, --auto-correct'?: ''\n\n /**\n * Use the config provided, overriding .theme-check.yml if present\n Supports all theme-check: config values, e.g., theme-check:theme-app-extension,\n theme-check:recommended, theme-check:all\n For backwards compatibility, :theme_app_extension is also supported \n * @environment SHOPIFY_FLAG_CONFIG\n */\n '-C, --config '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Minimum severity for exit with error code\n * @environment SHOPIFY_FLAG_FAIL_LEVEL\n */\n '--fail-level '?: string\n\n /**\n * Generate a .theme-check.yml file\n * @environment SHOPIFY_FLAG_INIT\n */\n '--init'?: ''\n\n /**\n * List enabled checks\n * @environment SHOPIFY_FLAG_LIST\n */\n '--list'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The output format to use\n * @environment SHOPIFY_FLAG_OUTPUT\n */\n '-o, --output '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Output active config to STDOUT\n * @environment SHOPIFY_FLAG_PRINT\n */\n '--print'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Print Theme Check version\n * @environment SHOPIFY_FLAG_VERSION\n */\n '-v, --version'?: ''\n}" } }, "themeconsole": { @@ -4977,6 +5470,15 @@ "description": "The following flags are available for the `theme console` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-console.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-console.interface.ts", "syntaxKind": "PropertySignature", @@ -5050,7 +5552,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface themeconsole {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * The url to be used as context\n * @environment SHOPIFY_FLAG_URL\n */\n '--url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeconsole {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * The url to be used as context\n * @environment SHOPIFY_FLAG_URL\n */\n '--url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themedelete": { @@ -5060,6 +5562,15 @@ "description": "The following flags are available for the `theme delete` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-delete.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-delete.interface.ts", "syntaxKind": "PropertySignature", @@ -5151,7 +5662,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themedelete {\n /**\n * Delete your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip confirmation.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Include others development themes in theme list.\n * @environment SHOPIFY_FLAG_SHOW_ALL\n */\n '-a, --show-all'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themedelete {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Delete your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip confirmation.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Include others development themes in theme list.\n * @environment SHOPIFY_FLAG_SHOW_ALL\n */\n '-a, --show-all'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themedev": { @@ -5161,6 +5672,15 @@ "description": "The following flags are available for the `theme dev` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-dev.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-dev.interface.ts", "syntaxKind": "PropertySignature", @@ -5351,7 +5871,7 @@ "environmentValue": "SHOPIFY_FLAG_IGNORE" } ], - "value": "export interface themedev {\n /**\n * Allow development on a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Controls the visibility of the error overlay when an theme asset upload fails:\n- silent Prevents the error overlay from appearing.\n- default Displays the error overlay.\n \n * @environment SHOPIFY_FLAG_ERROR_OVERLAY\n */\n '--error-overlay '?: string\n\n /**\n * Set which network interface the web server listens on. The default value is 127.0.0.1.\n * @environment SHOPIFY_FLAG_HOST\n */\n '--host '?: string\n\n /**\n * Skip hot reloading any files that match the specified pattern.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * The live reload mode switches the server behavior when a file is modified:\n- hot-reload Hot reloads local changes to CSS and sections (default)\n- full-page Always refreshes the entire page\n- off Deactivate live reload\n * @environment SHOPIFY_FLAG_LIVE_RELOAD\n */\n '--live-reload '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevents files from being deleted in the remote theme when a file has been deleted locally. This applies to files that are deleted while the command is running, and files that have been deleted locally before the command is run.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_NOTIFY\n */\n '--notify '?: string\n\n /**\n * Hot reload only files that match the specified pattern.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Automatically launch the theme preview in your default web browser.\n * @environment SHOPIFY_FLAG_OPEN\n */\n '--open'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Local port to serve theme preview from. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_PORT\n */\n '--port '?: string\n\n /**\n * Inject the standard events inspector into storefront HTML.\n * @environment SHOPIFY_FLAG_STANDARD_EVENTS_INSPECTOR\n */\n '--standard-events-inspector'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Synchronize Theme Editor updates in the local theme files.\n * @environment SHOPIFY_FLAG_THEME_EDITOR_SYNC\n */\n '--theme-editor-sync'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themedev {\n /**\n * Allow development on a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Controls the visibility of the error overlay when an theme asset upload fails:\n- silent Prevents the error overlay from appearing.\n- default Displays the error overlay.\n \n * @environment SHOPIFY_FLAG_ERROR_OVERLAY\n */\n '--error-overlay '?: string\n\n /**\n * Set which network interface the web server listens on. The default value is 127.0.0.1.\n * @environment SHOPIFY_FLAG_HOST\n */\n '--host '?: string\n\n /**\n * Skip hot reloading any files that match the specified pattern.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * The live reload mode switches the server behavior when a file is modified:\n- hot-reload Hot reloads local changes to CSS and sections (default)\n- full-page Always refreshes the entire page\n- off Deactivate live reload\n * @environment SHOPIFY_FLAG_LIVE_RELOAD\n */\n '--live-reload '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevents files from being deleted in the remote theme when a file has been deleted locally. This applies to files that are deleted while the command is running, and files that have been deleted locally before the command is run.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * 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.\n * @environment SHOPIFY_FLAG_NOTIFY\n */\n '--notify '?: string\n\n /**\n * Hot reload only files that match the specified pattern.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Automatically launch the theme preview in your default web browser.\n * @environment SHOPIFY_FLAG_OPEN\n */\n '--open'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Local port to serve theme preview from. Must be between 1 and 65535.\n * @environment SHOPIFY_FLAG_PORT\n */\n '--port '?: string\n\n /**\n * Inject the standard events inspector into storefront HTML.\n * @environment SHOPIFY_FLAG_STANDARD_EVENTS_INSPECTOR\n */\n '--standard-events-inspector'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Synchronize Theme Editor updates in the local theme files.\n * @environment SHOPIFY_FLAG_THEME_EDITOR_SYNC\n */\n '--theme-editor-sync'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themeduplicate": { @@ -5361,6 +5881,15 @@ "description": "The following flags are available for the `theme duplicate` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts", "syntaxKind": "PropertySignature", @@ -5443,7 +5972,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themeduplicate {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Force the duplicate operation to run without prompts or confirmations.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Name of the newly duplicated theme.\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeduplicate {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Force the duplicate operation to run without prompts or confirmations.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Name of the newly duplicated theme.\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themeinfo": { @@ -5453,6 +5982,15 @@ "description": "The following flags are available for the `theme info` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-info.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-info.interface.ts", "syntaxKind": "PropertySignature", @@ -5535,7 +6073,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themeinfo {\n /**\n * Retrieve info from your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeinfo {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Retrieve info from your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themeinit": { @@ -5545,6 +6083,15 @@ "description": "The following flags are available for the `theme init` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-init.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-init.interface.ts", "syntaxKind": "PropertySignature", @@ -5591,7 +6138,7 @@ "environmentValue": "SHOPIFY_FLAG_CLONE_URL" } ], - "value": "export interface themeinit {\n /**\n * The Git URL to clone from. Defaults to Shopify's Skeleton theme.\n * @environment SHOPIFY_FLAG_CLONE_URL\n */\n '-u, --clone-url '?: string\n\n /**\n * Downloads the latest release of the `clone-url`\n * @environment SHOPIFY_FLAG_LATEST\n */\n '-l, --latest'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeinit {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The Git URL to clone from. Defaults to Shopify's Skeleton theme.\n * @environment SHOPIFY_FLAG_CLONE_URL\n */\n '-u, --clone-url '?: string\n\n /**\n * Downloads the latest release of the `clone-url`\n * @environment SHOPIFY_FLAG_LATEST\n */\n '-l, --latest'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themelanguageserver": { @@ -5601,6 +6148,15 @@ "description": "The following flags are available for the `theme language-server` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-language-server.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-language-server.interface.ts", "syntaxKind": "PropertySignature", @@ -5620,7 +6176,7 @@ "environmentValue": "SHOPIFY_FLAG_VERBOSE" } ], - "value": "export interface themelanguageserver {\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themelanguageserver {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themelist": { @@ -5630,6 +6186,15 @@ "description": "The following flags are available for the `theme list` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-list.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-list.interface.ts", "syntaxKind": "PropertySignature", @@ -5721,7 +6286,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface themelist {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Only list theme with the given ID.\n * @environment SHOPIFY_FLAG_ID\n */\n '--id '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Only list themes that contain the given name.\n * @environment SHOPIFY_FLAG_NAME\n */\n '--name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Only list themes with the given role.\n * @environment SHOPIFY_FLAG_ROLE\n */\n '--role '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themelist {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Only list theme with the given ID.\n * @environment SHOPIFY_FLAG_ID\n */\n '--id '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Only list themes that contain the given name.\n * @environment SHOPIFY_FLAG_NAME\n */\n '--name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Only list themes with the given role.\n * @environment SHOPIFY_FLAG_ROLE\n */\n '--role '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "thememetafieldspull": { @@ -5731,6 +6296,15 @@ "description": "The following flags are available for the `theme metafields pull` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-metafields-pull.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-metafields-pull.interface.ts", "syntaxKind": "PropertySignature", @@ -5786,7 +6360,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface thememetafieldspull {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface thememetafieldspull {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themeopen": { @@ -5796,6 +6370,15 @@ "description": "The following flags are available for the `theme open` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-open.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-open.interface.ts", "syntaxKind": "PropertySignature", @@ -5887,7 +6470,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themeopen {\n /**\n * Open your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * Open the theme editor for the specified theme in the browser.\n * @environment SHOPIFY_FLAG_EDITOR\n */\n '-E, --editor'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Open your live (published) theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeopen {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Open your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * Open the theme editor for the specified theme in the browser.\n * @environment SHOPIFY_FLAG_EDITOR\n */\n '-E, --editor'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Open your live (published) theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themepackage": { @@ -5897,6 +6480,15 @@ "description": "The following flags are available for the `theme package` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-package.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-package.interface.ts", "syntaxKind": "PropertySignature", @@ -5925,7 +6517,7 @@ "environmentValue": "SHOPIFY_FLAG_VERBOSE" } ], - "value": "export interface themepackage {\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themepackage {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themepreview": { @@ -5935,6 +6527,15 @@ "description": "The following flags are available for the `theme preview` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-preview.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-preview.interface.ts", "syntaxKind": "PropertySignature", @@ -6033,7 +6634,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themepreview {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the preview URL and identifier as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '--json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Automatically launch the theme preview in your default web browser.\n * @environment SHOPIFY_FLAG_OPEN\n */\n '--open'?: ''\n\n /**\n * Path to a JSON overrides file.\n * @environment SHOPIFY_FLAG_OVERRIDES\n */\n '--overrides ': string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * An existing preview identifier to update instead of creating a new preview.\n * @environment SHOPIFY_FLAG_PREVIEW_ID\n */\n '--preview-id '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme ': string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themepreview {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the preview URL and identifier as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '--json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Automatically launch the theme preview in your default web browser.\n * @environment SHOPIFY_FLAG_OPEN\n */\n '--open'?: ''\n\n /**\n * Path to a JSON overrides file.\n * @environment SHOPIFY_FLAG_OVERRIDES\n */\n '--overrides ': string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * An existing preview identifier to update instead of creating a new preview.\n * @environment SHOPIFY_FLAG_PREVIEW_ID\n */\n '--preview-id '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme ': string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themeprofile": { @@ -6043,6 +6644,15 @@ "description": "The following flags are available for the `theme profile` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-profile.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-profile.interface.ts", "syntaxKind": "PropertySignature", @@ -6134,7 +6744,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themeprofile {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * The url to be used as context\n * @environment SHOPIFY_FLAG_URL\n */\n '--url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeprofile {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * The url to be used as context\n * @environment SHOPIFY_FLAG_URL\n */\n '--url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themepublish": { @@ -6144,6 +6754,15 @@ "description": "The following flags are available for the `theme publish` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-publish.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-publish.interface.ts", "syntaxKind": "PropertySignature", @@ -6217,7 +6836,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themepublish {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip confirmation.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themepublish {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip confirmation.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themepull": { @@ -6227,6 +6846,15 @@ "description": "The following flags are available for the `theme pull` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-pull.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-pull.interface.ts", "syntaxKind": "PropertySignature", @@ -6336,7 +6964,7 @@ "environmentValue": "SHOPIFY_FLAG_IGNORE" } ], - "value": "export interface themepull {\n /**\n * Pull theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip downloading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * Pull theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting local files that don't exist remotely.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Download only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themepull {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Pull theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip downloading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * Pull theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting local files that don't exist remotely.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Download only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themepush": { @@ -6346,6 +6974,15 @@ "description": "The following flags are available for the `theme push` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-push.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-push.interface.ts", "syntaxKind": "PropertySignature", @@ -6518,7 +7155,7 @@ "environmentValue": "SHOPIFY_FLAG_IGNORE" } ], - "value": "export interface themepush {\n /**\n * Allow push to a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * Push theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * Unique identifier for a development theme context (e.g., PR number, branch name). Reuses an existing development theme with this context name, or creates one if none exists.\n * @environment SHOPIFY_FLAG_DEVELOPMENT_CONTEXT\n */\n '-c, --development-context '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip uploading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * Push theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting remote files that don't exist locally.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Upload only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Publish as the live theme after uploading.\n * @environment SHOPIFY_FLAG_PUBLISH\n */\n '-p, --publish'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Require theme check to pass without errors before pushing. Warnings are allowed.\n * @environment SHOPIFY_FLAG_STRICT_PUSH\n */\n '--strict'?: ''\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Create a new unpublished theme and push to it.\n * @environment SHOPIFY_FLAG_UNPUBLISHED\n */\n '-u, --unpublished'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themepush {\n /**\n * Allow push to a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Push theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * Unique identifier for a development theme context (e.g., PR number, branch name). Reuses an existing development theme with this context name, or creates one if none exists.\n * @environment SHOPIFY_FLAG_DEVELOPMENT_CONTEXT\n */\n '-c, --development-context '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip uploading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * Push theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting remote files that don't exist locally.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Upload only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Publish as the live theme after uploading.\n * @environment SHOPIFY_FLAG_PUBLISH\n */\n '-p, --publish'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Require theme check to pass without errors before pushing. Warnings are allowed.\n * @environment SHOPIFY_FLAG_STRICT_PUSH\n */\n '--strict'?: ''\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Create a new unpublished theme and push to it.\n * @environment SHOPIFY_FLAG_UNPUBLISHED\n */\n '-u, --unpublished'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themerename": { @@ -6528,6 +7165,15 @@ "description": "The following flags are available for the `theme rename` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-rename.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-rename.interface.ts", "syntaxKind": "PropertySignature", @@ -6619,7 +7265,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themerename {\n /**\n * Rename your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Rename your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * The new name for the theme.\n * @environment SHOPIFY_FLAG_NEW_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themerename {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * Rename your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Rename your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * The new name for the theme.\n * @environment SHOPIFY_FLAG_NEW_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "themeshare": { @@ -6629,6 +7275,15 @@ "description": "The following flags are available for the `theme share` command:", "isPublicDocs": true, "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/theme-share.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--auth-alias ", + "value": "string", + "description": "Alias of the Shopify account to use for authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_AUTH_ALIAS" + }, { "filePath": "docs-shopify.dev/commands/interfaces/theme-share.interface.ts", "syntaxKind": "PropertySignature", @@ -6693,7 +7348,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface themeshare {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeshare {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "upgrade": { diff --git a/docs/cli/testing-strategy.md b/docs/cli/testing-strategy.md index 6244f7a2a9a..c28615ece69 100644 --- a/docs/cli/testing-strategy.md +++ b/docs/cli/testing-strategy.md @@ -37,7 +37,7 @@ pnpm test path/to/my.test.ts ``` ### Filesystem I/O and temporary directories -If the subject under testing does a filesystem I/O operation, we recommend not stubbing that behavior instead of hitting the filesystem. Create a temporary directory whose lifecycle is tied to the lifecycle of the test: +If the subject under test performs filesystem I/O, prefer using a temporary directory instead of stubbing the filesystem. Create a temporary directory whose lifecycle is tied to the lifecycle of the test: ```ts import {file, path} from "@shopify/cli-kit" diff --git a/package.json b/package.json index e4329c091fb..73a14aa7f41 100644 --- a/package.json +++ b/package.json @@ -359,12 +359,6 @@ ] } }, - "packages/ui-extensions-dev-console": { - "entry": [ - "**/src/main.tsx!" - ], - "project": "**/*.{ts,tsx}!" - }, "packages/ui-extensions-server-kit": { "entry": [ "**/src/index.ts!", diff --git a/packages/app/project.json b/packages/app/project.json index 1137aaef142..6f889c815db 100644 --- a/packages/app/project.json +++ b/packages/app/project.json @@ -4,7 +4,6 @@ "sourceRoot": "packages/app/src", "projectType": "library", "tags": ["scope:feature"], - "implicitDependencies": ["ui-extensions-dev-console"], "targets": { "clean": { "executor": "nx:run-commands", diff --git a/packages/app/src/cli/api/graphql/development_preview.ts b/packages/app/src/cli/api/graphql/development_preview.ts deleted file mode 100644 index 66a0eb75d8e..00000000000 --- a/packages/app/src/cli/api/graphql/development_preview.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {gql} from 'graphql-request' - -export const DevelopmentStorePreviewUpdateQuery = gql` - mutation DevelopmentStorePreviewUpdate($input: DevelopmentStorePreviewUpdateInput!) { - developmentStorePreviewUpdate(input: $input) { - app { - id - developmentStorePreviewEnabled - } - userErrors { - message - field - } - } - } -` - -export interface DevelopmentStorePreviewUpdateInput { - input: { - apiKey: string - enabled: boolean - } -} - -export interface DevelopmentStorePreviewUpdateSchema { - developmentStorePreviewUpdate: { - app: { - id: string - developmentStorePreviewEnabled: boolean - } - userErrors: { - field: string[] - message: string - }[] - } -} diff --git a/packages/app/src/cli/api/graphql/extension_create.ts b/packages/app/src/cli/api/graphql/extension_create.ts deleted file mode 100644 index 5dc701cf80e..00000000000 --- a/packages/app/src/cli/api/graphql/extension_create.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {gql} from 'graphql-request' - -export const ExtensionCreateQuery = gql` - mutation ExtensionCreate( - $apiKey: String! - $type: ExtensionType! - $title: String! - $config: JSON! - $context: String - $handle: String - ) { - extensionCreate( - input: {apiKey: $apiKey, type: $type, title: $title, config: $config, context: $context, handle: $handle} - ) { - extensionRegistration { - id - uuid - type - title - draftVersion { - config - registrationId - lastUserInteractionAt - validationErrors { - field - message - } - } - } - userErrors { - field - message - } - } - } -` - -export interface ExtensionCreateVariables { - apiKey: string - type: string - title: string - config: string - context?: string | null - handle: string -} - -export interface ExtensionCreateSchema { - extensionCreate: { - extensionRegistration: { - id: string - uuid: string - type: string - title: string - draftVersion: { - config: string - registrationId: string - lastUserInteractionAt: string - validationErrors: { - field: string[] - message: string - }[] - } - } - userErrors: { - field: string[] - message: string - }[] - } -} diff --git a/packages/app/src/cli/api/graphql/find_app_preview_mode.ts b/packages/app/src/cli/api/graphql/find_app_preview_mode.ts deleted file mode 100644 index 421b0b70ffb..00000000000 --- a/packages/app/src/cli/api/graphql/find_app_preview_mode.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {gql} from 'graphql-request' - -export const FindAppPreviewModeQuery = gql` - query FindAppPreviewMode($apiKey: String!) { - app(apiKey: $apiKey) { - developmentStorePreviewEnabled - } - } -` - -export interface FindAppPreviewModeSchema { - app: { - developmentStorePreviewEnabled: boolean - } -} - -export interface FindAppPreviewModeVariables { - apiKey: string -} diff --git a/packages/app/src/cli/api/graphql/partners/generated/update-draft.ts b/packages/app/src/cli/api/graphql/partners/generated/update-draft.ts deleted file mode 100644 index 0d4f2e9302a..00000000000 --- a/packages/app/src/cli/api/graphql/partners/generated/update-draft.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* eslint-disable @typescript-eslint/consistent-type-definitions */ -import * as Types from './types.js' - -import {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core' - -export type ExtensionUpdateDraftMutationVariables = Types.Exact<{ - apiKey: Types.Scalars['String']['input'] - registrationId: Types.Scalars['ID']['input'] - config: Types.Scalars['JSON']['input'] - context?: Types.InputMaybe - handle?: Types.InputMaybe -}> - -export type ExtensionUpdateDraftMutation = { - extensionUpdateDraft?: {userErrors?: {field?: string[] | null; message: string}[] | null} | null -} - -export const ExtensionUpdateDraft = { - kind: 'Document', - definitions: [ - { - kind: 'OperationDefinition', - operation: 'mutation', - name: {kind: 'Name', value: 'ExtensionUpdateDraft'}, - variableDefinitions: [ - { - kind: 'VariableDefinition', - variable: {kind: 'Variable', name: {kind: 'Name', value: 'apiKey'}}, - type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}}, - }, - { - kind: 'VariableDefinition', - variable: {kind: 'Variable', name: {kind: 'Name', value: 'registrationId'}}, - type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'ID'}}}, - }, - { - kind: 'VariableDefinition', - variable: {kind: 'Variable', name: {kind: 'Name', value: 'config'}}, - type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'JSON'}}}, - }, - { - kind: 'VariableDefinition', - variable: {kind: 'Variable', name: {kind: 'Name', value: 'context'}}, - type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}, - }, - { - kind: 'VariableDefinition', - variable: {kind: 'Variable', name: {kind: 'Name', value: 'handle'}}, - type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}, - }, - ], - selectionSet: { - kind: 'SelectionSet', - selections: [ - { - kind: 'Field', - name: {kind: 'Name', value: 'extensionUpdateDraft'}, - arguments: [ - { - kind: 'Argument', - name: {kind: 'Name', value: 'input'}, - value: { - kind: 'ObjectValue', - fields: [ - { - kind: 'ObjectField', - name: {kind: 'Name', value: 'apiKey'}, - value: {kind: 'Variable', name: {kind: 'Name', value: 'apiKey'}}, - }, - { - kind: 'ObjectField', - name: {kind: 'Name', value: 'registrationId'}, - value: {kind: 'Variable', name: {kind: 'Name', value: 'registrationId'}}, - }, - { - kind: 'ObjectField', - name: {kind: 'Name', value: 'config'}, - value: {kind: 'Variable', name: {kind: 'Name', value: 'config'}}, - }, - { - kind: 'ObjectField', - name: {kind: 'Name', value: 'context'}, - value: {kind: 'Variable', name: {kind: 'Name', value: 'context'}}, - }, - { - kind: 'ObjectField', - name: {kind: 'Name', value: 'handle'}, - value: {kind: 'Variable', name: {kind: 'Name', value: 'handle'}}, - }, - ], - }, - }, - ], - selectionSet: { - kind: 'SelectionSet', - selections: [ - { - kind: 'Field', - name: {kind: 'Name', value: 'userErrors'}, - selectionSet: { - kind: 'SelectionSet', - selections: [ - {kind: 'Field', name: {kind: 'Name', value: 'field'}}, - {kind: 'Field', name: {kind: 'Name', value: 'message'}}, - {kind: 'Field', name: {kind: 'Name', value: '__typename'}}, - ], - }, - }, - {kind: 'Field', name: {kind: 'Name', value: '__typename'}}, - ], - }, - }, - ], - }, - }, - ], -} as unknown as DocumentNode diff --git a/packages/app/src/cli/api/graphql/partners/queries/update-draft.graphql b/packages/app/src/cli/api/graphql/partners/queries/update-draft.graphql deleted file mode 100644 index fde5ff2b525..00000000000 --- a/packages/app/src/cli/api/graphql/partners/queries/update-draft.graphql +++ /dev/null @@ -1,16 +0,0 @@ -mutation ExtensionUpdateDraft( - $apiKey: String! - $registrationId: ID! - $config: JSON! - $context: String - $handle: String -) { - extensionUpdateDraft( - input: {apiKey: $apiKey, registrationId: $registrationId, config: $config, context: $context, handle: $handle} - ) { - userErrors { - field - message - } - } -} diff --git a/packages/app/src/cli/commands/app/config/link.test.ts b/packages/app/src/cli/commands/app/config/link.test.ts new file mode 100644 index 00000000000..ef7244a2d61 --- /dev/null +++ b/packages/app/src/cli/commands/app/config/link.test.ts @@ -0,0 +1,83 @@ +import ConfigLink from './link.js' +import link from '../../../services/app/config/link.js' +import {linkedAppContext} from '../../../services/app-context.js' +import {testAppLinked, testOrganizationApp} from '../../../models/app/app.test-data.js' +import {inTemporaryDirectory} from '@shopify/cli-kit/node/fs' +import {beforeEach, describe, expect, test, vi} from 'vitest' + +vi.mock('../../../services/app/config/link.js') +vi.mock('../../../services/app-context.js') + +describe('app config link command', () => { + beforeEach(() => { + vi.mocked(link).mockReset() + vi.mocked(linkedAppContext).mockReset() + }) + + test('accepts --client-id with --file-name to link a specific app to a specific config file', async () => { + await inTemporaryDirectory(async (tmp) => { + const app = testAppLinked() + vi.mocked(link).mockResolvedValue({ + remoteApp: testOrganizationApp(), + configFileName: 'shopify.app.staging.toml', + configuration: app.configuration, + }) + vi.mocked(linkedAppContext).mockResolvedValue({app} as Awaited>) + + await ConfigLink.run( + ['--path', tmp, '--client-id', 'api-key', '--file-name', 'staging', '--force'], + import.meta.url, + ) + + expect(link).toHaveBeenCalledWith({ + directory: tmp, + apiKey: 'api-key', + configName: undefined, + fileName: 'staging', + force: true, + }) + expect(linkedAppContext).toHaveBeenCalledWith({ + directory: tmp, + clientId: undefined, + forceRelink: false, + userProvidedConfigName: 'shopify.app.staging.toml', + }) + }) + }) + + test('accepts --config without requiring --file-name when --force is not passed', async () => { + await inTemporaryDirectory(async (tmp) => { + const app = testAppLinked() + vi.mocked(link).mockResolvedValue({ + remoteApp: testOrganizationApp(), + configFileName: 'shopify.app.secondary.toml', + configuration: app.configuration, + }) + vi.mocked(linkedAppContext).mockResolvedValue({app} as Awaited>) + + await ConfigLink.run(['--path', tmp, '--config', 'secondary'], import.meta.url) + + expect(link).toHaveBeenCalledWith({ + directory: tmp, + apiKey: undefined, + configName: 'secondary', + fileName: undefined, + force: false, + }) + expect(linkedAppContext).toHaveBeenCalledWith({ + directory: tmp, + clientId: undefined, + forceRelink: false, + userProvidedConfigName: 'shopify.app.secondary.toml', + }) + }) + }) + + test('requires --file-name when --force is passed', async () => { + await inTemporaryDirectory(async (tmp) => { + await expect(ConfigLink.run(['--path', tmp, '--force'], import.meta.url)).rejects.toThrow() + + expect(link).not.toHaveBeenCalled() + }) + }) +}) diff --git a/packages/app/src/cli/commands/app/config/link.ts b/packages/app/src/cli/commands/app/config/link.ts index c108f2c5f9e..b51b016bab9 100644 --- a/packages/app/src/cli/commands/app/config/link.ts +++ b/packages/app/src/cli/commands/app/config/link.ts @@ -23,6 +23,18 @@ export default class ConfigLink extends AppLinkedCommand { env: 'SHOPIFY_FLAG_ORGANIZATION_ID', exclusive: ['client-id'], }), + 'file-name': Flags.string({ + hidden: false, + description: 'The name of the app configuration file to create or overwrite.', + env: 'SHOPIFY_FLAG_APP_CONFIG_FILE_NAME', + exclusive: ['config'], + }), + force: Flags.boolean({ + hidden: false, + description: 'Overwrite an existing configuration file without prompting.', + env: 'SHOPIFY_FLAG_FORCE', + dependsOn: ['file-name'], + }), } public async run(): Promise { @@ -33,6 +45,8 @@ export default class ConfigLink extends AppLinkedCommand { apiKey: flags['client-id'], organizationId: flags['organization-id'], configName: flags.config, + fileName: flags['file-name'], + force: flags.force ?? false, } const result = await link(options) diff --git a/packages/app/src/cli/commands/app/deploy.ts b/packages/app/src/cli/commands/app/deploy.ts index b5b5a437db3..dd36957d820 100644 --- a/packages/app/src/cli/commands/app/deploy.ts +++ b/packages/app/src/cli/commands/app/deploy.ts @@ -87,11 +87,9 @@ export default class Deploy extends AppLinkedCommand { cmd_app_reset_used: flags.reset, })) - const force = flags['no-release'] - // When releasing, we require --no-release or --allow-updates or --allow-deletes for non-TTY. const requiredNonTTYFlags: string[] = [] - const hasAnyForceFlags = force || flags['allow-updates'] || flags['allow-deletes'] + const hasAnyForceFlags = flags['no-release'] || flags['allow-updates'] || flags['allow-deletes'] if (!hasAnyForceFlags) { requiredNonTTYFlags.push('allow-updates') } @@ -104,8 +102,8 @@ export default class Deploy extends AppLinkedCommand { userProvidedConfigName: flags.config, }) - const allowUpdates = force || flags['allow-updates'] - const allowDeletes = force || flags['allow-deletes'] + const allowUpdates = flags['no-release'] || flags['allow-updates'] + const allowDeletes = flags['no-release'] || flags['allow-deletes'] const result = await deploy({ app, @@ -114,7 +112,6 @@ export default class Deploy extends AppLinkedCommand { organization, developerPlatformClient, reset: flags.reset, - force, allowUpdates, allowDeletes, noRelease: flags['no-release'], diff --git a/packages/app/src/cli/commands/organization/list.ts b/packages/app/src/cli/commands/organization/list.ts index 0b850a0fca4..9f56f5605dd 100644 --- a/packages/app/src/cli/commands/organization/list.ts +++ b/packages/app/src/cli/commands/organization/list.ts @@ -1,8 +1,10 @@ import {organizationList} from '../../services/organization/list.js' -import {globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli' +import {authAliasFlag, globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli' import BaseCommand from '@shopify/cli-kit/node/base-command' export default class OrganizationList extends BaseCommand { + static baseFlags = authAliasFlag + static summary = 'List Shopify organizations you have access to.' static descriptionWithMarkdown = `Lists the Shopify organizations that you have access to, along with their organization IDs.` diff --git a/packages/app/src/cli/models/app/app.test-data.ts b/packages/app/src/cli/models/app/app.test-data.ts index 5d7eb1fb90e..b60f0b612c4 100644 --- a/packages/app/src/cli/models/app/app.test-data.ts +++ b/packages/app/src/cli/models/app/app.test-data.ts @@ -41,13 +41,7 @@ import { } from '../../utilities/developer-platform-client.js' import {AllAppExtensionRegistrationsQuerySchema} from '../../api/graphql/all_app_extension_registrations.js' import {AppDeploySchema, AppDeployVariables} from '../../api/graphql/app_deploy.js' -import {ExtensionCreateSchema, ExtensionCreateVariables} from '../../api/graphql/extension_create.js' import {ConvertDevToTransferDisabledStoreVariables} from '../../api/graphql/convert_dev_to_transfer_disabled_store.js' -import { - DevelopmentStorePreviewUpdateInput, - DevelopmentStorePreviewUpdateSchema, -} from '../../api/graphql/development_preview.js' -import {FindAppPreviewModeSchema, FindAppPreviewModeVariables} from '../../api/graphql/find_app_preview_mode.js' import {SendSampleWebhookSchema, SendSampleWebhookVariables} from '../../services/webhook/request-sample.js' import {PublicApiVersionsSchema} from '../../services/webhook/request-api-versions.js' import {WebhookTopicsSchema, WebhookTopicsVariables} from '../../services/webhook/request-topics.js' @@ -67,10 +61,6 @@ import {MigrateAppModuleSchema, MigrateAppModuleVariables} from '../../api/graph import appWebhookSubscriptionSpec from '../extensions/specifications/app_config_webhook_subscription.js' import appAccessSpec from '../extensions/specifications/app_config_app_access.js' import {AppLogsSubscribeResponse} from '../../api/graphql/subscribe_to_app_logs.js' -import { - ExtensionUpdateDraftMutation, - ExtensionUpdateDraftMutationVariables, -} from '../../api/graphql/partners/generated/update-draft.js' import {SchemaDefinitionByTargetQueryVariables} from '../../api/graphql/functions/generated/schema-definition-by-target.js' import {SchemaDefinitionByApiTypeQueryVariables} from '../../api/graphql/functions/generated/schema-definition-by-api-type.js' import {AppHomeSpecIdentifier} from '../extensions/specifications/app_config_app_home.js' @@ -1221,30 +1211,6 @@ const appVersionsDiffResponse: AppVersionsDiffSchema = { }, } -export const extensionCreateResponse: ExtensionCreateSchema = { - extensionCreate: { - extensionRegistration: { - id: 'extension-id', - uuid: 'extension-uuid', - title: 'my extension', - type: 'other', - draftVersion: { - config: 'config', - registrationId: 'registration-id', - lastUserInteractionAt: '2024-01-01', - validationErrors: [], - }, - }, - userErrors: [], - }, -} - -const extensionUpdateResponse: ExtensionUpdateDraftMutation = { - extensionUpdateDraft: { - userErrors: [], - }, -} - const deployResponse: AppDeploySchema = { appDeploy: { appVersion: { @@ -1282,22 +1248,6 @@ const convertedToTransferDisabledStoreResponse = { }, } -const updateDeveloperPreviewResponse: DevelopmentStorePreviewUpdateSchema = { - developmentStorePreviewUpdate: { - app: { - id: 'app-id', - developmentStorePreviewEnabled: true, - }, - userErrors: [], - }, -} - -const appPreviewModeResponse: FindAppPreviewModeSchema = { - app: { - developmentStorePreviewEnabled: true, - }, -} - const organizationsResponse: Organization[] = [testOrganization()] const sendSampleWebhookResponse: SendSampleWebhookSchema = { @@ -1362,12 +1312,8 @@ export function testDeveloperPlatformClient(stubs: Partial Promise.resolve(testPartnersUserSession), unsafeRefreshToken: () => Promise.resolve(testPartnersUserSession.token), accountInfo: () => Promise.resolve(testPartnersUserSession.accountInfo), @@ -1390,16 +1336,11 @@ export function testDeveloperPlatformClient(stubs: Partial Promise.resolve(emptyActiveAppVersion), appVersionByTag: (_app: MinimalOrganizationApp, _tag: string) => Promise.resolve(appVersionByTagResponse), appVersionsDiff: (_input: AppVersionsDiffVariables) => Promise.resolve(appVersionsDiffResponse), - createExtension: (_input: ExtensionCreateVariables) => Promise.resolve(extensionCreateResponse), - updateExtension: (_input: ExtensionUpdateDraftMutationVariables) => Promise.resolve(extensionUpdateResponse), deploy: (_input: AppDeployVariables) => Promise.resolve(deployResponse), release: (_input: {app: MinimalAppIdentifiers; version: AppVersionIdentifiers}) => Promise.resolve(releaseResponse), generateSignedUploadUrl: (_app: MinimalAppIdentifiers) => Promise.resolve(generateSignedUploadUrlResponse), convertToTransferDisabledStore: (_input: ConvertDevToTransferDisabledStoreVariables) => Promise.resolve(convertedToTransferDisabledStoreResponse), - updateDeveloperPreview: (_input: DevelopmentStorePreviewUpdateInput) => - Promise.resolve(updateDeveloperPreviewResponse), - appPreviewMode: (_input: FindAppPreviewModeVariables) => Promise.resolve(appPreviewModeResponse), sendSampleWebhook: (_input: SendSampleWebhookVariables) => Promise.resolve(sendSampleWebhookResponse), apiVersions: () => Promise.resolve(apiVersionsResponse), topics: (_input: WebhookTopicsVariables) => Promise.resolve(topicsResponse), @@ -1447,17 +1388,7 @@ export function testDeveloperPlatformClient(stubs: Partial + key as keyof Omit ] = vi.fn().mockImplementation(value) } } diff --git a/packages/app/src/cli/models/app/app.ts b/packages/app/src/cli/models/app/app.ts index 6777a805227..c2fa8ddf53a 100644 --- a/packages/app/src/cli/models/app/app.ts +++ b/packages/app/src/cli/models/app/app.ts @@ -8,7 +8,6 @@ import {AppConfigurationUsedByCli} from '../extensions/specifications/types/app_ import {EditorExtensionCollectionType} from '../extensions/specifications/editor_extension_collection.js' import {UIExtensionSchema} from '../extensions/specifications/ui_extension.js' import {CreateAppOptions, Flag} from '../../utilities/developer-platform-client.js' -import {AppAccessSpecIdentifier} from '../extensions/specifications/app_config_app_access.js' import {configurationFileNames} from '../../constants.js' import {ApplicationURLs} from '../../services/dev/urls.js' import {patchAppHiddenConfigFile} from '../../services/app/patch-app-configuration-file.js' @@ -228,7 +227,6 @@ export interface AppInterface< allExtensions: ExtensionInstance[] realExtensions: ExtensionInstance[] nonConfigExtensions: ExtensionInstance[] - draftableExtensions: ExtensionInstance[] errors: AppErrors hiddenConfig: AppHiddenConfig includeConfigOnDeploy: boolean | undefined @@ -328,12 +326,6 @@ export class App< return this.realExtensions.filter((ext) => !ext.isAppConfigExtension) } - get draftableExtensions() { - return this.realExtensions.filter( - (ext) => ext.isUUIDStrategyExtension || ext.specification.identifier === AppAccessSpecIdentifier, - ) - } - setDevApplicationURLs(devApplicationURLs: ApplicationURLs) { this.patchAppConfiguration(devApplicationURLs) this.realExtensions.forEach((ext) => ext.patchWithAppDevURLs(devApplicationURLs)) diff --git a/packages/app/src/cli/models/app/identifiers.test.ts b/packages/app/src/cli/models/app/identifiers.test.ts index 5ad091c0ac9..e0615febd4c 100644 --- a/packages/app/src/cli/models/app/identifiers.test.ts +++ b/packages/app/src/cli/models/app/identifiers.test.ts @@ -1,12 +1,12 @@ import {updateAppIdentifiers, getAppIdentifiers} from './identifiers.js' -import {testApp, testAppWithConfig, testDeveloperPlatformClient, testUIExtension} from './app.test-data.js' +import {testApp, testAppWithConfig, testUIExtension} from './app.test-data.js' import {describe, expect, test} from 'vitest' import {readAndParseDotEnv} from '@shopify/cli-kit/node/dot-env' import {fileExists, inTemporaryDirectory, readFile, writeFile} from '@shopify/cli-kit/node/fs' import {joinPath} from '@shopify/cli-kit/node/path' describe('updateAppIdentifiers', () => { - test('persists the ids that are not env variables when deploying, creating a new file', async () => { + test('updates ids in memory when deploying without creating a new env file', async () => { await inTemporaryDirectory(async (tmpDir: string) => { // Given const uiExtension = await testUIExtension() @@ -25,19 +25,15 @@ describe('updateAppIdentifiers', () => { }, }, command: 'deploy', - developerPlatformClient: testDeveloperPlatformClient(), }) // Then - const dotEnvFile = await readAndParseDotEnv(joinPath(tmpDir, '.env')) - expect(dotEnvFile.variables.SHOPIFY_API_KEY).toEqual('FOO') - expect(dotEnvFile.variables.SHOPIFY_MY_EXTENSION_ID).toEqual('BAR') - expect(gotApp.dotenv?.variables.SHOPIFY_API_KEY).toEqual('FOO') - expect(gotApp.dotenv?.variables.SHOPIFY_MY_EXTENSION_ID).toEqual('BAR') + await expect(fileExists(joinPath(tmpDir, '.env'))).resolves.toBe(false) + expect(gotApp.dotenv).toBeUndefined() }) }) - test('persists the ids in the config-specific env file when deploying, updating the existing file', async () => { + test('does not write ids to the config-specific env file when deploying', async () => { await inTemporaryDirectory(async (tmpDir: string) => { // Given const dotEnvFilePath = joinPath(tmpDir, '.env.staging') @@ -62,20 +58,17 @@ describe('updateAppIdentifiers', () => { }, }, command: 'deploy', - developerPlatformClient: testDeveloperPlatformClient(), }) // Then const dotEnvFileContent = await readFile(dotEnvFilePath) const dotEnvFile = await readAndParseDotEnv(dotEnvFilePath) - expect(dotEnvFileContent).toEqual( - '#comment\nEXISTING_VAR=value\nSHOPIFY_MY_EXTENSION_ID=BAR\n#anothercomment\nSHOPIFY_API_KEY=FOO', - ) + expect(dotEnvFileContent).toEqual('#comment\nEXISTING_VAR=value\nSHOPIFY_MY_EXTENSION_ID=OLDID\n#anothercomment') expect(dotEnvFile.variables.EXISTING_VAR).toEqual('value') - expect(dotEnvFile.variables.SHOPIFY_API_KEY).toEqual('FOO') - expect(dotEnvFile.variables.SHOPIFY_MY_EXTENSION_ID).toEqual('BAR') - expect(gotApp.dotenv?.variables.SHOPIFY_API_KEY).toEqual('FOO') - expect(gotApp.dotenv?.variables.SHOPIFY_MY_EXTENSION_ID).toEqual('BAR') + expect(dotEnvFile.variables.SHOPIFY_API_KEY).toBeUndefined() + expect(dotEnvFile.variables.SHOPIFY_MY_EXTENSION_ID).toEqual('OLDID') + expect(gotApp.dotenv?.variables.SHOPIFY_API_KEY).toBeUndefined() + expect(gotApp.dotenv?.variables.SHOPIFY_MY_EXTENSION_ID).toBeUndefined() }) }) @@ -99,7 +92,6 @@ describe('updateAppIdentifiers', () => { }, }, command: 'deploy', - developerPlatformClient: testDeveloperPlatformClient(), }, {SHOPIFY_API_KEY: 'FOO', SHOPIFY_MY_EXTENSION_ID: 'BAR'}, ) @@ -115,7 +107,7 @@ describe('updateAppIdentifiers', () => { }) }) -test('does not change a unified config TOML with multiple when the uid is already present for atomic deployments', async () => { +test('does not change a unified config TOML with multiple when the uid is already present', async () => { await inTemporaryDirectory(async (tmpDir: string) => { // Given const uiExtension1 = await testUIExtension({ @@ -167,7 +159,6 @@ type = "ui_extension"`, }, }, command: 'deploy', - developerPlatformClient: testDeveloperPlatformClient({supportsAtomicDeployments: true}), }, {SHOPIFY_API_KEY: 'FOO', SHOPIFY_MY_EXTENSION_ID: 'BAR'}, ) diff --git a/packages/app/src/cli/models/app/identifiers.ts b/packages/app/src/cli/models/app/identifiers.ts index 773bb3759cd..ed38e1ecdb0 100644 --- a/packages/app/src/cli/models/app/identifiers.ts +++ b/packages/app/src/cli/models/app/identifiers.ts @@ -1,11 +1,9 @@ import {getDotEnvFileName} from './loader.js' import {ExtensionInstance} from '../extensions/extension-instance.js' -import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' import {patchEnvFile} from '@shopify/cli-kit/node/dot-env' import {constantize} from '@shopify/cli-kit/common/string' import {joinPath} from '@shopify/cli-kit/node/path' import {fileExists, readFile, writeFile} from '@shopify/cli-kit/node/fs' -import {deepCompare} from '@shopify/cli-kit/common/object' import type {AppInterface} from './app.js' export interface IdentifiersExtensions { @@ -38,7 +36,6 @@ interface UpdateAppIdentifiersOptions { app: AppInterface identifiers: UuidOnlyIdentifiers command: UpdateAppIdentifiersCommand - developerPlatformClient: DeveloperPlatformClient } /** @@ -47,7 +44,7 @@ interface UpdateAppIdentifiersOptions { * @returns An copy of the app with the environment updated to reflect the updated identifiers. */ export async function updateAppIdentifiers( - {app, identifiers, command, developerPlatformClient}: UpdateAppIdentifiersOptions, + {app, identifiers, command}: UpdateAppIdentifiersOptions, systemEnvironment = process.env, ): Promise { let dotenvFile = app.dotenv @@ -67,12 +64,7 @@ export async function updateAppIdentifiers( } }) - const contentIsEqual = deepCompare(dotenvFile.variables, updatedVariables) - const writeToFile = - (!contentIsEqual && - (command === 'deploy' || command === 'release') && - !developerPlatformClient.supportsAtomicDeployments) || - command === 'import-extensions' + const writeToFile = command === 'import-extensions' dotenvFile.variables = updatedVariables diff --git a/packages/app/src/cli/models/extensions/extension-instance.test.ts b/packages/app/src/cli/models/extensions/extension-instance.test.ts index a3dc4413ae0..bfb1a1680fe 100644 --- a/packages/app/src/cli/models/extensions/extension-instance.test.ts +++ b/packages/app/src/cli/models/extensions/extension-instance.test.ts @@ -346,191 +346,145 @@ describe('isFlow', async () => { }) }) -describe('draftMessages', async () => { - test('returns correct success message when the extension is draftable and not configuration', async () => { +describe('buildHandle', async () => { + test('extensions handle is either its handle or name when specification uidStrategy is uuid', async () => { // Given const extensionInstance = await testUIExtension() - // When - const result = extensionInstance.draftMessages.successMessage - + const result = extensionInstance.configuration.handle ?? slugify(extensionInstance.configuration.name ?? '') // Then - expect(result).toEqual('Draft updated successfully for extension: test-ui-extension') + expect(extensionInstance.handle).toBe(result) }) - test('returns no success message when the extension is draftable but configuration', async () => { + test('extensions handle is its identifier when specification uidStrategy is single', async () => { // Given const extensionInstance = await testAppConfigExtensions() - // When - const result = extensionInstance.draftMessages.successMessage - // Then - expect(result).toBeUndefined() + expect(extensionInstance.handle).toBe(extensionInstance.specification.identifier) }) - test('returns correct error message when the extension is draftable and not configuration', async () => { + test('extensions handle is a hashString when specification uidStrategy is dynamic and it is a webhook subscription extension', async () => { // Given - const extensionInstance = await testUIExtension() + const extensionInstance = await testSingleWebhookSubscriptionExtension() // When - const result = extensionInstance.draftMessages.errorMessage + const subscription = extensionInstance.configuration as unknown as SingleWebhookSubscriptionType + let result = '' + if (subscription) { + result = hashString(subscription.topic + subscription.uri + subscription.filter).substring( + 0, + MAX_EXTENSION_HANDLE_LENGTH, + ) + } // Then - expect(result).toEqual('Error updating extension draft for test-ui-extension') + expect(extensionInstance.handle).toBe(result) }) +}) - test('returns no error message when the extension is draftable but configuration', async () => { +describe('buildUIDFromStrategy', async () => { + test('returns specification identifier when strategy is single', async () => { // Given const extensionInstance = await testAppConfigExtensions() - // When - const result = extensionInstance.draftMessages.successMessage - // Then - expect(result).toBeUndefined() + expect(extensionInstance.uid).toBe(extensionInstance.specification.identifier) }) - describe('buildHandle', async () => { - test('extensions handle is either its handle or name when specification uidStrategy is uuid', async () => { - // Given - const extensionInstance = await testUIExtension() - - const result = extensionInstance.configuration.handle ?? slugify(extensionInstance.configuration.name ?? '') - // Then - expect(extensionInstance.handle).toBe(result) - }) - - test('extensions handle is its identifier when specification uidStrategy is single', async () => { - // Given - const extensionInstance = await testAppConfigExtensions() - - // Then - expect(extensionInstance.handle).toBe(extensionInstance.specification.identifier) + test('returns configuration uid when strategy is uuid and uid exists', async () => { + // Given + const extensionInstance = await testUIExtension({ + name: 'test-extension', + type: 'ui_extension', + uid: 'test-uid', }) - test('extensions handle is a hashString when specification uidStrategy is dynamic and it is a webhook subscription extension', async () => { - // Given - const extensionInstance = await testSingleWebhookSubscriptionExtension() - - // When - const subscription = extensionInstance.configuration as unknown as SingleWebhookSubscriptionType - let result = '' - if (subscription) { - result = hashString(subscription.topic + subscription.uri + subscription.filter).substring( - 0, - MAX_EXTENSION_HANDLE_LENGTH, - ) - } - - // Then - expect(extensionInstance.handle).toBe(result) - }) + // Then + expect(extensionInstance.uid).toBe('test-uid') }) - describe('buildUIDFromStrategy', async () => { - test('returns specification identifier when strategy is single', async () => { - // Given - const extensionInstance = await testAppConfigExtensions() - - // Then - expect(extensionInstance.uid).toBe(extensionInstance.specification.identifier) - }) - - test('returns configuration uid when strategy is uuid and uid exists', async () => { - // Given - const extensionInstance = await testUIExtension({ - name: 'test-extension', - type: 'ui_extension', - uid: 'test-uid', - }) + test('returns non-random UUID based on handle when strategy is uuid and no uid exists', async () => { + // Given + const extensionInstance = await testThemeExtensions() - // Then - expect(extensionInstance.uid).toBe('test-uid') - }) + // Then + expect(extensionInstance.uid).toBe(nonRandomUUID(extensionInstance.handle)) + }) - test('returns non-random UUID based on handle when strategy is uuid and no uid exists', async () => { - // Given - const extensionInstance = await testThemeExtensions() + test('returns a custom string when strategy is dynamic and it is a webhook subscription extension without filters', async () => { + // Given + const extensionInstance = await testSingleWebhookSubscriptionExtension() + // Then + expect(extensionInstance.uid).toBe('orders/delete::undefined::https://my-app.com/webhooks') + }) - // Then - expect(extensionInstance.uid).toBe(nonRandomUUID(extensionInstance.handle)) + test('returns a custom string when strategy is dynamic and it is a webhook subscription extension with filters', async () => { + // Given + const extensionInstance = await testSingleWebhookSubscriptionExtension({ + config: { + topic: 'orders/delete', + uri: 'https://my-app.com/webhooks', + filter: '123', + }, }) + // Then + expect(extensionInstance.uid).toBe('orders/delete::123::https://my-app.com/webhooks') + }) +}) - test('returns a custom string when strategy is dynamic and it is a webhook subscription extension without filters', async () => { - // Given - const extensionInstance = await testSingleWebhookSubscriptionExtension() - // Then - expect(extensionInstance.uid).toBe('orders/delete::undefined::https://my-app.com/webhooks') +describe('outputPath for function extensions', async () => { + test('uses default path when build is undefined', async () => { + // Given + const config = { + name: 'foo', + type: 'function', + api_version: '2023-07', + configuration_ui: true, + // build is intentionally omitted to test undefined case + } as FunctionConfigType + + const extensionInstance = await testFunctionExtension({ + config, + dir: 'test-function', }) - test('returns a custom string when strategy is dynamic and it is a webhook subscription extension with filters', async () => { - // Given - const extensionInstance = await testSingleWebhookSubscriptionExtension({ - config: { - topic: 'orders/delete', - uri: 'https://my-app.com/webhooks', - filter: '123', - }, - }) - // Then - expect(extensionInstance.uid).toBe('orders/delete::123::https://my-app.com/webhooks') - }) + // Then + expect(extensionInstance.outputPath).toBe(joinPath('test-function', 'dist', 'index.wasm')) }) - describe('outputPath for function extensions', async () => { - test('uses default path when build is undefined', async () => { - // Given - const config = { - name: 'foo', - type: 'function', - api_version: '2023-07', - configuration_ui: true, - // build is intentionally omitted to test undefined case - } as FunctionConfigType - - const extensionInstance = await testFunctionExtension({ - config, - dir: 'test-function', - }) + test('uses default path when build.path is undefined', async () => { + // Given + const config = functionConfiguration() + config.build = { + wasm_opt: true, + // path is not defined + } - // Then - expect(extensionInstance.outputPath).toBe(joinPath('test-function', 'dist', 'index.wasm')) + const extensionInstance = await testFunctionExtension({ + config, + dir: 'test-function', }) - test('uses default path when build.path is undefined', async () => { - // Given - const config = functionConfiguration() - config.build = { - wasm_opt: true, - // path is not defined - } + // Then + expect(extensionInstance.outputPath).toBe(joinPath('test-function', 'dist', 'index.wasm')) + }) - const extensionInstance = await testFunctionExtension({ - config, - dir: 'test-function', - }) + test('uses default path when build.path is defined (custom path is only applied during build)', async () => { + // Given + const config = functionConfiguration() + config.build = { + wasm_opt: true, + path: 'custom/output.wasm', + } - // Then - expect(extensionInstance.outputPath).toBe(joinPath('test-function', 'dist', 'index.wasm')) + const extensionInstance = await testFunctionExtension({ + config, + dir: 'test-function', }) - test('uses default path when build.path is defined (custom path is only applied during build)', async () => { - // Given - const config = functionConfiguration() - config.build = { - wasm_opt: true, - path: 'custom/output.wasm', - } - - const extensionInstance = await testFunctionExtension({ - config, - dir: 'test-function', - }) - - // Then - outputPath always defaults to dist/index.wasm; build.path is applied by buildFunctionExtension - expect(extensionInstance.outputPath).toBe(joinPath('test-function', 'dist', 'index.wasm')) - }) + // Then - outputPath always defaults to dist/index.wasm; build.path is applied by buildFunctionExtension + expect(extensionInstance.outputPath).toBe(joinPath('test-function', 'dist', 'index.wasm')) }) }) diff --git a/packages/app/src/cli/models/extensions/extension-instance.ts b/packages/app/src/cli/models/extensions/extension-instance.ts index cb56470d242..f651bfd5c12 100644 --- a/packages/app/src/cli/models/extensions/extension-instance.ts +++ b/packages/app/src/cli/models/extensions/extension-instance.ts @@ -163,13 +163,6 @@ export class ExtensionInstance { describe('deployOrReleaseConfirmationPrompt', () => { describe('when release', () => { - test('and force no prompt should be displayed and true returned', async () => { + test('and no release no prompt should be displayed and true returned', async () => { // Given const {extensionIdentifiersBreakdown, configExtensionIdentifiersBreakdown} = buildCompleteBreakdownInfo() const renderConfirmationPromptSpyOn = vi.spyOn(ui, 'renderConfirmationPrompt') @@ -30,8 +30,7 @@ describe('deployOrReleaseConfirmationPrompt', () => { extensionIdentifiersBreakdown, configExtensionIdentifiersBreakdown, appTitle, - release: true, - force: true, + release: false, }) // Then @@ -59,7 +58,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { configExtensionIdentifiersBreakdown, appTitle, release: true, - force: false, }) // Then @@ -104,7 +102,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle, release: true, - force: false, }) // Then @@ -159,7 +156,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle, release: true, - force: false, }) // Then @@ -220,7 +216,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle, release: true, - force: false, installCount: 1243, }) @@ -247,7 +242,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle, release: true, - force: false, installCount: 0, }) @@ -272,7 +266,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { const result = await deployOrReleaseConfirmationPrompt({ ...breakdownInfo, release: true, - force: false, }) // Then @@ -325,7 +318,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { const result = await deployOrReleaseConfirmationPrompt({ ...breakdownInfo, release: true, - force: false, showConfig: false, }) @@ -373,7 +365,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle, release: true, - force: false, }) // Then @@ -412,10 +403,9 @@ describe('deployOrReleaseConfirmationPrompt', () => { }) describe('when no release', () => { - test('and no force without extensions deleted should display the complete confirmation prompt', async () => { + test('skips the confirmation prompt', async () => { // Given const breakdownInfo = buildCompleteBreakdownInfo() - breakdownInfo.extensionIdentifiersBreakdown.onlyRemote = [] const renderConfirmationPromptSpyOn = vi.spyOn(ui, 'renderConfirmationPrompt').mockResolvedValue(true) const metadataSpyOn = vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {}) @@ -426,44 +416,15 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle, release: false, - force: false, }) // Then verifyMetada({ metadataSpyOn, - extensionIdentifiersBreakdown: breakdownInfo.extensionIdentifiersBreakdown, confirmed: result, configExtensionIdentifiersBreakdown: breakdownInfo.configExtensionIdentifiersBreakdown!, }) - expect(renderConfirmationPromptSpyOn).toHaveBeenCalledWith( - renderConfirmationPromptContent({ - appTitle, - infoTable: [ - { - header: 'Configuration:', - items: [ - {bullet: '+', item: ['new field name1', {subdued: '(new)'}], color: 'green'}, - {item: ['updating field name1', {subdued: '(updated)'}], color: '#FF8800'}, - 'existing field name1', - {bullet: '-', item: ['deleted field name1', {subdued: '(removed)'}], color: 'red'}, - ], - }, - { - header: 'Extensions:', - items: [ - {bullet: '+', item: ['to create extension (uid: uid-create)', {subdued: '(new)'}], color: 'green'}, - {item: ['to update extension', {subdued: '(updated)'}], color: '#FF8800'}, - 'unchanged extension', - ['from dashboard extension', {subdued: '(from Partner Dashboard)'}], - ], - }, - ], - dangerPrompt: false, - confirmationMessage: 'Yes, create this new version', - message: 'Create a new version of app title?', - }), - ) + expect(renderConfirmationPromptSpyOn).not.toHaveBeenCalled() expect(result).toBe(true) }) }) @@ -480,7 +441,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, allowUpdates: true, allowDeletes: true, }) @@ -505,7 +465,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, allowUpdates: true, allowDeletes: false, }) @@ -530,7 +489,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, allowUpdates: true, allowDeletes: false, }) @@ -555,7 +513,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, allowUpdates: false, allowDeletes: true, }) @@ -577,7 +534,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, allowUpdates: true, allowDeletes: false, }), @@ -596,7 +552,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, allowUpdates: false, allowDeletes: true, }), @@ -619,7 +574,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, }), ).rejects.toMatchObject({ message: 'This deployment includes changes that require confirmation.', @@ -645,7 +599,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, }), ).rejects.toMatchObject({ message: 'This deployment includes changes that require confirmation.', @@ -666,7 +619,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, }), ).rejects.toMatchObject({ message: 'This deployment includes changes that require confirmation.', @@ -687,7 +639,6 @@ describe('deployOrReleaseConfirmationPrompt', () => { ...breakdownInfo, appTitle: 'app title', release: true, - force: false, }) // Then - should show the prompt normally since there are no changes requiring confirmation diff --git a/packages/app/src/cli/prompts/deploy-release.ts b/packages/app/src/cli/prompts/deploy-release.ts index 7d779fdde7b..b94728bb1fe 100644 --- a/packages/app/src/cli/prompts/deploy-release.ts +++ b/packages/app/src/cli/prompts/deploy-release.ts @@ -18,7 +18,6 @@ interface DeployOrReleaseConfirmationPromptOptions { configExtensionIdentifiersBreakdown?: ConfigExtensionIdentifiersBreakdown appTitle?: string release: boolean - force: boolean /** If true, allow adding and updating extensions and configuration without user confirmation */ allowUpdates?: boolean /** If true, allow removing extensions and configuration without user confirmation */ @@ -46,20 +45,20 @@ interface DeployConfirmationPromptOptions { * Throws an error if in non-TTY mode and there are changes that require confirmation. */ function shouldSkipConfirmationPrompt({ - force, + release, allowUpdates, allowDeletes, extensionIdentifiersBreakdown, configExtensionIdentifiersBreakdown, }: { - force: boolean + release: boolean allowUpdates?: boolean allowDeletes?: boolean extensionIdentifiersBreakdown: ExtensionIdentifiersBreakdown configExtensionIdentifiersBreakdown?: ConfigExtensionIdentifiersBreakdown }): boolean { - // --no-release (which sets force=true internally) is equivalent to --allow-updates --allow-deletes - if (force || (allowUpdates && allowDeletes)) return true + // not releasing is equivalent to --allow-updates --allow-deletes + if (!release || (allowUpdates && allowDeletes)) return true const hasDeletedExtensions = extensionIdentifiersBreakdown.onlyRemote.length > 0 const hasDeletedConfig = (configExtensionIdentifiersBreakdown?.deletedFieldNames.length ?? 0) > 0 @@ -92,7 +91,6 @@ function shouldSkipConfirmationPrompt({ } export async function deployOrReleaseConfirmationPrompt({ - force, allowUpdates, allowDeletes, extensionIdentifiersBreakdown, @@ -104,7 +102,7 @@ export async function deployOrReleaseConfirmationPrompt({ await metadata.addPublicMetadata(() => buildConfigurationBreakdownMetadata(configExtensionIdentifiersBreakdown)) const shouldSkip = shouldSkipConfirmationPrompt({ - force, + release, allowUpdates, allowDeletes, extensionIdentifiersBreakdown, diff --git a/packages/app/src/cli/prompts/dev.test.ts b/packages/app/src/cli/prompts/dev.test.ts index 6d45b5e9dae..51eee69ee3b 100644 --- a/packages/app/src/cli/prompts/dev.test.ts +++ b/packages/app/src/cli/prompts/dev.test.ts @@ -273,44 +273,17 @@ describe('createAsNewAppPrompt', () => { }) describe('updateURLsPrompt', () => { - test('shows legacy prompt when dev sessions is disabled', async () => { + test('shows prompt without app proxy', async () => { // Given vi.mocked(renderConfirmationPrompt).mockResolvedValue(true) const currentAppUrl = 'http://current-url' - const currentRedirectUrls = ['http://current-redirect-url1', 'http://current-redirect-url2'] const newUrls = { applicationUrl: 'http://new-url', redirectUrlWhitelist: ['http://new-redirect-url'], } // When - const got = await updateURLsPrompt(false, currentAppUrl, currentRedirectUrls, newUrls) - - // Then - expect(got).toEqual(true) - expect(renderConfirmationPrompt).toHaveBeenCalledWith({ - message: "Have Shopify automatically update your app's URL in order to create a preview experience?", - infoTable: { - 'Current app URL': ['http://current-url'], - 'Current redirect URLs': ['http://current-redirect-url1', 'http://current-redirect-url2'], - }, - confirmationMessage: 'Yes, automatically update', - cancellationMessage: 'No, never', - }) - }) - - test('shows dev sessions prompt when enabled without app proxy', async () => { - // Given - vi.mocked(renderConfirmationPrompt).mockResolvedValue(true) - const currentAppUrl = 'http://current-url' - const currentRedirectUrls: string[] = [] - const newUrls = { - applicationUrl: 'http://new-url', - redirectUrlWhitelist: ['http://new-redirect-url'], - } - - // When - const got = await updateURLsPrompt(true, currentAppUrl, currentRedirectUrls, newUrls) + const got = await updateURLsPrompt(currentAppUrl, newUrls) // Then expect(got).toEqual(true) @@ -327,11 +300,10 @@ describe('updateURLsPrompt', () => { }) }) - test('shows dev sessions prompt when enabled with app proxy', async () => { + test('shows prompt with app proxy', async () => { // Given vi.mocked(renderConfirmationPrompt).mockResolvedValue(true) const currentAppUrl = 'http://current-url' - const currentRedirectUrls: string[] = [] const newUrls: ApplicationURLs = { applicationUrl: 'http://new-url', redirectUrlWhitelist: ['http://new-redirect-url'], @@ -343,7 +315,7 @@ describe('updateURLsPrompt', () => { } // When - const got = await updateURLsPrompt(true, currentAppUrl, currentRedirectUrls, newUrls) + const got = await updateURLsPrompt(currentAppUrl, newUrls) // Then expect(got).toEqual(true) diff --git a/packages/app/src/cli/prompts/dev.ts b/packages/app/src/cli/prompts/dev.ts index dcdbb7ec2c6..e8c249fda76 100644 --- a/packages/app/src/cli/prompts/dev.ts +++ b/packages/app/src/cli/prompts/dev.ts @@ -154,39 +154,15 @@ export async function createAsNewAppPrompt(): Promise { }) } -export function updateURLsPrompt( - usingDevSessions: boolean, - currentAppUrl: string, - currentRedirectUrls: string[], - newURLs: ApplicationURLs, -): Promise { - if (usingDevSessions) { - return updateURLsPromptWithDevSessions(currentAppUrl, newURLs) - } - return legacyUpdateURLsPrompt(currentAppUrl, currentRedirectUrls) -} - -function legacyUpdateURLsPrompt(currentAppUrl: string, currentRedirectUrls: string[]): Promise { - return renderConfirmationPrompt({ - message: "Have Shopify automatically update your app's URL in order to create a preview experience?", - confirmationMessage: 'Yes, automatically update', - cancellationMessage: 'No, never', - infoTable: { - 'Current app URL': [currentAppUrl], - 'Current redirect URLs': currentRedirectUrls, - }, - }) -} - -function updateURLsPromptWithDevSessions(currentAppUrl: string, urls: ApplicationURLs): Promise { +export function updateURLsPrompt(currentAppUrl: string, newURLs: ApplicationURLs): Promise { const affectedConfigs = ['application_url', 'redirect_urls'] - if (urls.appProxy?.proxyUrl) { + if (newURLs.appProxy?.proxyUrl) { affectedConfigs.push('app_proxy') } const infoTable: {[key: string]: string[]} = { 'Currently released app URL': [currentAppUrl], - '=> Dev URL': [urls.applicationUrl], + '=> Dev URL': [newURLs.applicationUrl], 'Affected configurations': affectedConfigs, } diff --git a/packages/app/src/cli/services/app-context.ts b/packages/app/src/cli/services/app-context.ts index 4000c37764e..00d37b86fce 100644 --- a/packages/app/src/cli/services/app-context.ts +++ b/packages/app/src/cli/services/app-context.ts @@ -152,10 +152,10 @@ export async function linkedAppContext({ await logMetadata(remoteApp, organization, forceRelink) - // Add UIDs to extension TOML files if using app-management. + // Add UIDs to UUID-strategy extension TOML files. // Only safe when there are no errors — errors may mean UIDs weren't loaded correctly. if (localApp.errors.isEmpty()) { - await addUidToTomlsIfNecessary(localApp.allExtensions, developerPlatformClient) + await addUidToTomlsIfNecessary(localApp.allExtensions) } return {project, activeConfig, app: localApp, remoteApp, developerPlatformClient, specifications, organization} diff --git a/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts b/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts index e3d91805dfd..54420977ebf 100644 --- a/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts +++ b/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts @@ -1,43 +1,10 @@ import {addUidToTomlsIfNecessary} from './add-uid-to-extension-toml.js' import {ExtensionInstance} from '../../models/extensions/extension-instance.js' -import {testDeveloperPlatformClient, testUIExtension} from '../../models/app/app.test-data.js' import {describe, test, expect} from 'vitest' import {writeFile, readFile, inTemporaryDirectory} from '@shopify/cli-kit/node/fs' import {joinPath} from '@shopify/cli-kit/node/path' describe('addUidToTomlsIfNecessary', () => { - test('skips if platform does not support atomic deployments', async () => { - await inTemporaryDirectory(async (tmpDir) => { - // Given - const tomlPath = joinPath(tmpDir, 'extension.toml') - const tomlContent = ` - type = "checkout_ui_extension" - handle = "my-extension" - ` - await writeFile(tomlPath, tomlContent) - - const extension = await testUIExtension({ - directory: tmpDir, - configuration: { - handle: 'my-extension', - type: 'checkout_ui_extension', - name: 'test', - }, - configurationPath: tomlPath, - uid: '123', - }) - - const client = testDeveloperPlatformClient({supportsAtomicDeployments: false}) - - // When - await addUidToTomlsIfNecessary([extension], client) - - // Then - const updatedContent = await readFile(tomlPath) - expect(updatedContent).toBe(tomlContent) - }) - }) - test('adds uid to single extension TOML', async () => { await inTemporaryDirectory(async (tmpDir) => { // Given @@ -56,10 +23,8 @@ describe('addUidToTomlsIfNecessary', () => { configuration: {}, } as ExtensionInstance - const client = testDeveloperPlatformClient({supportsAtomicDeployments: true}) - // When - await addUidToTomlsIfNecessary([extension], client) + await addUidToTomlsIfNecessary([extension]) // Then const updatedContent = await readFile(tomlPath) @@ -97,10 +62,8 @@ scopes = "write_metaobject_definitions,write_metaobjects,write_products" configuration: {}, } as ExtensionInstance - const client = testDeveloperPlatformClient({supportsAtomicDeployments: true}) - // When - await addUidToTomlsIfNecessary([extension], client) + await addUidToTomlsIfNecessary([extension]) // Then — uid must be inside the [[extensions]] block (right after handle), not at // the top level of the file. @@ -155,10 +118,8 @@ scopes = "write_metaobject_definitions,write_metaobjects,write_products" configuration: {}, } as ExtensionInstance - const client = testDeveloperPlatformClient({supportsAtomicDeployments: true}) - // When - await addUidToTomlsIfNecessary([extension, extension1], client) + await addUidToTomlsIfNecessary([extension, extension1]) // Then const updatedContent = await readFile(tomlPath) @@ -197,10 +158,8 @@ scopes = "write_metaobject_definitions,write_metaobjects,write_products" }, } as ExtensionInstance - const client = testDeveloperPlatformClient({supportsAtomicDeployments: true}) - // When - await addUidToTomlsIfNecessary([extension], client) + await addUidToTomlsIfNecessary([extension]) // Then const updatedContent = await readFile(tomlPath) @@ -226,10 +185,8 @@ scopes = "write_metaobject_definitions,write_metaobjects,write_products" configuration: {}, } as ExtensionInstance - const client = testDeveloperPlatformClient({supportsAtomicDeployments: true}) - // When - await addUidToTomlsIfNecessary([extension], client) + await addUidToTomlsIfNecessary([extension]) // Then const updatedContent = await readFile(tomlPath) diff --git a/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts b/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts index 34b4aa17b2f..802a00af553 100644 --- a/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts +++ b/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts @@ -1,14 +1,8 @@ import {ExtensionInstance} from '../../models/extensions/extension-instance.js' -import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' import {TomlFile} from '@shopify/cli-kit/node/toml/toml-file' import {getPathValue} from '@shopify/cli-kit/common/object' -export async function addUidToTomlsIfNecessary( - extensions: ExtensionInstance[], - developerPlatformClient: DeveloperPlatformClient, -) { - if (!developerPlatformClient.supportsAtomicDeployments) return - +export async function addUidToTomlsIfNecessary(extensions: ExtensionInstance[]) { // We can't update the TOML files in parallel because some extensions might share the same file for (const extension of extensions) { // eslint-disable-next-line no-await-in-loop diff --git a/packages/app/src/cli/services/app/config/__snapshots__/link.test.ts.snap b/packages/app/src/cli/services/app/config/__snapshots__/link.test.ts.snap index ce03398d6be..9994e232c7f 100644 --- a/packages/app/src/cli/services/app/config/__snapshots__/link.test.ts.snap +++ b/packages/app/src/cli/services/app/config/__snapshots__/link.test.ts.snap @@ -79,6 +79,7 @@ use_legacy_install_flow = true [build] include_config_on_deploy = true +automatically_update_urls_on_dev = true " `; @@ -515,6 +516,7 @@ url = "https://api-client-config.com/preferences" [build] include_config_on_deploy = true +automatically_update_urls_on_dev = true " `; @@ -542,10 +544,11 @@ embedded = false [build] include_config_on_deploy = true +automatically_update_urls_on_dev = true " `; -exports[`link > when remote app is new and supports dev sessions then include automatically_update_urls_on_dev = true 1`] = ` +exports[`link > when remote app is new then include automatically_update_urls_on_dev = true 1`] = ` "# Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration application_url = "https://example.com" diff --git a/packages/app/src/cli/services/app/config/link-service.test.ts b/packages/app/src/cli/services/app/config/link-service.test.ts index 1fb6aba1059..fca01a594c5 100644 --- a/packages/app/src/cli/services/app/config/link-service.test.ts +++ b/packages/app/src/cli/services/app/config/link-service.test.ts @@ -29,7 +29,6 @@ beforeEach(async () => { function buildDeveloperPlatformClient(): DeveloperPlatformClient { return testDeveloperPlatformClient({ - supportsDevSessions: true, async appFromIdentifiers(apiKey: string): Promise { switch (apiKey) { case 'api-key': diff --git a/packages/app/src/cli/services/app/config/link.test.ts b/packages/app/src/cli/services/app/config/link.test.ts index ff69cf0f38a..3088fb07db1 100644 --- a/packages/app/src/cli/services/app/config/link.test.ts +++ b/packages/app/src/cli/services/app/config/link.test.ts @@ -115,6 +115,76 @@ describe('link', () => { }) }) + test('does not ask for a name when a file name is provided as a flag', async () => { + await inTemporaryDirectory(async (tmp) => { + // Given + const developerPlatformClient = buildDeveloperPlatformClient() + const options: LinkOptions = { + directory: tmp, + fileName: 'staging', + developerPlatformClient, + } + await mockLoadOpaqueAppWithApp(tmp) + vi.mocked(fetchOrCreateOrganizationApp).mockResolvedValue(mockRemoteApp({developerPlatformClient})) + + // When + const {configFileName} = await link(options) + + // Then + expect(selectConfigName).not.toHaveBeenCalled() + expect(configFileName).toBe('shopify.app.staging.toml') + expect(fileExistsSync(joinPath(tmp, 'shopify.app.staging.toml'))).toBeTruthy() + }) + }) + + test('throws when a file name is provided for an existing file without force', async () => { + await inTemporaryDirectory(async (tmp) => { + // Given + const developerPlatformClient = buildDeveloperPlatformClient() + const options: LinkOptions = { + directory: tmp, + fileName: 'staging', + developerPlatformClient, + } + writeFileSync(joinPath(tmp, 'shopify.app.staging.toml'), 'client_id = "12345"') + await mockLoadOpaqueAppWithApp(tmp) + vi.mocked(fetchOrCreateOrganizationApp).mockResolvedValue(mockRemoteApp({developerPlatformClient})) + + // When + const result = link(options) + + // Then + await expect(result).rejects.toThrow(/Configuration file shopify\.app\.staging\.toml already exists/) + expect(selectConfigName).not.toHaveBeenCalled() + }) + }) + + test('overwrites an existing file name when force is provided', async () => { + await inTemporaryDirectory(async (tmp) => { + // Given + const developerPlatformClient = buildDeveloperPlatformClient() + const options: LinkOptions = { + directory: tmp, + fileName: 'staging', + force: true, + developerPlatformClient, + } + writeFileSync(joinPath(tmp, 'shopify.app.staging.toml'), 'name = "old app"') + await mockLoadOpaqueAppWithApp(tmp) + vi.mocked(fetchOrCreateOrganizationApp).mockResolvedValue(mockRemoteApp({developerPlatformClient})) + + // When + const {configFileName} = await link(options) + + // Then + const content = await readFile(joinPath(tmp, 'shopify.app.staging.toml')) + expect(selectConfigName).not.toHaveBeenCalled() + expect(configFileName).toBe('shopify.app.staging.toml') + expect(content).toContain('client_id = "12345"') + expect(content).not.toContain('old app') + }) + }) + test('does not ask for a name when the selected app is already linked', async () => { await inTemporaryDirectory(async (tmp) => { // Given @@ -241,6 +311,7 @@ describe('link', () => { }, build: { include_config_on_deploy: true, + automatically_update_urls_on_dev: true, }, }) expect(content).toMatchSnapshot() @@ -342,6 +413,7 @@ describe('link', () => { }, build: { include_config_on_deploy: true, + automatically_update_urls_on_dev: true, }, }) expect(content).toMatchSnapshot() @@ -1195,14 +1267,14 @@ describe('link', () => { }) }) - test('when remote app is new and supports dev sessions then include automatically_update_urls_on_dev = true', async () => { + test('when remote app is new then include automatically_update_urls_on_dev = true', async () => { await inTemporaryDirectory(async (tmp) => { // Given const filePath = joinPath(tmp, 'shopify.app.toml') const initialContent = `scopes = "" ` writeFileSync(filePath, initialContent) - const developerPlatformClient = buildDeveloperPlatformClient({supportsDevSessions: true}) + const developerPlatformClient = buildDeveloperPlatformClient() const options: LinkOptions = { directory: tmp, developerPlatformClient, diff --git a/packages/app/src/cli/services/app/config/link.ts b/packages/app/src/cli/services/app/config/link.ts index df7722cb194..5ef02ac9dda 100644 --- a/packages/app/src/cli/services/app/config/link.ts +++ b/packages/app/src/cli/services/app/config/link.ts @@ -26,6 +26,7 @@ import {loadLocalExtensionsSpecifications} from '../../../models/extensions/load import {renderSuccess} from '@shopify/cli-kit/node/ui' import {formatPackageManagerCommand} from '@shopify/cli-kit/node/output' import {deepMergeObjects, isEmpty} from '@shopify/cli-kit/common/object' +import {fileExists} from '@shopify/cli-kit/node/fs' import {joinPath} from '@shopify/cli-kit/node/path' import {AbortError} from '@shopify/cli-kit/node/error' import {PackageManager} from '@shopify/cli-kit/node/node-package-manager' @@ -36,6 +37,8 @@ export interface LinkOptions { appId?: string organizationId?: string configName?: string + fileName?: string + force?: boolean developerPlatformClient?: DeveloperPlatformClient isNewApp?: boolean } @@ -297,6 +300,18 @@ async function loadConfigurationFileName( appDirectory?: string }, ): Promise { + if (options.fileName) { + const fileName = getAppConfigurationFileName(options.fileName) + const appDirectory = localAppInfo.appDirectory ?? options.directory + if (!options.force && (await fileExists(joinPath(appDirectory, fileName)))) { + throw new AbortError( + `Configuration file ${fileName} already exists.`, + 'Run the command with --force to overwrite it.', + ) + } + return fileName + } + if (options.configName) { return getAppConfigurationFileName(options.configName) } @@ -360,7 +375,7 @@ export async function overwriteLocalConfigFileWithRemoteAppConfiguration(options existingBuildOptions: localAppOptions.existingBuildOptions, linkedAppAndClientIdFromFileAreInSync: localAppOptions.localAppIdMatchedRemote, linkedAppWasNewlyCreated: Boolean(remoteApp.newApp), - defaultToUpdateUrlsOnDev: developerPlatformClient.supportsDevSessions, + defaultToUpdateUrlsOnDev: true, }), } diff --git a/packages/app/src/cli/services/context.test.ts b/packages/app/src/cli/services/context.test.ts index 9e5b1589e4b..dd8bf8e6488 100644 --- a/packages/app/src/cli/services/context.test.ts +++ b/packages/app/src/cli/services/context.test.ts @@ -2,29 +2,20 @@ import {fetchOrganizations, fetchOrgFromId} from './dev/fetch.js' import {selectOrCreateApp} from './dev/select-app.js' import {selectStore} from './dev/select-store.js' import {ensureDeploymentIdsPresence} from './context/identifiers.js' -import {appFromIdentifiers, ensureDeployContext, ensureThemeExtensionDevContext} from './context.js' -import {createExtension} from './dev/create-extension.js' +import {appFromIdentifiers, ensureDeployContext} from './context.js' import {CachedAppInfo} from './local-storage.js' import link from './app/config/link.js' import {fetchSpecifications} from './generate/fetch-extension-specifications.js' import {DeployOptions} from './deploy.js' -import { - MinimalAppIdentifiers, - Organization, - OrganizationApp, - OrganizationSource, - OrganizationStore, -} from '../models/organization.js' +import {Organization, OrganizationApp, OrganizationSource, OrganizationStore} from '../models/organization.js' import {getAppIdentifiers} from '../models/app/identifiers.js' import { testDeveloperPlatformClient, testAppWithConfig, testOrganizationApp, - testThemeExtensions, testProject, } from '../models/app/app.test-data.js' -import metadata from '../metadata.js' -import {getAppConfigurationFileName, isWebType, loadApp} from '../models/app/loader.js' +import {getAppConfigurationFileName, isWebType} from '../models/app/loader.js' import {AppLinkedInterface} from '../models/app/app.js' import * as loadSpecifications from '../models/extensions/load-specifications.js' import { @@ -37,7 +28,6 @@ import {selectOrganizationPrompt} from '@shopify/organizations' import {TomlFile} from '@shopify/cli-kit/node/toml/toml-file' import {isServiceAccount, isUserAccount} from '@shopify/cli-kit/node/session' import {afterEach, beforeAll, beforeEach, describe, expect, test, vi} from 'vitest' -import {AbortError} from '@shopify/cli-kit/node/error' import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' import {getPackageManager} from '@shopify/cli-kit/node/node-package-manager' import {renderConfirmationPrompt, renderInfo, renderTasks, renderWarning, Task} from '@shopify/cli-kit/node/ui' @@ -84,7 +74,8 @@ const deployOptions = (app: AppLinkedInterface, reset = false, force = false): D remoteApp: APP2, organization: ORG1, reset, - force, + allowUpdates: force, + allowDeletes: force, noRelease: false, developerPlatformClient: buildDeveloperPlatformClient(), skipBuild: false, @@ -114,7 +105,6 @@ function buildDeveloperPlatformClient(extras?: Partial) vi.mock('./local-storage.js') vi.mock('./dev/fetch') -vi.mock('./dev/create-extension') vi.mock('./dev/select-app') vi.mock('./dev/select-store') vi.mock('../prompts/dev') @@ -181,168 +171,7 @@ afterEach(() => { }) describe('ensureDeployContext', () => { - test('prompts the user to include the configuration if the flag is false and current config is false', async () => { - // Given - const app = testAppWithConfig({config: {client_id: APP2.apiKey, build: {include_config_on_deploy: false}}}) - const identifiers = { - app: APP2.apiKey, - extensions: {}, - extensionIds: {}, - extensionsNonUuidManaged: {}, - } - vi.mocked(getAppIdentifiers).mockReturnValue({app: undefined}) - vi.mocked(ensureDeploymentIdsPresence).mockResolvedValue(identifiers) - vi.mocked(loadApp).mockResolvedValue(app) - vi.mocked(link).mockResolvedValue((app as any).configuration) - vi.mocked(getAppConfigurationFileName).mockReturnValue('shopify.app.toml') - mockTomlFilePatch.mockResolvedValue(undefined) - const metadataSpyOn = vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {}) - - const options = deployOptions(app) - vi.mocked(selectDeveloperPlatformClient).mockReturnValue(options.developerPlatformClient) - - // When - await ensureDeployContext(options) - - // Then - expect(metadataSpyOn).toHaveBeenCalled() - - expect(renderConfirmationPrompt).toHaveBeenCalled() - expect(mockTomlFilePatch).toHaveBeenCalled() - expect(renderInfo).toHaveBeenCalledWith({ - body: [ - { - list: { - items: ['Org: org1', 'App: app2', 'Include config: No'], - }, - }, - '\n', - 'You can pass', - { - command: '--reset', - }, - 'to your command to reset your app configuration.', - ], - headline: 'Using shopify.app.toml for default values:', - }) - mockTomlFilePatch.mockClear() - }) - - test('doesnt prompt the user to include the configuration and display the current value if the config is true', async () => { - // Given - const app = testAppWithConfig({config: {client_id: APP2.apiKey, build: {include_config_on_deploy: true}}}) - const identifiers = { - app: APP2.apiKey, - extensions: {}, - extensionIds: {}, - extensionsNonUuidManaged: {}, - } - vi.mocked(getAppIdentifiers).mockReturnValue({app: undefined}) - vi.mocked(ensureDeploymentIdsPresence).mockResolvedValue(identifiers) - vi.mocked(loadApp).mockResolvedValue(app) - vi.mocked(link).mockResolvedValue((app as any).configuration) - // vi.mocked(selectDeveloperPlatformClient).mockReturnValue(testDeveloperPlatformClient) - vi.mocked(getAppConfigurationFileName).mockReturnValue('shopify.app.toml') - mockTomlFilePatch.mockResolvedValue(undefined) - const metadataSpyOn = vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {}) - - const options = deployOptions(app) - vi.mocked(selectDeveloperPlatformClient).mockReturnValue(options.developerPlatformClient) - - // When - await ensureDeployContext(options) - - // Then - expect(metadataSpyOn).not.toHaveBeenCalled() - - expect(renderConfirmationPrompt).not.toHaveBeenCalled() - expect(mockTomlFilePatch).not.toHaveBeenCalled() - expect(renderInfo).toHaveBeenCalledWith({ - body: [ - { - list: { - items: ['Org: org1', 'App: app2', 'Include config: Yes'], - }, - }, - '\n', - 'You can pass', - { - command: '--reset', - }, - 'to your command to reset your app configuration.', - ], - headline: 'Using shopify.app.toml for default values:', - }) - mockTomlFilePatch.mockClear() - }) - - test('prompts the user to include the configuration when reset is used and the flag is present', async () => { - // Given - const app = testAppWithConfig({config: {client_id: APP2.apiKey, build: {include_config_on_deploy: true}}}) - const identifiers = { - app: APP2.apiKey, - extensions: {}, - extensionIds: {}, - extensionsNonUuidManaged: {}, - } - vi.mocked(ensureDeploymentIdsPresence).mockResolvedValue(identifiers) - vi.mocked(renderConfirmationPrompt).mockResolvedValue(false) - vi.mocked(getAppConfigurationFileName).mockReturnValue('shopify.app.toml') - mockTomlFilePatch.mockResolvedValue(undefined) - const metadataSpyOn = vi.spyOn(metadata, 'addPublicMetadata').mockImplementation(async () => {}) - - const options = deployOptions(app, true) - vi.mocked(selectDeveloperPlatformClient).mockReturnValue(options.developerPlatformClient) - // When - await ensureDeployContext(deployOptions(app, true)) - - // Then - expect(metadataSpyOn).toHaveBeenNthCalledWith(1, expect.any(Function)) - expect(metadataSpyOn.mock.calls[0]![0]()).toEqual({cmd_deploy_confirm_include_config_used: false}) - - expect(renderConfirmationPrompt).toHaveBeenCalled() - expect(mockTomlFilePatch).toHaveBeenCalledWith({build: {include_config_on_deploy: false}}) - - expect(renderInfo).toHaveBeenCalledWith({ - body: [ - { - list: { - items: ['Org: org1', 'App: app2', 'Include config: No'], - }, - }, - '\n', - 'You can pass', - { - command: '--reset', - }, - 'to your command to reset your app configuration.', - ], - headline: 'Using shopify.app.toml for default values:', - }) - mockTomlFilePatch.mockClear() - }) - - test('aborts when force is true and include_config_on_deploy is not set on Partners', async () => { - // Given - const app = testAppWithConfig({config: {client_id: APP2.apiKey}}) - const identifiers = { - app: APP2.apiKey, - extensions: {}, - extensionIds: {}, - extensionsNonUuidManaged: {}, - } - vi.mocked(ensureDeploymentIdsPresence).mockResolvedValue(identifiers) - vi.mocked(getAppConfigurationFileName).mockReturnValue('shopify.app.toml') - - const options = deployOptions(app, false, true) - vi.mocked(selectDeveloperPlatformClient).mockReturnValue(options.developerPlatformClient) - - // When/Then - await expect(ensureDeployContext(options)).rejects.toThrowError(AbortError) - await expect(ensureDeployContext(options)).rejects.toThrow('You must specify a value for') - }) - - test('does not abort when force is true and include_config_on_deploy is not set for App Management', async () => { + test('does not abort when force is true and include_config_on_deploy is not set', async () => { // Given const app = testAppWithConfig({config: {client_id: APP2.apiKey}}) const identifiers = { @@ -356,7 +185,7 @@ describe('ensureDeployContext', () => { const options = { ...deployOptions(app, false, true), - developerPlatformClient: buildDeveloperPlatformClient({supportsAtomicDeployments: true}), + developerPlatformClient: buildDeveloperPlatformClient({}), } vi.mocked(selectDeveloperPlatformClient).mockReturnValue(options.developerPlatformClient) @@ -364,45 +193,6 @@ describe('ensureDeployContext', () => { await expect(ensureDeployContext(options)).resolves.toBeDefined() }) - test('prompts the user to include the configuration when force is used and the flag is present', async () => { - // Given - const app = testAppWithConfig({config: {client_id: APP2.apiKey, build: {include_config_on_deploy: true}}}) - const identifiers = { - app: APP2.apiKey, - extensions: {}, - extensionIds: {}, - extensionsNonUuidManaged: {}, - } - vi.mocked(ensureDeploymentIdsPresence).mockResolvedValue(identifiers) - vi.mocked(renderConfirmationPrompt).mockResolvedValue(false) - vi.mocked(getAppConfigurationFileName).mockReturnValue('shopify.app.toml') - mockTomlFilePatch.mockResolvedValue(undefined) - - // When - await ensureDeployContext(deployOptions(app, false, true)) - - // Then - expect(renderConfirmationPrompt).not.toHaveBeenCalled() - expect(mockTomlFilePatch).not.toHaveBeenCalled() - expect(renderInfo).toHaveBeenCalledWith({ - body: [ - { - list: { - items: ['Org: org1', 'App: app2', 'Include config: Yes'], - }, - }, - '\n', - 'You can pass', - { - command: '--reset', - }, - 'to your command to reset your app configuration.', - ], - headline: 'Using shopify.app.toml for default values:', - }) - mockTomlFilePatch.mockClear() - }) - test('removes the include_config_on_deploy field when using app management API and the value is true', async () => { // Given const app = testAppWithConfig({config: {client_id: APP2.apiKey, build: {include_config_on_deploy: true}}}) @@ -423,9 +213,8 @@ describe('ensureDeployContext', () => { remoteApp: APP2, organization: ORG1, reset: false, - force: false, noRelease: false, - developerPlatformClient: buildDeveloperPlatformClient({supportsAtomicDeployments: true}), + developerPlatformClient: buildDeveloperPlatformClient({}), skipBuild: false, } await ensureDeployContext(options) @@ -466,9 +255,8 @@ describe('ensureDeployContext', () => { remoteApp: APP2, organization: ORG1, reset: false, - force: false, noRelease: false, - developerPlatformClient: buildDeveloperPlatformClient({supportsAtomicDeployments: true}), + developerPlatformClient: buildDeveloperPlatformClient({}), skipBuild: false, } await ensureDeployContext(options) @@ -515,7 +303,6 @@ describe('ensureDeployContext', () => { } const developerPlatformClient = buildDeveloperPlatformClient({ - supportsAtomicDeployments: true, activeAppVersion: () => Promise.resolve(activeAppVersion), }) @@ -526,7 +313,6 @@ describe('ensureDeployContext', () => { remoteApp: APP2, organization: ORG1, reset: false, - force: false, noRelease: false, developerPlatformClient, skipBuild: false, @@ -562,7 +348,6 @@ describe('ensureDeployContext', () => { } const developerPlatformClient = buildDeveloperPlatformClient({ - supportsAtomicDeployments: true, activeAppVersion: () => Promise.resolve(activeAppVersion), }) @@ -573,7 +358,6 @@ describe('ensureDeployContext', () => { remoteApp: APP2, organization: ORG1, reset: false, - force: false, noRelease: false, developerPlatformClient, skipBuild: false, @@ -584,70 +368,6 @@ describe('ensureDeployContext', () => { }) }) -describe('ensureThemeExtensionDevContext', () => { - test('fetches theme extension when it exists', async () => { - // Given - const apiKey = 'apiKey' - const extension = await testThemeExtensions() - - const mockedExtensionRegistrations = { - app: { - extensionRegistrations: [ - { - id: 'other ID', - uuid: 'other UUID', - title: 'other extension', - type: 'other', - }, - { - id: 'existing ID', - uuid: 'UUID', - title: 'theme app extension', - type: 'THEME_APP_EXTENSION', - }, - ], - configurationRegistrations: [], - dashboardManagedExtensionRegistrations: [], - }, - } - - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - appExtensionRegistrations: (_app: MinimalAppIdentifiers) => Promise.resolve(mockedExtensionRegistrations), - }) - - // When - const got = await ensureThemeExtensionDevContext(extension, apiKey, developerPlatformClient) - - // Then - expect('existing ID').toEqual(got.id) - expect('UUID').toEqual(got.uuid) - expect('theme app extension').toEqual(got.title) - expect('THEME_APP_EXTENSION').toEqual(got.type) - }) - - test('creates theme extension when it does not exist', async () => { - // Given - const apiKey = 'apiKey' - const extension = await testThemeExtensions() - - vi.mocked(createExtension).mockResolvedValue({ - id: 'new ID', - uuid: 'UUID', - title: 'theme app extension', - type: 'THEME_APP_EXTENSION', - }) - - // When - const got = await ensureThemeExtensionDevContext(extension, apiKey, buildDeveloperPlatformClient()) - - // Then - expect('new ID').toEqual(got.id) - expect('UUID').toEqual(got.uuid) - expect('theme app extension').toEqual(got.title) - expect('THEME_APP_EXTENSION').toEqual(got.type) - }) -}) - describe('appFromIdentifiers', () => { test('renders the org name when an app cannot be found and the account is a service account ', async () => { vi.mocked(isServiceAccount).mockReturnValue(true) diff --git a/packages/app/src/cli/services/context.ts b/packages/app/src/cli/services/context.ts index 41555451f9d..d2d81730080 100644 --- a/packages/app/src/cli/services/context.ts +++ b/packages/app/src/cli/services/context.ts @@ -1,7 +1,6 @@ import {selectOrCreateApp} from './dev/select-app.js' import {fetchOrganizations, fetchOrgFromId} from './dev/fetch.js' import {ensureDeploymentIdsPresence} from './context/identifiers.js' -import {createExtension} from './dev/create-extension.js' import {CachedAppInfo} from './local-storage.js' import {DeployOptions} from './deploy.js' import {formatConfigInfoBody} from './format-config-info-body.js' @@ -10,24 +9,17 @@ import {Identifiers, updateAppIdentifiers, getAppIdentifiers} from '../models/ap import {Organization, OrganizationApp, OrganizationSource, OrganizationStore} from '../models/organization.js' import metadata from '../metadata.js' import {getAppConfigurationFileName} from '../models/app/loader.js' -import {ExtensionInstance} from '../models/extensions/extension-instance.js' -import {ExtensionRegistration} from '../api/graphql/all_app_extension_registrations.js' -import { - DevelopmentStorePreviewUpdateInput, - DevelopmentStorePreviewUpdateSchema, -} from '../api/graphql/development_preview.js' import { allDeveloperPlatformClients, CreateAppOptions, - DeveloperPlatformClient, selectDeveloperPlatformClient, } from '../utilities/developer-platform-client.js' import {selectOrganizationPrompt} from '@shopify/organizations' import {TomlFile} from '@shopify/cli-kit/node/toml/toml-file' import {isServiceAccount, isUserAccount} from '@shopify/cli-kit/node/session' import {tryParseInt} from '@shopify/cli-kit/common/string' -import {Token, renderConfirmationPrompt, renderInfo, renderWarning} from '@shopify/cli-kit/node/ui' +import {Token, renderInfo, renderWarning} from '@shopify/cli-kit/node/ui' import {AbortError} from '@shopify/cli-kit/node/error' import {outputContent} from '@shopify/cli-kit/node/output' import {basename, sniffForJson} from '@shopify/cli-kit/node/path' @@ -108,29 +100,6 @@ export const appFromIdentifiers = async (options: AppFromIdOptions): Promise { - const remoteSpecifications = await developerPlatformClient.appExtensionRegistrations({ - id: apiKey, - apiKey, - organizationId: '1', - }) - const remoteRegistration = remoteSpecifications.app.extensionRegistrations.find((extension) => { - return extension.type === 'THEME_APP_EXTENSION' - }) - - if (remoteRegistration) { - return remoteRegistration - } - - const registration = await createExtension(apiKey, extension.graphQLType, extension.handle, developerPlatformClient) - - return registration -} - interface EnsureDeployContextResult { identifiers: Identifiers didMigrateExtensionsToDevDash: boolean @@ -149,17 +118,16 @@ interface EnsureDeployContextResult { * @returns The selected org, app and dev store */ export async function ensureDeployContext(options: DeployOptions): Promise { - const {reset, force, noRelease, app, remoteApp, developerPlatformClient, organization} = options + const {noRelease, app, remoteApp, developerPlatformClient, organization} = options const activeAppVersion = await developerPlatformClient.activeAppVersion(remoteApp) - const includeConfigOnDeploy = await checkIncludeConfigOnDeploy({app, reset, force, developerPlatformClient}) + await removeIncludeConfigOnDeployField(app) renderCurrentlyUsedConfigInfo({ org: organization.businessName, appName: remoteApp.title, appDotEnv: app.dotenv?.path, configFile: basename(app.configPath), - includeConfigOnDeploy, messages: [resetHelpMessage], }) @@ -167,7 +135,6 @@ export async function ensureDeployContext(options: DeployOptions): Promise !version.registrationId) } return {identifiers, didMigrateExtensionsToDevDash} } -interface ShouldOrPromptIncludeConfigDeployOptions { - appDirectory: string - localApp: AppInterface -} - -async function checkIncludeConfigOnDeploy({ - app, - reset, - force, - developerPlatformClient, -}: { - app: AppInterface - reset: boolean - force: boolean - developerPlatformClient: DeveloperPlatformClient -}): Promise { - if (developerPlatformClient.supportsAtomicDeployments) { - await removeIncludeConfigOnDeployField(app) - return undefined - } - - let includeConfigOnDeploy = app.includeConfigOnDeploy - if (reset) includeConfigOnDeploy = undefined - - if (force && includeConfigOnDeploy === undefined) { - // If a partner is deploying on CI/CD with include_config_on_deploy not set, - // we need to abort the deploy, because the default value changed to true. - const message = [ - 'You must specify a value for', - {command: 'include_config_on_deploy'}, - 'in your TOML file. Including configuration will be required very soon.', - ] - const nextSteps = [ - 'Run', - {command: 'shopify app deploy'}, - 'interactively, without', - {command: '--allow-updates'}, - 'or', - {command: '--allow-deletes'}, - '.', - ] - throw new AbortError(message, nextSteps) - } - - if (force || includeConfigOnDeploy === true) return includeConfigOnDeploy - - return promptAndSaveIncludeConfigOnDeploy({ - appDirectory: app.directory, - localApp: app, - }) -} - async function removeIncludeConfigOnDeployField(localApp: AppInterface) { const includeConfigOnDeploy = localApp.configuration.build?.include_config_on_deploy if (includeConfigOnDeploy === undefined) return @@ -276,28 +191,6 @@ function renderWarningAboutIncludeConfigOnDeploy() { }) } -async function promptAndSaveIncludeConfigOnDeploy(options: ShouldOrPromptIncludeConfigDeployOptions): Promise { - const shouldIncludeConfigDeploy = await includeConfigOnDeployPrompt(options.localApp.configPath) - options.localApp.configuration.build = { - ...options.localApp.configuration.build, - include_config_on_deploy: shouldIncludeConfigDeploy, - } - const configFile = await TomlFile.read(options.localApp.configPath) - await configFile.patch({build: {include_config_on_deploy: shouldIncludeConfigDeploy}}) - await metadata.addPublicMetadata(() => ({cmd_deploy_confirm_include_config_used: shouldIncludeConfigDeploy})) - return shouldIncludeConfigDeploy -} - -function includeConfigOnDeployPrompt(configPath: string): Promise { - return renderConfirmationPrompt({ - message: `Include \`${basename( - configPath, - )}\` configuration on \`deploy\`? Soon, this will no longer be optional and configuration will be included on every deploy.`, - confirmationMessage: 'Yes, always (Recommended)', - cancellationMessage: 'No, not now', - }) -} - export async function fetchOrCreateOrganizationApp( options: CreateAppOptions & {organizationId?: string}, ): Promise { @@ -373,7 +266,6 @@ interface CurrentlyUsedConfigInfoOptions { updateURLs?: string configFile?: string appDotEnv?: string - includeConfigOnDeploy?: boolean messages?: Token[][] } @@ -384,7 +276,6 @@ export function renderCurrentlyUsedConfigInfo({ updateURLs, configFile, appDotEnv, - includeConfigOnDeploy, messages, }: CurrentlyUsedConfigInfoOptions): void { const devStores = [] @@ -394,7 +285,7 @@ export function renderCurrentlyUsedConfigInfo({ renderInfo({ headline: configFile ? `Using ${fileName} for default values:` : 'Using these settings:', - body: formatConfigInfoBody({appName, org, devStores, updateURLs, includeConfigOnDeploy, messages}), + body: formatConfigInfoBody({appName, org, devStores, updateURLs, messages}), }) } @@ -410,43 +301,3 @@ export async function logMetadataForLoadedContext( api_key: app.apiKey, })) } - -export async function enableDeveloperPreview({ - apiKey, - developerPlatformClient, -}: { - apiKey: string - developerPlatformClient: DeveloperPlatformClient -}) { - return developerPreviewUpdate({apiKey, developerPlatformClient, enabled: true}) -} - -export async function disableDeveloperPreview({ - apiKey, - developerPlatformClient, -}: { - apiKey: string - developerPlatformClient: DeveloperPlatformClient -}) { - await developerPreviewUpdate({apiKey, developerPlatformClient, enabled: false}) -} - -export async function developerPreviewUpdate({ - apiKey, - developerPlatformClient, - enabled, -}: { - apiKey: string - developerPlatformClient: DeveloperPlatformClient - enabled: boolean -}) { - const input: DevelopmentStorePreviewUpdateInput = { - input: { - apiKey, - enabled, - }, - } - const result: DevelopmentStorePreviewUpdateSchema = await developerPlatformClient.updateDeveloperPreview(input) - const userErrors = result.developmentStorePreviewUpdate.userErrors - return !userErrors || userErrors.length === 0 -} diff --git a/packages/app/src/cli/services/context/breakdown-extensions.test.ts b/packages/app/src/cli/services/context/breakdown-extensions.test.ts index 7ac6882d58c..3e67d706db5 100644 --- a/packages/app/src/cli/services/context/breakdown-extensions.test.ts +++ b/packages/app/src/cli/services/context/breakdown-extensions.test.ts @@ -533,211 +533,6 @@ describe('extensionsIdentifiersDeployBreakdown', () => { remoteExtensionsRegistrations: remoteExtensionRegistrations.app, }) }) - test('and there is an active version with matching cli app modules then cli extension should be updated as "unchanged", and no dashboard extension should be migrated', async () => { - // Given - const extensionsToConfirm = { - validMatches: {EXTENSION_A: 'UUID_A'}, - dashboardOnlyExtensions: [REGISTRATION_DASHBOARD_A], - extensionsToCreate: [EXTENSION_A_2], - didMigrateDashboardExtensions: false, - } - vi.mocked(ensureExtensionsIds).mockResolvedValue(extensionsToConfirm) - const remoteExtensionRegistrations = { - app: { - extensionRegistrations: [REGISTRATION_A], - configurationRegistrations: [], - dashboardManagedExtensionRegistrations: [REGISTRATION_DASHBOARD_A], - }, - } - const activeAppVersion = { - appModuleVersions: [MODULE_CONFIG_A, MODULE_DASHBOARD_A, MODULE_CLI_A], - } - let fetchActiveAppVersionCalled = false - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - appExtensionRegistrations: (_app: MinimalAppIdentifiers) => Promise.resolve(remoteExtensionRegistrations), - activeAppVersion: (_app: MinimalAppIdentifiers) => { - fetchActiveAppVersionCalled = true - return Promise.resolve(activeAppVersion) - }, - }) - - // When - const result = await extensionsIdentifiersDeployBreakdown( - await options({uiExtensions, developerPlatformClient, activeAppVersion}), - ) - - // Then - expect(fetchActiveAppVersionCalled).toBe(false) - expect(result).toEqual({ - extensionIdentifiersBreakdown: { - onlyRemote: [], - toCreate: [buildExtensionBreakdownInfo('extension-a-2', 'test-ui-extension-uid')], - toUpdate: [], - unchanged: [ - buildExtensionBreakdownInfo('EXTENSION_A', undefined), - buildDashboardBreakdownInfo('Dashboard A'), - ], - }, - extensionsToConfirm, - remoteExtensionsRegistrations: remoteExtensionRegistrations.app, - }) - }) - - test('and there is an active version with a module matching a local spec external identifier then cli extension should be unchanged', async () => { - // Given - const extensionsToConfirm = { - validMatches: {EXTENSION_A: 'UUID_A'}, - dashboardOnlyExtensions: [], - extensionsToCreate: [], - didMigrateDashboardExtensions: false, - } - vi.mocked(ensureExtensionsIds).mockResolvedValue(extensionsToConfirm) - const remoteExtensionRegistrations = { - app: { - extensionRegistrations: [REGISTRATION_A], - configurationRegistrations: [], - dashboardManagedExtensionRegistrations: [], - }, - } - const activeAppVersion = { - appModuleVersions: [MODULE_CLI_A_EXTERNAL_IDENTIFIER], - } - - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - appExtensionRegistrations: (_app: MinimalAppIdentifiers) => Promise.resolve(remoteExtensionRegistrations), - }) - - // When - const result = await extensionsIdentifiersDeployBreakdown( - await options({uiExtensions: [EXTENSION_A], developerPlatformClient, activeAppVersion}), - ) - - // Then - expect(result).toEqual({ - extensionIdentifiersBreakdown: { - onlyRemote: [], - toCreate: [], - toUpdate: [], - unchanged: [buildExtensionBreakdownInfo('EXTENSION_A', undefined)], - }, - extensionsToConfirm, - remoteExtensionsRegistrations: remoteExtensionRegistrations.app, - }) - }) - - test('and there is an active version with matching dashboard migrated cli app modules then migrated extension should be returned in the to create', async () => { - // Given - const remoteExtensionRegistrations = { - app: { - extensionRegistrations: [REGISTRATION_A, REGISTRATION_DASH_MIGRATED_A], - configurationRegistrations: [], - dashboardManagedExtensionRegistrations: [REGISTRATION_DASHBOARD_A, REGISTRATION_DASH_MIGRATED_A], - }, - } - const extensionsToConfirm = { - validMatches: {EXTENSION_A: 'UUID_A', DASH_MIGRATED_EXTENSION_A: 'UUID_DM_A'}, - dashboardOnlyExtensions: [REGISTRATION_DASHBOARD_A, REGISTRATION_DASH_MIGRATED_A], - extensionsToCreate: [EXTENSION_A_2], - didMigrateDashboardExtensions: true, - } - vi.mocked(ensureExtensionsIds).mockResolvedValue(extensionsToConfirm) - const activeAppVersion = { - appModuleVersions: [MODULE_CONFIG_A, MODULE_DASHBOARD_A, MODULE_CLI_A, MODULE_DASHBOARD_MIGRATED_CLI_A], - } - let fetchActiveAppVersionCalled = false - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - appExtensionRegistrations: (_app: MinimalAppIdentifiers) => Promise.resolve(remoteExtensionRegistrations), - activeAppVersion: (_app: MinimalAppIdentifiers) => { - fetchActiveAppVersionCalled = true - return Promise.resolve(activeAppVersion) - }, - }) - - // When - const result = await extensionsIdentifiersDeployBreakdown( - await options({uiExtensions, developerPlatformClient, activeAppVersion}), - ) - - // Then - expect(fetchActiveAppVersionCalled).toBe(true) - expect(result).toEqual({ - extensionIdentifiersBreakdown: { - onlyRemote: [], - toCreate: [ - buildExtensionBreakdownInfo('DASH_MIGRATED_EXTENSION_A', 'UUID_DM_A'), - buildExtensionBreakdownInfo('extension-a-2', 'test-ui-extension-uid'), - ], - toUpdate: [], - unchanged: [ - buildExtensionBreakdownInfo('EXTENSION_A', undefined), - buildDashboardBreakdownInfo('Dashboard A'), - ], - }, - extensionsToConfirm, - remoteExtensionsRegistrations: remoteExtensionRegistrations.app, - }) - }) - test('and there is an active version with no matching local app modules then they should be returned in the extensions list to delete', async () => { - // Given - const remoteExtensionRegistrations = { - app: { - extensionRegistrations: [REGISTRATION_A, REGISTRATION_DASH_MIGRATED_A], - configurationRegistrations: [], - dashboardManagedExtensionRegistrations: [ - REGISTRATION_DASHBOARD_A, - REGISTRATION_DASH_MIGRATED_A, - REGISTRATION_DASHBOARD_NEW, - ], - }, - } - const extensionsToConfirm = { - validMatches: {EXTENSION_A: 'UUID_A', DASH_MIGRATED_EXTENSION_A: 'UUID_DM_A'}, - dashboardOnlyExtensions: [REGISTRATION_DASHBOARD_A, REGISTRATION_DASH_MIGRATED_A, REGISTRATION_DASHBOARD_NEW], - extensionsToCreate: [EXTENSION_A_2], - didMigrateDashboardExtensions: false, - } - vi.mocked(ensureExtensionsIds).mockResolvedValue(extensionsToConfirm) - const activeVersion = { - appModuleVersions: [ - MODULE_CONFIG_A, - MODULE_DASHBOARD_A, - MODULE_CLI_A, - MODULE_DASHBOARD_MIGRATED_CLI_A, - MODULE_DELETED_DASHBOARD_B, - MODULE_DELETED_CLI_B, - ], - } - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - appExtensionRegistrations: (_app: MinimalAppIdentifiers) => Promise.resolve(remoteExtensionRegistrations), - activeAppVersion: (_app: MinimalAppIdentifiers) => Promise.resolve(activeVersion), - }) - - // When - const result = await extensionsIdentifiersDeployBreakdown(await options({uiExtensions, developerPlatformClient})) - - // Then - expect(result).toEqual({ - extensionIdentifiersBreakdown: { - onlyRemote: [ - buildExtensionBreakdownInfo('Checkout post purchase Deleted B', 'B'), - buildDashboardBreakdownInfo('Dashboard Deleted B'), - ], - toCreate: [ - buildExtensionBreakdownInfo('DASH_MIGRATED_EXTENSION_A', 'UUID_DM_A'), - buildExtensionBreakdownInfo('extension-a-2', 'test-ui-extension-uid'), - buildDashboardBreakdownInfo('Dashboard New'), - ], - toUpdate: [], - unchanged: [ - buildExtensionBreakdownInfo('EXTENSION_A', undefined), - buildDashboardBreakdownInfo('Dashboard A'), - ], - }, - extensionsToConfirm, - remoteExtensionsRegistrations: remoteExtensionRegistrations.app, - }) - }) - test('and there is an active version with modules without UID, those should be returned as toUpdate, the rest, unchanged', async () => { // Given const extensionsToConfirm = { diff --git a/packages/app/src/cli/services/context/breakdown-extensions.ts b/packages/app/src/cli/services/context/breakdown-extensions.ts index aad339444f5..dfb5ea8c9f5 100644 --- a/packages/app/src/cli/services/context/breakdown-extensions.ts +++ b/packages/app/src/cli/services/context/breakdown-extensions.ts @@ -15,7 +15,6 @@ import {ExtensionSpecification, isAppConfigSpecification} from '../../models/ext import {rewriteConfiguration} from '../app/write-app-configuration-file.js' import {AppConfigurationUsedByCli} from '../../models/extensions/specifications/types/app_config.js' import {removeTrailingSlash} from '../../models/extensions/specifications/validation/common.js' -import {throwUidMappingError} from '../../prompts/uid-mapping-error.js' import {deepCompare, deepDifference} from '@shopify/cli-kit/common/object' import {zod} from '@shopify/cli-kit/node/schema' @@ -58,14 +57,6 @@ export async function extensionsIdentifiersDeployBreakdown(options: EnsureDeploy }> { let remoteExtensionsRegistrations = await fetchRemoteExtensionsRegistrations(options) - if (options.force && !options.developerPlatformClient.supportsDashboardManagedExtensions) { - const unMigratedextensions = remoteExtensionsRegistrations.app.extensionRegistrations.filter((ext) => !ext.id) - - if (unMigratedextensions.length > 0) { - throwUidMappingError() - } - } - const extensionsToConfirm = await ensureExtensionsIds(options, remoteExtensionsRegistrations.app) if (extensionsToConfirm.didMigrateDashboardExtensions) { @@ -317,13 +308,7 @@ async function resolveRemoteExtensionIdentifiersBreakdown( const version = activeAppVersion ?? (await developerPlatformClient.activeAppVersion(remoteApp)) if (!version) return - const extensionIdentifiersBreakdown = loadExtensionsIdentifiersBreakdown( - version, - validMatches, - toCreate, - specs, - developerPlatformClient, - ) + const extensionIdentifiersBreakdown = loadExtensionsIdentifiersBreakdown(version, validMatches, toCreate, specs) const dashboardOnlyFinal = dashboardOnly.filter( (dashboardOnly) => @@ -345,7 +330,6 @@ function loadExtensionsIdentifiersBreakdown( validMatches: IdentifiersExtensions, toCreate: LocalSource[], specs: ExtensionSpecification[], - developerPlatformClient: DeveloperPlatformClient, ) { const extensionModules = activeAppVersion?.appModuleVersions.filter((ext) => { const spec = specs.find( @@ -362,11 +346,7 @@ function loadExtensionsIdentifiersBreakdown( const UidMatch = module.registrationId === identifier const pendingMigration = module.registrationId.length === 0 - if (developerPlatformClient.supportsAtomicDeployments) { - return UidMatch || (pendingMigration && UuidMatch) - } else { - return UuidMatch - } + return UidMatch || (pendingMigration && UuidMatch) } const allExistingExtensions = Object.entries(validMatches) diff --git a/packages/app/src/cli/services/context/id-manual-matching.test.ts b/packages/app/src/cli/services/context/id-manual-matching.test.ts index 830428e6914..f03fe7bdb14 100644 --- a/packages/app/src/cli/services/context/id-manual-matching.test.ts +++ b/packages/app/src/cli/services/context/id-manual-matching.test.ts @@ -1,6 +1,6 @@ /* eslint-disable @shopify/prefer-module-scope-constants */ import {manualMatchIds, ManualMatchResult} from './id-manual-matching.js' -import {ExtensionRegistration} from '../dev/create-extension.js' +import {RemoteSource} from './identifiers.js' import {testUIExtension} from '../../models/app/app.test-data.js' import {ExtensionInstance} from '../../models/extensions/extension-instance.js' import {describe, expect, vi, test, beforeAll} from 'vitest' @@ -8,7 +8,7 @@ import {renderAutocompletePrompt} from '@shopify/cli-kit/node/ui' vi.mock('@shopify/cli-kit/node/ui') -const REGISTRATION_A: ExtensionRegistration = { +const REGISTRATION_A: RemoteSource = { uuid: 'UUID_A', id: 'A', title: 'A', diff --git a/packages/app/src/cli/services/context/id-matching.test.ts b/packages/app/src/cli/services/context/id-matching.test.ts index a8313fe5765..ecc126e2f3b 100644 --- a/packages/app/src/cli/services/context/id-matching.test.ts +++ b/packages/app/src/cli/services/context/id-matching.test.ts @@ -2,12 +2,11 @@ import {automaticMatchmaking} from './id-matching.js' import {RemoteSource} from './identifiers.js' import {ExtensionInstance} from '../../models/extensions/extension-instance.js' -import {testDeveloperPlatformClient, testFunctionExtension, testUIExtension} from '../../models/app/app.test-data.js' +import {testFunctionExtension, testUIExtension} from '../../models/app/app.test-data.js' import {describe, expect, vi, test, beforeAll} from 'vitest' import {outputInfo} from '@shopify/cli-kit/node/output' vi.mock('../dev/fetch') -vi.mock('../dev/create-extension') vi.mock('@shopify/cli-kit/node/output') const REGISTRATION_A: RemoteSource = { @@ -251,552 +250,10 @@ beforeAll(async () => { }) }) -describe('automaticMatchmaking: some local, no remote ones', () => { - test('creates all local extensions', async () => { - // When - const got = await automaticMatchmaking([EXTENSION_A, EXTENSION_B], [], {}, testDeveloperPlatformClient()) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [EXTENSION_A, EXTENSION_B], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: some local of the same type, no remote ones', () => { - test('creates all local extensions', async () => { - // When - const got = await automaticMatchmaking([EXTENSION_A, EXTENSION_A_2], [], {}, testDeveloperPlatformClient()) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [EXTENSION_A, EXTENSION_A_2], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: some local of the same type, only one remote', () => { - test('creates all local extensions', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2], - [REGISTRATION_A], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A'}, - toConfirm: [], - toCreate: [EXTENSION_A_2], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: some local of the same type, a remote with same type but a remote name that doesnt match a local handle', () => { - test('prompts for manual matching', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2], - [REGISTRATION_A_3], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [EXTENSION_A, EXTENSION_A_2], remote: [REGISTRATION_A_3]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: some local of the same type, one matching remote and one not matching', () => { - test('prompts for manual matching', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2], - [REGISTRATION_A, REGISTRATION_A_3], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A'}, - toConfirm: [{local: EXTENSION_A_2, remote: REGISTRATION_A_3}], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: some local of the same type, two remotes that do not match', () => { - test('prompts for manual matching', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2], - [REGISTRATION_A_3, REGISTRATION_A_4], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [EXTENSION_A, EXTENSION_A_2], remote: [REGISTRATION_A_3, REGISTRATION_A_4]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: two pairs of local and only one pair of remote but with diff names', () => { - test('creates one pair, adds the other to manual match', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2, EXTENSION_B, EXTENSION_B_2], - [REGISTRATION_A_3, REGISTRATION_A_4], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [EXTENSION_B, EXTENSION_B_2], - toManualMatch: {local: [EXTENSION_A, EXTENSION_A_2], remote: [REGISTRATION_A_3, REGISTRATION_A_4]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: same number of local and remote with matching types', () => { - test('matches them automatically', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B], - [REGISTRATION_A, REGISTRATION_B], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A', 'extension-b': 'UUID_B'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: more local than remote, all remote match some local', () => { - test('matches some and will create the rest', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B, EXTENSION_C, EXTENSION_D], - [REGISTRATION_A, REGISTRATION_B], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A', 'extension-b': 'UUID_B'}, - toConfirm: [], - toCreate: [EXTENSION_C, EXTENSION_D], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: remote have types not present locally', () => { - test('create local ones but remind we have unmatched remote', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B], - [REGISTRATION_C, REGISTRATION_D], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [EXTENSION_A, EXTENSION_B], - toManualMatch: {local: [], remote: [REGISTRATION_C, REGISTRATION_D]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: some sources match, but other are missing', () => { - test('matches when possible and leave rest to manual matching', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B], - [REGISTRATION_A, REGISTRATION_C], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A'}, - toConfirm: [], - toCreate: [EXTENSION_B], - toManualMatch: {local: [], remote: [REGISTRATION_C]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: multiple sources of the same type locally and remotely', () => { - test('matches automatically', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2], - [REGISTRATION_A, REGISTRATION_A_2], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: { - 'extension-a': 'UUID_A', - 'extension-a-2': 'UUID_A_2', - }, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: multiple sources of the same type locally and remotely, others can be matched', () => { - test('matches automatically and creates new one', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2, EXTENSION_B], - [REGISTRATION_A, REGISTRATION_A_2], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: { - 'extension-a': 'UUID_A', - 'extension-a-2': 'UUID_A_2', - }, - toConfirm: [], - toCreate: [EXTENSION_B], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: more remote of the same type than local', () => { - test('matches one and leaves to manual matching', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A], - [REGISTRATION_A, REGISTRATION_A_2], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: [REGISTRATION_A_2]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: more remote of the same type than local, but none matching', () => { - test('leaves to manual matching', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A], - [REGISTRATION_A_2, REGISTRATION_A_3], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [EXTENSION_A], - toManualMatch: {local: [], remote: [REGISTRATION_A_2, REGISTRATION_A_3]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: more remote of different types than local', () => { - test('matches one and leaves to manual matching', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A], - [REGISTRATION_A, REGISTRATION_B], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: [REGISTRATION_B]}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: same name but different remote type (but still matches)', () => { - test('matches automatically', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_D], - [REGISTRATION_D_WITH_EXTERNAL_ID], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-d': 'UUID_D'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: some sources have uuid, others can be matched', () => { - test('matches automatically', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B], - [REGISTRATION_A, REGISTRATION_B], - { - EXTENSION_A: 'UUID_A', - }, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A', 'extension-b': 'UUID_B'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe("automaticMatchmaking: some sources have uuid, but doesn't match a remote one", () => { - test('matches to the correct UUID', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B], - [REGISTRATION_A, REGISTRATION_B], - { - EXTENSION_A: 'UUID_WRONG', - }, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A', 'extension-b': 'UUID_B'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: duplicated sources types but some of them already matched', () => { - test('matches the other extensions', async () => { - // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2, EXTENSION_B], - [REGISTRATION_A, REGISTRATION_A_2, REGISTRATION_B], - { - EXTENSION_A: 'UUID_A', - }, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'extension-a': 'UUID_A', 'extension-a-2': 'UUID_A_2', 'extension-b': 'UUID_B'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: automatic matches with different names', () => { - test('matches pending confirmation', async () => { - // When - const registrationNewA = {...REGISTRATION_A, title: 'A_NEW'} - const registrationNewB = {...REGISTRATION_B, title: 'B_NEW'} - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B], - [registrationNewA, registrationNewB], - {}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {}, - toConfirm: [ - {local: EXTENSION_A, remote: registrationNewA}, - {local: EXTENSION_B, remote: registrationNewB}, - ], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: if identifiers contains something else', () => { - test('is ignored', async () => { - // When - const got = await automaticMatchmaking([], [], {FUNCTION_A: 'FUNCTION_A'}, testDeveloperPlatformClient()) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: functions', () => { - test('creates all local functions', async () => { - // When - const got = await automaticMatchmaking([FUNCTION_A], [], {}, testDeveloperPlatformClient()) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [FUNCTION_A], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: migrates functions with legacy IDs to extension IDs', () => { - test('updates function when using legacy ID and value exists on remote', async () => { - // When - const got = await automaticMatchmaking( - [FUNCTION_A], - [REGISTRATION_FUNCTION_A], - {'function-a': 'LEGACY_FUNCTION_ULID_A'}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'function-a': 'FUNCTION_UUID_A'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - - expect(got).toEqual(expected) - }) - - test('updates function when using legacy UUID and value exists on remote', async () => { - // When - const got = await automaticMatchmaking( - [FUNCTION_A], - [REGISTRATION_FUNCTION_A], - {'function-a': 'LEGACY_FUNCTION_UUID_A'}, - testDeveloperPlatformClient(), - ) - - // Then - const expected = { - identifiers: {'function-a': 'FUNCTION_UUID_A'}, - toConfirm: [], - toCreate: [], - toManualMatch: {local: [], remote: []}, - } - - expect(got).toEqual(expected) - }) - - test('creates local function when it does not exist on remote', async () => { - // When - const got = await automaticMatchmaking([FUNCTION_A], [], {}, testDeveloperPlatformClient()) - - // Then - const expected = { - identifiers: {}, - toConfirm: [], - toCreate: [FUNCTION_A], - toManualMatch: {local: [], remote: []}, - } - expect(got).toEqual(expected) - }) -}) - -describe('automaticMatchmaking: with Atomic Deployments enabled', () => { +describe('automaticMatchmaking', () => { test('creates all local extensions when there are no remote ones', async () => { // When - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_B], - [], - {}, - testDeveloperPlatformClient({supportsAtomicDeployments: true}), - ) + const got = await automaticMatchmaking([EXTENSION_A, EXTENSION_B], [], {}) // Then const expected = { @@ -811,12 +268,7 @@ describe('automaticMatchmaking: with Atomic Deployments enabled', () => { test('creates the missing extension when there is a remote one', async () => { // When const registrationA = {...REGISTRATION_A, id: ''} - const got = await automaticMatchmaking( - [EXTENSION_A, EXTENSION_A_2], - [registrationA], - {'extension-a': 'UUID_A'}, - testDeveloperPlatformClient({supportsAtomicDeployments: true}), - ) + const got = await automaticMatchmaking([EXTENSION_A, EXTENSION_A_2], [registrationA], {'extension-a': 'UUID_A'}) // Then const expected = { @@ -852,7 +304,6 @@ describe('outputAddedIDs', () => { 'extension-c': 'UUID_C', 'extension-d': 'UUID_D', }, - testDeveloperPlatformClient({supportsAtomicDeployments: true}), ) // Then: outputInfo should be called with the expected messages diff --git a/packages/app/src/cli/services/context/id-matching.ts b/packages/app/src/cli/services/context/id-matching.ts index f6546355e10..24ca7daa04d 100644 --- a/packages/app/src/cli/services/context/id-matching.ts +++ b/packages/app/src/cli/services/context/id-matching.ts @@ -1,6 +1,5 @@ import {RemoteSource, LocalSource} from './identifiers.js' import {IdentifiersExtensions} from '../../models/app/identifiers.js' -import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' import {ExtensionInstance} from '../../models/extensions/extension-instance.js' import {groupBy, partition} from '@shopify/cli-kit/common/collection' import {uniqBy, difference} from '@shopify/cli-kit/common/array' @@ -210,24 +209,9 @@ export async function automaticMatchmaking( localSources: LocalSource[], remoteSources: RemoteSource[], identifiers: IdentifiersExtensions, - developerPlatformClient: DeveloperPlatformClient, ): Promise { - const useUuidMatching = developerPlatformClient.supportsAtomicDeployments const ids = getExtensionIds(localSources, identifiers) - const localIds = Object.values(ids) - - const existsRemotely = (local: LocalSource) => - remoteSources.some((remote) => { - if (remote.type !== developerPlatformClient.toExtensionGraphQLType(local.graphQLType)) return false - return ids[local.localIdentifier] === remote.uuid - }) - - const local = localSources.filter((local) => !existsRemotely(local)) - const remote = remoteSources.filter((remote) => !localIds.includes(remote.uuid)) - - const {matched, toCreate, toConfirm, toManualMatch} = useUuidMatching - ? matchByUIDandUUID(localSources, remoteSources, ids) - : matchByNameAndType(local, remote) + const {matched, toCreate, toConfirm, toManualMatch} = matchByUIDandUUID(localSources, remoteSources, ids) return { identifiers: {...ids, ...matched}, diff --git a/packages/app/src/cli/services/context/identifiers-extensions.test.ts b/packages/app/src/cli/services/context/identifiers-extensions.test.ts index 8686cc8c5df..ec5c8b3f3de 100644 --- a/packages/app/src/cli/services/context/identifiers-extensions.test.ts +++ b/packages/app/src/cli/services/context/identifiers-extensions.test.ts @@ -19,13 +19,11 @@ import { testPaymentsAppExtension, testDeveloperPlatformClient, testSingleWebhookSubscriptionExtension, - testAppAccessConfigExtension, } from '../../models/app/app.test-data.js' import {migrateExtensionsToUIExtension} from '../dev/migrate-to-ui-extension.js' import {OrganizationApp} from '../../models/organization.js' import {ExtensionInstance} from '../../models/extensions/extension-instance.js' import {DeveloperPlatformClient, Flag} from '../../utilities/developer-platform-client.js' -import {ExtensionCreateSchema} from '../../api/graphql/extension_create.js' import appPOSSpec from '../../models/extensions/specifications/app_config_point_of_sale.js' import appWebhookSubscriptionSpec from '../../models/extensions/specifications/app_config_webhook_subscription.js' import {getModulesToMigrate} from '../dev/migrate-app-module.js' @@ -35,14 +33,6 @@ import {beforeEach, describe, expect, vi, test, beforeAll} from 'vitest' import {AbortSilentError} from '@shopify/cli-kit/node/error' import {setPathValue} from '@shopify/cli-kit/common/object' -interface Registration { - uuid: string - id: string - title: string - type: string - contextValue?: string -} - const REGISTRATION_A = { uuid: 'UUID_A', id: 'A', @@ -157,23 +147,6 @@ const options = ( return localApp } -async function createExtensionResult(registration: Registration): Promise { - return { - extensionCreate: { - extensionRegistration: { - ...registration, - draftVersion: { - config: 'config', - registrationId: 'registrationId', - lastUserInteractionAt: '2024-01-01', - validationErrors: [], - }, - }, - userErrors: [], - }, - } -} - vi.mock('@shopify/cli-kit/node/session') vi.mock('./prompts', async () => { @@ -402,9 +375,7 @@ describe('matchmaking returns ok with pending manual matches', () => { EXTENSION_A_2: 'UUID_A_2', } const remoteExtensions = [REGISTRATION_A, REGISTRATION_A_2] - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: () => createExtensionResult(REGISTRATION_B), - }) + const developerPlatformClient = testDeveloperPlatformClient() // When const got = await deployConfirmed( @@ -422,9 +393,9 @@ describe('matchmaking returns ok with pending manual matches', () => { extensions: { EXTENSION_A: 'UUID_A', EXTENSION_A_2: 'UUID_A_2', - 'extension-b': 'UUID_B', + 'extension-b': EXTENSION_B.uid, }, - extensionIds: {EXTENSION_A: 'A', EXTENSION_A_2: 'A_2', 'extension-b': 'B'}, + extensionIds: {EXTENSION_A: 'A', EXTENSION_A_2: 'A_2', 'extension-b': EXTENSION_B.uid}, extensionsNonUuidManaged: {}, }) }) @@ -476,9 +447,7 @@ describe('matchmaking returns ok with pending manual matches and manual match fa EXTENSION_A: 'UUID_A', } const remoteExtensions = [REGISTRATION_A, REGISTRATION_A_2] - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: () => createExtensionResult(REGISTRATION_A_3), - }) + const developerPlatformClient = testDeveloperPlatformClient() // When const got = await deployConfirmed( @@ -495,9 +464,9 @@ describe('matchmaking returns ok with pending manual matches and manual match fa expect(got).toEqual({ extensions: { EXTENSION_A: 'UUID_A', - 'extension-a-2': 'UUID_A_3', + 'extension-a-2': EXTENSION_A_2.uid, }, - extensionIds: {EXTENSION_A: 'A', 'extension-a-2': 'A_3'}, + extensionIds: {EXTENSION_A: 'A', 'extension-a-2': EXTENSION_A_2.uid}, extensionsNonUuidManaged: {}, }) }) @@ -535,19 +504,7 @@ describe('matchmaking returns ok with pending some pending to create', () => { const extensionsToCreate: LocalSource[] = [EXTENSION_A, EXTENSION_A_2] const validMatches = {} const remoteExtensions = [REGISTRATION_A, REGISTRATION_A_2] - let createExtensionCounter = 0 - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: async () => { - createExtensionCounter++ - if (createExtensionCounter === 1) { - return createExtensionResult(REGISTRATION_A) - } else if (createExtensionCounter === 2) { - return createExtensionResult(REGISTRATION_A_2) - } else { - throw new Error('createExtension should not be called 3 times') - } - }, - }) + const developerPlatformClient = testDeveloperPlatformClient() // When const got = await deployConfirmed( @@ -561,10 +518,9 @@ describe('matchmaking returns ok with pending some pending to create', () => { ) // Then - expect(developerPlatformClient.createExtension).toBeCalledTimes(2) expect(got).toEqual({ - extensions: {'extension-a': 'UUID_A', 'extension-a-2': 'UUID_A_2'}, - extensionIds: {'extension-a': 'A', 'extension-a-2': 'A_2'}, + extensions: {'extension-a': EXTENSION_A.uid, 'extension-a-2': EXTENSION_A_2.uid}, + extensionIds: {'extension-a': EXTENSION_A.uid, 'extension-a-2': EXTENSION_A_2.uid}, extensionsNonUuidManaged: {}, }) }) @@ -614,7 +570,6 @@ describe('matchmaking returns ok with some pending confirmation', () => { }) // Then - expect(developerPlatformClient.createExtension).not.toBeCalled() expect(got).toEqual({ extensions: {'extension-b': 'UUID_B'}, extensionIds: {'extension-b': 'B'}, @@ -656,9 +611,7 @@ describe('matchmaking returns ok with some pending confirmation', () => { const extensionsToCreate: LocalSource[] = [EXTENSION_B] const validMatches = {} const remoteExtensions = [REGISTRATION_B] - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: () => createExtensionResult(REGISTRATION_B), - }) + const developerPlatformClient = testDeveloperPlatformClient() // When const got = await deployConfirmed(options([EXTENSION_B], [], {developerPlatformClient}), remoteExtensions, [], { @@ -667,10 +620,9 @@ describe('matchmaking returns ok with some pending confirmation', () => { }) // Then - expect(developerPlatformClient.createExtension).toBeCalledTimes(1) expect(got).toEqual({ - extensions: {'extension-b': 'UUID_B'}, - extensionIds: {'extension-b': 'B'}, + extensions: {'extension-b': EXTENSION_B.uid}, + extensionIds: {'extension-b': EXTENSION_B.uid}, extensionsNonUuidManaged: {}, }) }) @@ -722,7 +674,6 @@ describe('matchmaking returns ok with nothing pending', () => { ) // Then - expect(developerPlatformClient.createExtension).not.toBeCalled() expect(got).toEqual({ extensions: {EXTENSION_A: 'UUID_A', EXTENSION_A_2: 'UUID_A_2'}, extensionIds: {EXTENSION_A: 'A', EXTENSION_A_2: 'A_2'}, @@ -756,7 +707,6 @@ describe('includes functions', () => { [EXTENSION_A, FUNCTION_A], [REGISTRATION_A, FUNCTION_REGISTRATION_A], {}, - ensureExtensionsIdsOptions.developerPlatformClient, ) expect(got).toEqual({ dashboardOnlyExtensions: [], @@ -784,7 +734,6 @@ describe('includes functions', () => { ) // Then - expect(developerPlatformClient.createExtension).not.toBeCalled() expect(got).toEqual({ extensions: {EXTENSION_A: 'UUID_A', FUNCTION_A: 'FUNCTION_A_UUID'}, extensionIds: {EXTENSION_A: 'A', FUNCTION_A: 'FUNCTION_A'}, @@ -815,12 +764,7 @@ describe('excludes non uuid managed extensions', () => { }) // Then - expect(automaticMatchmaking).toHaveBeenCalledWith( - [EXTENSION_A], - [REGISTRATION_A], - {}, - ensureExtensionsIdsOptions.developerPlatformClient, - ) + expect(automaticMatchmaking).toHaveBeenCalledWith([EXTENSION_A], [REGISTRATION_A], {}) }) }) @@ -925,7 +869,6 @@ describe('deployConfirmed: handle non existent uuid managed extensions', () => { }) // Then - expect(developerPlatformClient.createExtension).not.toBeCalled() expect(got).toEqual({ extensions: {}, extensionIds: {point_of_sale: 'C_A'}, @@ -948,76 +891,12 @@ describe('deployConfirmed: handle non existent uuid managed extensions', () => { }) // Then - expect(developerPlatformClient.createExtension).not.toHaveBeenCalled() expect(got).toEqual({ extensions: {}, extensionIds: {}, extensionsNonUuidManaged: {}, }) }) - test('when the include config on deploy flag is disabled but draft extensions should be used configuration extensions are created', async () => { - // Given - const extensionsToCreate: LocalSource[] = [] - const validMatches = {} - const REGISTRATION_CONFIG_A = { - uuid: 'UUID_C_A', - id: 'C_A', - title: 'C_A', - type: 'app-access', - } - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: () => createExtensionResult(REGISTRATION_CONFIG_A), - }) - - // When - - const CONFIG_A = await testAppAccessConfigExtension() - const ensureExtensionsIdsOptions = options([], [], {configExtensions: [CONFIG_A], developerPlatformClient}) - ensureExtensionsIdsOptions.includeDraftExtensions = true - const got = await deployConfirmed(ensureExtensionsIdsOptions, [], [], { - extensionsToCreate, - validMatches, - }) - - // Then - expect(developerPlatformClient.createExtension).toBeCalledTimes(1) - expect(got).toEqual({ - extensions: {}, - extensionIds: {app_access: 'C_A'}, - extensionsNonUuidManaged: {app_access: 'UUID_C_A'}, - }) - }) - test('when the include config on deploy flag is disabled but draft extensions should be used configuration extensions are created with context', async () => { - // Given - const extensionsToCreate: LocalSource[] = [PAYMENTS_A] - const validMatches = {} - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: () => createExtensionResult(PAYMENTS_REGISTRATION_A), - }) - - // When - const ensureExtensionsIdsOptions = options([], [], {configExtensions: [PAYMENTS_A], developerPlatformClient}) - ensureExtensionsIdsOptions.includeDraftExtensions = true - const got = await deployConfirmed(ensureExtensionsIdsOptions, [], [], { - extensionsToCreate, - validMatches, - }) - - // Then - expect(developerPlatformClient.createExtension).toHaveBeenCalledWith({ - apiKey: 'appId', - type: PAYMENTS_A.graphQLType, - config: '{}', - handle: PAYMENTS_A.handle, - title: PAYMENTS_A.handle, - context: 'payments.offsite.render', - }) - expect(got).toEqual({ - extensions: {'payments-extension': 'PAYMENTS_A_UUID'}, - extensionIds: {'payments-extension': 'PAYMENTS_A'}, - extensionsNonUuidManaged: {}, - }) - }) }) describe('deployConfirmed: handle existent uuid managed extensions', () => { test('when the include config on deploy flag is enabled configuration extensions are not created but the uuids are returned', async () => { @@ -1046,7 +925,6 @@ describe('deployConfirmed: handle existent uuid managed extensions', () => { }) // Then - expect(developerPlatformClient.createExtension).not.toHaveBeenCalled() expect(got).toEqual({ extensions: {}, extensionIds: {point_of_sale: 'C_A'}, @@ -1082,7 +960,6 @@ describe('deployConfirmed: extensions that should be managed in the TOML', () => }) // Then - expect(developerPlatformClient.createExtension).not.toHaveBeenCalled() expect(got).toEqual({ extensions: {}, extensionIds: {point_of_sale: 'C_A'}, @@ -1145,42 +1022,19 @@ describe('ensureNonUuidManagedExtensionsIds: for extensions managed in the TOML' includeDeployConfig: true, flags: [], }).app - const appId = 'appId' - - let createExtensionCounter = 0 - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: () => { - createExtensionCounter++ - const registration = { - uuid: `webhook-subscription-${createExtensionCounter}`, - id: createExtensionCounter.toString(), - title: `Webhook Subscription ${createExtensionCounter}`, - type: 'WEBHOOK_SUBSCRIPTION', - contextValue: '', - } - return createExtensionResult(registration) - }, - }) + const developerPlatformClient = testDeveloperPlatformClient() // When const {extensionsNonUuidManaged, extensionsIdsNonUuidManaged} = await ensureNonUuidManagedExtensionsIds( remoteSources, app, - appId, - false, developerPlatformClient, ) // Then - expect(developerPlatformClient.createExtension).toBeCalledTimes(4) - expect(Object.values(extensionsNonUuidManaged)).toEqual([ - 'webhook-subscription-1', - 'webhook-subscription-2', - 'webhook-subscription-3', - 'webhook-subscription-4', - ]) - expect(Object.values(extensionsIdsNonUuidManaged)).toEqual(['1', '2', '3', '4']) + expect(Object.values(extensionsNonUuidManaged)).toEqual(localSources.map((source) => source.uid)) + expect(Object.values(extensionsIdsNonUuidManaged)).toEqual(localSources.map((source) => source.uid)) }) test('if there are possible matches, creates the extension for those that dont match', async () => { @@ -1223,41 +1077,23 @@ describe('ensureNonUuidManagedExtensionsIds: for extensions managed in the TOML' includeDeployConfig: true, flags: [], }).app - const appId = 'appId' - - let createExtensionCounter = 0 - const developerPlatformClient = testDeveloperPlatformClient({ - createExtension: async () => { - createExtensionCounter++ - const registration = { - uuid: `webhook-subscription-${createExtensionCounter}`, - id: createExtensionCounter.toString(), - title: `Webhook Subscription ${createExtensionCounter}`, - type: 'WEBHOOK_SUBSCRIPTION', - contextValue: '', - } - return createExtensionResult(registration) - }, - }) + const developerPlatformClient = testDeveloperPlatformClient() // When const {extensionsNonUuidManaged, extensionsIdsNonUuidManaged} = await ensureNonUuidManagedExtensionsIds( remoteSources, app, - appId, - false, developerPlatformClient, ) // Then - expect(developerPlatformClient.createExtension).toBeCalledTimes(4) expect(Object.values(extensionsNonUuidManaged)).toEqual([ 'webhook-subscription-uuid', - 'webhook-subscription-1', - 'webhook-subscription-2', - 'webhook-subscription-3', - 'webhook-subscription-4', + ...localSources.slice(1).map((source) => source.uid), + ]) + expect(Object.values(extensionsIdsNonUuidManaged)).toEqual([ + 'webhook-subscription-id', + ...localSources.slice(1).map((source) => source.uid), ]) - expect(Object.values(extensionsIdsNonUuidManaged)).toEqual(['webhook-subscription-id', '1', '2', '3', '4']) }) }) diff --git a/packages/app/src/cli/services/context/identifiers-extensions.ts b/packages/app/src/cli/services/context/identifiers-extensions.ts index 8a8887f93d4..6f96b48e7ab 100644 --- a/packages/app/src/cli/services/context/identifiers-extensions.ts +++ b/packages/app/src/cli/services/context/identifiers-extensions.ts @@ -2,7 +2,6 @@ import {manualMatchIds} from './id-manual-matching.js' import {automaticMatchmaking} from './id-matching.js' import {EnsureDeploymentIdsPresenceOptions, LocalSource, RemoteSource} from './identifiers.js' import {extensionMigrationPrompt, matchConfirmationPrompt} from './prompts.js' -import {createExtension} from '../dev/create-extension.js' import {IdentifiersExtensions} from '../../models/app/identifiers.js' import {migrateExtensionsToUIExtension} from '../dev/migrate-to-ui-extension.js' import {migrateFlowExtensions} from '../dev/migrate-flow-extension.js' @@ -22,7 +21,6 @@ import {ExtensionSpecification} from '../../models/extensions/specification.js' import {ExtensionInstance} from '../../models/extensions/extension-instance.js' import {SingleWebhookSubscriptionType} from '../../models/extensions/specifications/app_config_webhook_schemas/webhooks_schema.js' import {PartnersClient} from '../../utilities/developer-platform-client/partners-client.js' -import {outputCompleted} from '@shopify/cli-kit/node/output' import {AbortSilentError} from '@shopify/cli-kit/node/error' import {groupBy} from '@shopify/cli-kit/common/collection' @@ -147,12 +145,7 @@ export async function ensureExtensionsIds( didMigrateDashboardExtensions = true } - const matchExtensions = await automaticMatchmaking( - localExtensions, - remoteExtensions, - identifiers, - options.developerPlatformClient, - ) + const matchExtensions = await automaticMatchmaking(localExtensions, remoteExtensions, identifiers) let validMatches = matchExtensions.identifiers const extensionsToCreate = matchExtensions.toCreate ?? [] @@ -202,14 +195,12 @@ export async function deployConfirmed( const {extensionsNonUuidManaged, extensionsIdsNonUuidManaged} = await ensureNonUuidManagedExtensionsIds( singleAndDynamicStrategyExtensions, options.app, - options.appId, - options.includeDraftExtensions, options.developerPlatformClient, ) const validMatchesById: {[key: string]: string} = {} if (extensionsToCreate.length > 0) { - const newIdentifiers = await createExtensions(extensionsToCreate, options.appId, options.developerPlatformClient) + const newIdentifiers = await createExtensions(extensionsToCreate) for (const [localIdentifier, registration] of Object.entries(newIdentifiers)) { validMatches[localIdentifier] = registration.uuid validMatchesById[localIdentifier] = registration.id @@ -273,13 +264,9 @@ function loadExtensionIds( export async function ensureNonUuidManagedExtensionsIds( remoteConfigurationRegistrations: RemoteSource[], app: AppInterface, - appId: string, - includeDraftExtensions = false, developerPlatformClient: DeveloperPlatformClient, ) { - let localExtensionRegistrations = includeDraftExtensions ? app.draftableExtensions : app.allExtensions - - localExtensionRegistrations = localExtensionRegistrations.filter((ext) => !ext.isUUIDStrategyExtension) + const localExtensionRegistrations = app.allExtensions.filter((ext) => !ext.isUUIDStrategyExtension) const extensionsToCreate: LocalSource[] = [] const validMatches: {[key: string]: string} = {} @@ -295,7 +282,7 @@ export async function ensureNonUuidManagedExtensionsIds( ) if (extensionsToCreate.length > 0) { - const newIdentifiers = await createExtensions(extensionsToCreate, appId, developerPlatformClient, false) + const newIdentifiers = await createExtensions(extensionsToCreate) for (const [localIdentifier, registration] of Object.entries(newIdentifiers)) { validMatches[localIdentifier] = registration.uuid validMatchesById[localIdentifier] = registration.id @@ -305,35 +292,14 @@ export async function ensureNonUuidManagedExtensionsIds( return {extensionsNonUuidManaged: validMatches, extensionsIdsNonUuidManaged: validMatchesById} } -async function createExtensions( - extensions: LocalSource[], - appId: string, - developerPlatformClient: DeveloperPlatformClient, - output = true, -) { +async function createExtensions(extensions: LocalSource[]) { const result: {[localIdentifier: string]: RemoteSource} = {} for (const extension of extensions) { - if (developerPlatformClient.supportsAtomicDeployments) { - // Just pretend to create the extension, as it's not necessary to do anything - // in this case. - result[extension.localIdentifier] = { - id: extension.uid, - uuid: extension.uid, - type: extension.type, - title: extension.handle, - } - } else { - // Create one at a time to avoid API rate limiting issues. - // eslint-disable-next-line no-await-in-loop - const registration = await createExtension( - appId, - extension.graphQLType, - extension.handle, - developerPlatformClient, - extension.contextValue, - ) - if (output) outputCompleted(`Created extension ${extension.handle}.`) - result[extension.localIdentifier] = registration + result[extension.localIdentifier] = { + id: extension.uid, + uuid: extension.uid, + type: extension.type, + title: extension.handle, } } return result diff --git a/packages/app/src/cli/services/context/identifiers.test.ts b/packages/app/src/cli/services/context/identifiers.test.ts index b24fb50ccdf..ae5dab7e9e9 100644 --- a/packages/app/src/cli/services/context/identifiers.test.ts +++ b/packages/app/src/cli/services/context/identifiers.test.ts @@ -33,7 +33,6 @@ describe('ensureDeploymentIdsPresence', () => { appName: 'appName', remoteApp: testOrganizationApp(), envIdentifiers: {}, - force: false, release: true, } await expect(ensureDeploymentIdsPresence(params)).rejects.toThrow(AbortSilentError) @@ -59,7 +58,6 @@ describe('ensureDeploymentIdsPresence', () => { appName: 'appName', remoteApp, envIdentifiers: {}, - force: false, release: true, } @@ -74,7 +72,7 @@ describe('ensureDeploymentIdsPresence', () => { }) }) - test('when force is true, appInstallCount is not called even with remote-only extensions', async () => { + test('when release is false, appInstallCount is not called even with remote-only extensions', async () => { // Given const breakdown = buildExtensionsBreakdown() breakdown.extensionIdentifiersBreakdown.onlyRemote = [buildExtensionBreakdownInfo('removed', 'uuid-1')] @@ -98,8 +96,7 @@ describe('ensureDeploymentIdsPresence', () => { appName: 'appName', remoteApp: testOrganizationApp(), envIdentifiers: {}, - force: true, - release: true, + release: false, } // When @@ -133,7 +130,6 @@ describe('ensureDeploymentIdsPresence', () => { appName: 'appName', remoteApp: testOrganizationApp(), envIdentifiers: {}, - force: false, allowUpdates: true, allowDeletes: true, release: true, @@ -170,7 +166,6 @@ describe('ensureDeploymentIdsPresence', () => { appName: 'appName', remoteApp: testOrganizationApp(), envIdentifiers: {}, - force: false, release: true, } @@ -206,7 +201,6 @@ describe('ensureDeploymentIdsPresence', () => { appName: 'appName', remoteApp: testOrganizationApp(), envIdentifiers: {}, - force: false, release: true, } const result = await ensureDeploymentIdsPresence(params) diff --git a/packages/app/src/cli/services/context/identifiers.ts b/packages/app/src/cli/services/context/identifiers.ts index 4584c66ed0b..1f2b7eeefcf 100644 --- a/packages/app/src/cli/services/context/identifiers.ts +++ b/packages/app/src/cli/services/context/identifiers.ts @@ -15,14 +15,12 @@ export interface EnsureDeploymentIdsPresenceOptions { appId: string appName: string envIdentifiers: Partial - force: boolean /** If true, allow adding and updating extensions and configuration without user confirmation */ allowUpdates?: boolean /** If true, allow removing extensions and configuration without user confirmation */ allowDeletes?: boolean release: boolean remoteApp: PartnersAppForIdentifierMatching - includeDraftExtensions?: boolean activeAppVersion?: AppVersion } @@ -58,10 +56,8 @@ export async function ensureDeploymentIdsPresence(options: EnsureDeploymentIdsPr activeAppVersion: options.activeAppVersion, }) - const shouldFetchInstallCount = - extensionIdentifiersBreakdown.onlyRemote.length > 0 && - !options.force && - !(options.allowUpdates && options.allowDeletes) + const shouldWarn = options.release && !options.allowDeletes + const shouldFetchInstallCount = extensionIdentifiersBreakdown.onlyRemote.length > 0 && shouldWarn let installCount: number | undefined if (shouldFetchInstallCount) { @@ -82,7 +78,6 @@ export async function ensureDeploymentIdsPresence(options: EnsureDeploymentIdsPr configExtensionIdentifiersBreakdown, appTitle: options.remoteApp?.title, release: options.release, - force: options.force, allowUpdates: options.allowUpdates, allowDeletes: options.allowDeletes, installCount, diff --git a/packages/app/src/cli/services/deploy.test.ts b/packages/app/src/cli/services/deploy.test.ts index 4807b4ebdd2..0af16d422c3 100644 --- a/packages/app/src/cli/services/deploy.test.ts +++ b/packages/app/src/cli/services/deploy.test.ts @@ -690,7 +690,6 @@ interface TestDeployBundleInput { app: AppLinkedInterface remoteApp: OrganizationApp options?: { - force?: boolean noRelease?: boolean message?: string version?: string @@ -745,7 +744,6 @@ async function testDeployBundle({ remoteApp, organization: testOrganization(), reset: false, - force: Boolean(options?.force), noRelease: Boolean(options?.noRelease), message: options?.message, version: options?.version, @@ -756,33 +754,6 @@ async function testDeployBundle({ } describe('ImportExtensionsIfNeeded', () => { - test('skips extension import when force flag is true', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient() - - vi.mocked(getExtensions).mockResolvedValue([]) - - // When - const result = await importExtensionsIfNeeded({ - app, - remoteApp, - developerPlatformClient, - force: true, - }) - - // Then - expect(result).toBe(app) - expect(getExtensions).toHaveBeenCalledWith({ - developerPlatformClient, - apiKey: remoteApp.apiKey, - organizationId: remoteApp.organizationId, - extensionTypes: allExtensionTypes, - onlyDashboardManaged: true, - }) - }) - test('skips extension import when not in TTY environment', async () => { // Given const app = testAppLinked() @@ -797,7 +768,6 @@ describe('ImportExtensionsIfNeeded', () => { app, remoteApp, developerPlatformClient, - force: false, }) // Then @@ -811,7 +781,7 @@ describe('ImportExtensionsIfNeeded', () => { }) }) - test('prompts for extension import when in TTY environment and force is false', async () => { + test('prompts for extension import when in TTY environment', async () => { // Given const app = testAppLinked() const remoteApp = testOrganizationApp() @@ -830,7 +800,6 @@ describe('ImportExtensionsIfNeeded', () => { app, remoteApp, developerPlatformClient, - force: false, }) // Then @@ -843,14 +812,14 @@ describe('ImportExtensionsIfNeeded', () => { }) expect(renderConfirmationPrompt).toHaveBeenCalledWith({ message: [ - 'App includes legacy extensions that will be deprecated soon:\n', + "App can't be deployed until Partner Dashboard managed extensions are added to your version or removed from your app:\n", ' - Extension 1\n - Extension 2', '\n\nRun ', {command: 'shopify app import-extensions'}, - 'to add legacy extensions now?', + ' to add legacy extensions now?', ], confirmationMessage: 'Yes, add legacy extensions and deploy', - cancellationMessage: 'No, skip for now', + cancellationMessage: `No, don't add legacy extensions`, }) expect(importAllExtensions).toHaveBeenCalledWith({ app, @@ -876,7 +845,6 @@ describe('ImportExtensionsIfNeeded', () => { app, remoteApp, developerPlatformClient, - force: false, }) // Then @@ -884,7 +852,7 @@ describe('ImportExtensionsIfNeeded', () => { expect(renderConfirmationPrompt).not.toHaveBeenCalled() }) - test('returns original app when user declines import', async () => { + test('throws silent error when user declines import', async () => { // Given const app = testAppLinked() const remoteApp = testOrganizationApp() @@ -895,52 +863,23 @@ describe('ImportExtensionsIfNeeded', () => { vi.mocked(getExtensions).mockResolvedValue(mockExtensions as any) vi.mocked(renderConfirmationPrompt).mockResolvedValue(false) - // When - const result = await importExtensionsIfNeeded({ - app, - remoteApp, - developerPlatformClient, - force: false, - }) - - // Then - expect(result).toBe(app) - expect(importAllExtensions).not.toHaveBeenCalled() - expect(reloadApp).not.toHaveBeenCalled() - }) - - test('throws error when platform does not support dashboard managed extensions and force is true', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDashboardManagedExtensions: false, - }) - const mockExtensions = [{title: 'Extension 1'}] - - vi.mocked(isTTY).mockReturnValue(true) - vi.mocked(getExtensions).mockResolvedValue(mockExtensions as any) - // When/Then await expect( importExtensionsIfNeeded({ app, remoteApp, developerPlatformClient, - force: true, }), - ).rejects.toThrow( - "App can't be deployed until Partner Dashboard managed extensions are added to your version or removed from your app:", - ) + ).rejects.toThrowError(AbortSilentError) + expect(importAllExtensions).not.toHaveBeenCalled() + expect(reloadApp).not.toHaveBeenCalled() }) - test('throws error when platform does not support dashboard managed extensions and not in TTY', async () => { + test('throws error when not TTY without force-equivalent flags', async () => { // Given const app = testAppLinked() const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDashboardManagedExtensions: false, - }) + const developerPlatformClient = testDeveloperPlatformClient() const mockExtensions = [{title: 'Extension 1'}] vi.mocked(isTTY).mockReturnValue(false) @@ -952,60 +891,24 @@ describe('ImportExtensionsIfNeeded', () => { app, remoteApp, developerPlatformClient, - force: false, }), ).rejects.toThrow( "App can't be deployed until Partner Dashboard managed extensions are added to your version or removed from your app:", ) - }) - - test('imports extensions when platform does not support dashboard managed extensions', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDashboardManagedExtensions: false, - }) - const mockExtensions = [{title: 'Extension 1'}] - const reloadedApp = {...app, name: 'reloaded'} - - vi.mocked(isTTY).mockReturnValue(true) - vi.mocked(getExtensions).mockResolvedValue(mockExtensions as any) - vi.mocked(renderConfirmationPrompt).mockResolvedValue(true) - vi.mocked(reloadApp).mockResolvedValue(reloadedApp as any) - // When - const result = await importExtensionsIfNeeded({ - app, - remoteApp, - developerPlatformClient, - force: false, - }) - - // Then - expect(getExtensions).toHaveBeenCalledWith({ - developerPlatformClient, - apiKey: remoteApp.apiKey, - organizationId: remoteApp.organizationId, - extensionTypes: allExtensionTypes, - onlyDashboardManaged: true, - }) - expect(importAllExtensions).toHaveBeenCalledWith({ - app, - remoteApp, - developerPlatformClient, - extensions: mockExtensions, - }) - expect(result).toBe(reloadedApp) + expect(renderConfirmationPrompt).not.toHaveBeenCalled() + expect(importAllExtensions).not.toHaveBeenCalled() }) - test('throws error when platform does not support dashboard managed extensions and force is true', async () => { + test.each([ + {flag: 'allowUpdates', options: {allowUpdates: true}}, + {flag: 'allowDeletes', options: {allowDeletes: true}}, + {flag: 'noRelease', options: {noRelease: true}}, + ])('throws error without prompting when $flag is set', async ({options}) => { // Given const app = testAppLinked() const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDashboardManagedExtensions: false, - }) + const developerPlatformClient = testDeveloperPlatformClient() const mockExtensions = [{title: 'Extension 1'}] vi.mocked(isTTY).mockReturnValue(true) @@ -1017,140 +920,13 @@ describe('ImportExtensionsIfNeeded', () => { app, remoteApp, developerPlatformClient, - force: true, - }), - ).rejects.toThrow( - "App can't be deployed until Partner Dashboard managed extensions are added to your version or removed from your app:", - ) - }) - - test('throws error when platform does not support dashboard managed extensions and not TTY', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDashboardManagedExtensions: false, - }) - const mockExtensions = [{title: 'Extension 1'}] - - vi.mocked(isTTY).mockReturnValue(false) - vi.mocked(getExtensions).mockResolvedValue(mockExtensions as any) - - // When/Then - await expect( - importExtensionsIfNeeded({ - app, - remoteApp, - developerPlatformClient, - force: false, + ...options, }), ).rejects.toThrow( "App can't be deployed until Partner Dashboard managed extensions are added to your version or removed from your app:", ) - }) - - test('throws silent error when platform does not support dashboard managed extensions and user cancels', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDashboardManagedExtensions: false, - }) - const mockExtensions = [{title: 'Extension 1'}] - - vi.mocked(isTTY).mockReturnValue(true) - vi.mocked(getExtensions).mockResolvedValue(mockExtensions as any) - vi.mocked(renderConfirmationPrompt).mockResolvedValue(false) - - // When/Then - await expect( - importExtensionsIfNeeded({ - app, - remoteApp, - developerPlatformClient, - force: false, - }), - ).rejects.toThrowError(AbortSilentError) - }) - - test('returns app without prompting when platform supports dashboard managed extensions and force is true', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient() - const mockExtensions = [{title: 'Extension 1'}] - vi.mocked(isTTY).mockReturnValue(true) - vi.mocked(getExtensions).mockResolvedValue(mockExtensions as any) - - // When - const result = await importExtensionsIfNeeded({ - app, - remoteApp, - developerPlatformClient, - force: true, - }) - - // Then expect(renderConfirmationPrompt).not.toHaveBeenCalled() expect(importAllExtensions).not.toHaveBeenCalled() - expect(result).toBe(app) - }) - - test('returns app without prompting when platform supports dashboard managed extensions and not TTY', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient() - const mockExtensions = [{title: 'Extension 1'}] - - vi.mocked(isTTY).mockReturnValue(false) - vi.mocked(getExtensions).mockResolvedValue(mockExtensions as any) - - // When - const result = await importExtensionsIfNeeded({ - app, - remoteApp, - developerPlatformClient, - force: false, - }) - - // Then - expect(renderConfirmationPrompt).not.toHaveBeenCalled() - expect(importAllExtensions).not.toHaveBeenCalled() - expect(result).toBe(app) - }) - - test('ensureDeploymentIdsPresence throws when forcing deploy and unassigned dashboard extensions exist on unsupported platform', async () => { - // Given - const app = testAppLinked() - const remoteApp = testOrganizationApp() - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDashboardManagedExtensions: false, - appExtensionRegistrations: async () => - Promise.resolve({ - app: { - extensionRegistrations: [{id: '', title: 'Legacy extension'}], - configurationRegistrations: [], - }, - } as any), - }) - - const identifiersModule = - await vi.importActual('./context/identifiers.js') - - // When/Then - await expect( - identifiersModule.ensureDeploymentIdsPresence({ - app, - developerPlatformClient, - appId: remoteApp.apiKey, - appName: remoteApp.title, - envIdentifiers: {}, - force: true, - release: true, - remoteApp, - } as any), - ).rejects.toThrow('need to be assigned') }) }) diff --git a/packages/app/src/cli/services/deploy.ts b/packages/app/src/cli/services/deploy.ts index 2f9d31a27ba..83f9fd5734c 100644 --- a/packages/app/src/cli/services/deploy.ts +++ b/packages/app/src/cli/services/deploy.ts @@ -39,9 +39,6 @@ export interface DeployOptions { /** If true, ignore any cached appId or extensionId */ reset: boolean - /** If true, proceed with deploy without asking for confirmation (equivalent to allowUpdates && allowDeletes) */ - force: boolean - /** If true, allow adding and updating extensions and configuration without user confirmation */ allowUpdates?: boolean @@ -73,58 +70,24 @@ interface ImportExtensionsIfNeededOptions { app: AppLinkedInterface remoteApp: OrganizationApp developerPlatformClient: DeveloperPlatformClient - force: boolean -} - -async function handleSupportedDashboardExtensions( - options: ImportExtensionsIfNeededOptions & { - extensions: ExtensionRegistration[] - }, -): Promise { - const {app, remoteApp, developerPlatformClient, force, extensions} = options - - if (force || !isTTY()) { - return app - } - - const message = [ - `App includes legacy extensions that will be deprecated soon:\n`, - extensions.map((ext) => ` - ${ext.title}`).join('\n'), - '\n\nRun ', - {command: 'shopify app import-extensions'}, - 'to add legacy extensions now?', - ] - const shouldImportExtensions = await renderConfirmationPrompt({ - message, - confirmationMessage: 'Yes, add legacy extensions and deploy', - cancellationMessage: 'No, skip for now', - }) - - if (shouldImportExtensions) { - await importAllExtensions({ - app, - remoteApp, - developerPlatformClient, - extensions, - }) - return reloadApp(app) - } - - return app + noRelease?: boolean + allowUpdates?: boolean + allowDeletes?: boolean } -async function handleUnsupportedDashboardExtensions( +async function handleDashboardExtensions( options: ImportExtensionsIfNeededOptions & { extensions: ExtensionRegistration[] }, ): Promise { - const {app, remoteApp, developerPlatformClient, force, extensions} = options + const {app, remoteApp, developerPlatformClient, noRelease, allowUpdates, allowDeletes, extensions} = options + const force = [noRelease, allowUpdates, allowDeletes].some(Boolean) const message = [ `App can't be deployed until Partner Dashboard managed extensions are added to your version or removed from your app:\n`, extensions.map((ext) => ` - ${ext.title}`).join('\n'), ] - const nextSteps = ['\n\nRun ', {command: 'shopify app import-extensions'}, 'to add legacy extensions.'] + const nextSteps = ['\n\nRun ', {command: 'shopify app import-extensions'}, ' to add legacy extensions.'] if (force || !isTTY()) { throw new AbortError(message, nextSteps) @@ -145,9 +108,9 @@ async function handleUnsupportedDashboardExtensions( extensions, }) return reloadApp(app) - } else { - throw new AbortSilentError() } + + throw new AbortSilentError() } export async function importExtensionsIfNeeded(options: ImportExtensionsIfNeededOptions): Promise { @@ -167,27 +130,22 @@ export async function importExtensionsIfNeeded(options: ImportExtensionsIfNeeded return app } - if (developerPlatformClient.supportsDashboardManagedExtensions) { - return handleSupportedDashboardExtensions({ - ...options, - extensions: extensionsNotImportedYet, - }) - } else { - return handleUnsupportedDashboardExtensions({ - ...options, - extensions: extensionsNotImportedYet, - }) - } + return handleDashboardExtensions({ + ...options, + extensions: extensionsNotImportedYet, + }) } export async function deploy(options: DeployOptions) { - const {remoteApp, developerPlatformClient, noRelease, force, allowUpdates, allowDeletes} = options + const {remoteApp, developerPlatformClient, noRelease, allowUpdates, allowDeletes} = options const app = await importExtensionsIfNeeded({ app: options.app, remoteApp, developerPlatformClient, - force, + noRelease, + allowUpdates, + allowDeletes, }) const {identifiers, didMigrateExtensionsToDevDash} = await ensureDeployContext({ @@ -228,7 +186,7 @@ export async function deploy(options: DeployOptions) { bundlePath: candidateBundlePath, identifiers, skipBuild: options.skipBuild, - isDevDashboardApp: developerPlatformClient.supportsAtomicDeployments, + isDevDashboardApp: true, }) let uploadTaskTitle @@ -271,7 +229,7 @@ export async function deploy(options: DeployOptions) { commitReference: options.commitReference, }) - await updateAppIdentifiers({app, identifiers, command: 'deploy', developerPlatformClient}) + await updateAppIdentifiers({app, identifiers, command: 'deploy'}) }, }, ] @@ -292,7 +250,7 @@ export async function deploy(options: DeployOptions) { * If deployment fails when uploading we want the identifiers to be persisted * for the next run. */ - await updateAppIdentifiers({app, identifiers, command: 'deploy', developerPlatformClient}) + await updateAppIdentifiers({app, identifiers, command: 'deploy'}) throw error } diff --git a/packages/app/src/cli/services/dev-clean.test.ts b/packages/app/src/cli/services/dev-clean.test.ts index 258dadf48f1..3d8fe124c37 100644 --- a/packages/app/src/cli/services/dev-clean.test.ts +++ b/packages/app/src/cli/services/dev-clean.test.ts @@ -44,19 +44,10 @@ describe('devClean', () => { // When/Then await expect(devClean(mockOptions)).rejects.toThrow(`Failed to stop the dev preview: ${errorMessage}`) }) - - test('throws AbortError when devSessions are not supported', async () => { - // Given - mockOptions.appContextResult.developerPlatformClient = customDevPlatformClient(undefined, false) - - // When/Then - await expect(devClean(mockOptions)).rejects.toThrow('Dev preview is not supported for this app.') - }) }) -function customDevPlatformClient(devSessionDeleteError?: string, supportsDevSessions = true) { +function customDevPlatformClient(devSessionDeleteError?: string) { return testDeveloperPlatformClient({ - supportsDevSessions, devSessionDelete: vi.fn().mockResolvedValue({ devSessionDelete: { userErrors: devSessionDeleteError ? [{message: devSessionDeleteError}] : [], diff --git a/packages/app/src/cli/services/dev-clean.ts b/packages/app/src/cli/services/dev-clean.ts index cbd781dd1b3..ee3118b365e 100644 --- a/packages/app/src/cli/services/dev-clean.ts +++ b/packages/app/src/cli/services/dev-clean.ts @@ -12,12 +12,6 @@ export async function devClean(options: DevCleanOptions) { const client = options.appContextResult.developerPlatformClient const remoteApp = options.appContextResult.remoteApp - if (!client.supportsDevSessions) { - throw new AbortError( - `Dev preview is not supported for this app. It's valid only for apps created on the Next-Gen Dev Platform.`, - ) - } - const result = await client.devSessionDelete({shopFqdn: options.store.shopDomain, appId: remoteApp.id}) if (result.devSessionDelete?.userErrors.length) { diff --git a/packages/app/src/cli/services/dev.test.ts b/packages/app/src/cli/services/dev.test.ts index 2806e279347..119576f884d 100644 --- a/packages/app/src/cli/services/dev.test.ts +++ b/packages/app/src/cli/services/dev.test.ts @@ -1,4 +1,4 @@ -import {dev, warnIfScopesDifferBeforeDev, blockIfMigrationIncomplete} from './dev.js' +import {dev, blockIfMigrationIncomplete} from './dev.js' import {setupDevProcesses} from './dev/processes/setup-dev-processes.js' import {renderDev} from './dev/ui.js' import {fetchAppRemoteConfiguration} from './app/select-app.js' @@ -12,7 +12,6 @@ import { } from '../models/app/app.test-data.js' import metadata from '../metadata.js' import {describe, expect, test, vi} from 'vitest' -import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' import {hashString} from '@shopify/cli-kit/node/crypto' import {reportAnalyticsEvent} from '@shopify/cli-kit/node/analytics' import {checkPortAvailability, getAvailableTCPPort} from '@shopify/cli-kit/node/tcp' @@ -56,7 +55,7 @@ describe('dev', () => { remoteApp: testOrganizationApp({apiKey: 'api-key'}), organization: testOrganization(), specifications: [], - developerPlatformClient: testDeveloperPlatformClient({supportsDevSessions: false}), + developerPlatformClient: testDeveloperPlatformClient(), store, directory: app.directory, update: false, @@ -87,97 +86,15 @@ describe('dev', () => { }) }) -describe('warnIfScopesDifferBeforeDev', () => { - const appsWithScopes = (local: string, remote: string) => { - const localApp = testAppLinked({}) - const remoteApp = testOrganizationApp() - localApp.configuration = { - ...localApp.configuration, - access_scopes: {scopes: local, use_legacy_install_flow: false}, - } - remoteApp.configuration = { - ...remoteApp.configuration, - access_scopes: {scopes: remote, use_legacy_install_flow: false}, - } as any - return { - localApp, - remoteApp, - } - } - - test('does not warn if the scopes are the same', async () => { - // Given - const developerPlatformClient = testDeveloperPlatformClient({supportsDevSessions: false}) - const apps = appsWithScopes('scopes1,scopes2', 'scopes1,scopes2') - - // When - const mockOutput = mockAndCaptureOutput() - mockOutput.clear() - await warnIfScopesDifferBeforeDev({ - ...apps, - developerPlatformClient, - commandOptions: {project: testProject()} as any, - }) - - // Then - expect(mockOutput.warn()).toBe('') - }) - - test('warns if the scopes differ', async () => { - // Given - const apps = appsWithScopes('scopes1,scopes2', 'scopes3,scopes4') - const developerPlatformClient = testDeveloperPlatformClient({supportsDevSessions: false}) - - // When - const mockOutput = mockAndCaptureOutput() - mockOutput.clear() - await warnIfScopesDifferBeforeDev({ - ...apps, - developerPlatformClient, - commandOptions: {project: testProject()} as any, - }) - - // Then - expect(mockOutput.warn()).toContain("The scopes in your TOML don't match") - }) - - test('silent if scopes differ cosmetically', async () => { - // Given - const apps = appsWithScopes('scopes1, scopes2 ', ' scopes2, scopes1') - const developerPlatformClient = testDeveloperPlatformClient({supportsDevSessions: false}) - - // When - const mockOutput = mockAndCaptureOutput() - mockOutput.clear() - await warnIfScopesDifferBeforeDev({ - ...apps, - developerPlatformClient, - commandOptions: {project: testProject()} as any, - }) - - // Then - expect(mockOutput.warn()).toBe('') - }) -}) - describe('blockIfMigrationIncomplete', () => { const baseConfig = () => ({ localApp: testAppLinked({}), remoteApp: testOrganizationApp(), - developerPlatformClient: testDeveloperPlatformClient({supportsDevSessions: true}), - }) - - test('does nothing when dev sessions not supported', async () => { - const devConfig = { - ...baseConfig(), - developerPlatformClient: testDeveloperPlatformClient({supportsDevSessions: false}), - } as any - await expect(blockIfMigrationIncomplete(devConfig)).resolves.toBeUndefined() + developerPlatformClient: testDeveloperPlatformClient(), }) test('does nothing when all remote extensions have ids (migrated)', async () => { const developerPlatformClient = testDeveloperPlatformClient({ - supportsDevSessions: true, async appExtensionRegistrations() { return { app: { @@ -202,7 +119,6 @@ describe('blockIfMigrationIncomplete', () => { test('does nothing remote extensions dont have uids but are webhook subscriptions', async () => { const developerPlatformClient = testDeveloperPlatformClient({ - supportsDevSessions: true, async appExtensionRegistrations() { return { app: { @@ -227,7 +143,6 @@ describe('blockIfMigrationIncomplete', () => { test('throws AbortError when some remote extensions are missing ids (not migrated)', async () => { const developerPlatformClient = testDeveloperPlatformClient({ - supportsDevSessions: true, async appExtensionRegistrations() { return { app: { @@ -249,29 +164,4 @@ describe('blockIfMigrationIncomplete', () => { await expect(blockIfMigrationIncomplete(devConfig)).rejects.toThrow(/need to be assigned uid identifiers/) }) - - test('does nothing for Partners with missing ids (not migrated)', async () => { - const developerPlatformClient = testDeveloperPlatformClient({ - supportsDevSessions: false, - async appExtensionRegistrations() { - return { - app: { - extensionRegistrations: [ - {id: '', uuid: 'u1', title: 'Legacy Ext 1', type: 'theme'}, - {uuid: 'u2', title: 'Legacy Ext 2', type: 'web_pixel_extension'}, - ], - configurationRegistrations: [], - dashboardManagedExtensionRegistrations: [], - }, - } as any - }, - }) - - const devConfig = { - ...baseConfig(), - developerPlatformClient, - } as any - - await expect(blockIfMigrationIncomplete(devConfig)).resolves.toBeUndefined() - }) }) diff --git a/packages/app/src/cli/services/dev.ts b/packages/app/src/cli/services/dev.ts index 0d30481a791..0dfcb3b09e1 100644 --- a/packages/app/src/cli/services/dev.ts +++ b/packages/app/src/cli/services/dev.ts @@ -6,29 +6,20 @@ import { getURLs, shouldOrPromptUpdateURLs, startTunnelPlugin, - updateURLs, } from './dev/urls.js' -import { - enableDeveloperPreview, - disableDeveloperPreview, - developerPreviewUpdate, - showReusedDevValues, -} from './context.js' -import {fetchAppPreviewMode} from './dev/fetch.js' +import {showReusedDevValues} from './context.js' import {installAppDependencies} from './dependencies.js' import {DevConfig, DevProcesses, setupDevProcesses} from './dev/processes/setup-dev-processes.js' import {frontAndBackendConfig} from './dev/processes/utils.js' import {renderDev} from './dev/ui.js' -import {DeveloperPreviewController} from './dev/ui/components/Dev.js' import {DevProcessFunction} from './dev/processes/types.js' import {getCachedAppInfo, setCachedAppInfo} from './local-storage.js' -import {canEnablePreviewMode} from './extensions/common.js' import {fetchAppRemoteConfiguration} from './app/select-app.js' import {DevSessionStatusManager} from './dev/processes/dev-session/dev-session-status-manager.js' import {TunnelMode} from './dev/tunnel-mode.js' import {PortDetail, renderPortWarnings} from './dev/port-warnings.js' import {DeveloperPlatformClient} from '../utilities/developer-platform-client.js' -import {Web, getAppScopesArray, AppLinkedInterface} from '../models/app/app.js' +import {Web, AppLinkedInterface} from '../models/app/app.js' import {Project} from '../models/project/project.js' import {Organization, OrganizationApp, OrganizationStore} from '../models/organization.js' import {getAnalyticsTunnelType} from '../utilities/analytics.js' @@ -44,10 +35,8 @@ import {AbortController} from '@shopify/cli-kit/node/abort' import {checkPortAvailability, getAvailableTCPPort} from '@shopify/cli-kit/node/tcp' import {TunnelClient} from '@shopify/cli-kit/node/plugins/tunnel' import {getBackendPort} from '@shopify/cli-kit/node/environment' -import {basename} from '@shopify/cli-kit/node/path' -import {renderWarning} from '@shopify/cli-kit/node/ui' import {reportAnalyticsEvent} from '@shopify/cli-kit/node/analytics' -import {OutputProcess, formatPackageManagerCommand} from '@shopify/cli-kit/node/output' +import {OutputProcess} from '@shopify/cli-kit/node/output' import {hashString} from '@shopify/cli-kit/node/crypto' import {AbortError} from '@shopify/cli-kit/node/error' @@ -167,7 +156,6 @@ async function prepareForDev(commandOptions: DevOptions): Promise { cachedUpdateURLs, remoteApp, apiKey, - developerPlatformClient, ) return { @@ -186,63 +174,11 @@ async function prepareForDev(commandOptions: DevOptions): Promise { } async function actionsBeforeSettingUpDevProcesses(devConfig: DevConfig) { - await warnIfScopesDifferBeforeDev(devConfig) await blockIfMigrationIncomplete(devConfig) } -/** - * Show a warning if the scopes in the local app configuration do not match the scopes in the remote app configuration. - * - * This is to flag that the developer may wish to run `shopify app deploy` to push the latest scopes. - * - */ -export async function warnIfScopesDifferBeforeDev({ - localApp, - remoteApp, - developerPlatformClient, - commandOptions, -}: Pick) { - if (developerPlatformClient.supportsDevSessions) return - const localAccess = localApp.configuration.access_scopes - const remoteAccess = remoteApp.configuration?.access_scopes - - const rationaliseScopes = (scopeString: string | undefined) => { - if (!scopeString) return scopeString - return scopeString - .split(',') - .map((scope) => scope.trim()) - .sort() - .join(',') - } - const localScopes = rationaliseScopes(localAccess?.scopes) - const remoteScopes = rationaliseScopes(remoteAccess?.scopes) - - if (!localAccess?.use_legacy_install_flow && localScopes !== remoteScopes) { - const nextSteps = [ - [ - 'Run', - {command: formatPackageManagerCommand(commandOptions.project.packageManager, 'shopify app deploy')}, - 'to push your scopes to the Partner Dashboard', - ], - ] - - renderWarning({ - headline: [`The scopes in your TOML don't match the scopes in your Partner Dashboard`], - body: [ - `Scopes in ${basename(localApp.configPath)}:`, - scopesMessage(getAppScopesArray(localApp.configuration)), - '\n', - 'Scopes in Partner Dashboard:', - scopesMessage(remoteAccess?.scopes?.split(',') ?? []), - ], - nextSteps, - }) - } -} - export async function blockIfMigrationIncomplete(devConfig: DevConfig) { const {developerPlatformClient, remoteApp} = devConfig - if (!developerPlatformClient.supportsDevSessions) return const extensions = (await developerPlatformClient.appExtensionRegistrations(remoteApp)).app.extensionRegistrations if ( @@ -279,7 +215,6 @@ async function handleUpdatingOfPartnerUrls( cachedUpdateURLs: boolean | undefined, remoteApp: OrganizationApp, apiKey: string, - developerPlatformClient: DeveloperPlatformClient, ) { const {backendConfig, frontendConfig} = frontAndBackendConfig(webs) let shouldUpdateURLs = false @@ -298,19 +233,10 @@ async function handleUpdatingOfPartnerUrls( localApp, apiKey, newURLs, - developerPlatformClient, }) if (shouldUpdateURLs) { - if (developerPlatformClient.supportsDevSessions) { - // For dev sessions, store the new URLs in the local app so that the manifest can be patched with them - // The local toml is not updated. - localApp.setDevApplicationURLs(newURLs) - } else { - // When running dev app urls are pushed directly to API Client config instead of creating a new app version - // so current app version and API Client config will have diferent url values. - await updateURLs(newURLs, apiKey, developerPlatformClient, localApp) - } + localApp.setDevApplicationURLs(newURLs) } } } @@ -407,32 +333,18 @@ async function launchDevProcesses({ return outputProcess }) - const apiKey = config.remoteApp.apiKey const developerPlatformClient = config.developerPlatformClient const app = { - canEnablePreviewMode: developerPlatformClient.supportsDevSessions - ? false - : await canEnablePreviewMode({ - localApp: config.localApp, - developerPlatformClient, - apiKey, - organizationId: config.remoteApp.organizationId, - }), - developmentStorePreviewEnabled: config.remoteApp.developmentStorePreviewEnabled, - apiKey, id: config.remoteApp.id, developerPlatformClient, - extensions: config.localApp.allExtensions, } return renderDev({ processes: processesForTaskRunner, previewUrl, graphiqlUrl, - graphiqlPort: config.graphiqlPort, app, abortController, - developerPreview: developerPreviewController(apiKey, developerPlatformClient), shopFqdn: config.storeFqdn, devSessionStatusManager, appURL: config.localApp.devApplicationURLs?.applicationUrl, @@ -443,27 +355,6 @@ async function launchDevProcesses({ }) } -function developerPreviewController( - apiKey: string, - developerPlatformClient: DeveloperPlatformClient, -): DeveloperPreviewController { - if (developerPlatformClient.supportsDevSessions) { - return { - fetchMode: () => Promise.resolve(false), - enable: () => Promise.resolve(false), - disable: () => Promise.resolve(), - update: () => Promise.resolve(false), - } - } - - return { - fetchMode: async () => Boolean(await fetchAppPreviewMode(apiKey, developerPlatformClient)), - enable: async () => enableDeveloperPreview({apiKey, developerPlatformClient}), - disable: async () => disableDeveloperPreview({apiKey, developerPlatformClient}), - update: async (state: boolean) => developerPreviewUpdate({apiKey, developerPlatformClient, enabled: state}), - } -} - async function logMetadataForDev(options: { devOptions: DevOptions tunnelUrl: string @@ -486,14 +377,6 @@ async function logMetadataForDev(options: { })) } -function scopesMessage(scopes: string[]) { - return { - list: { - items: scopes.length === 0 ? ['No scopes'] : scopes, - }, - } -} - async function validateCustomPorts(webConfigs: Web[], graphiqlPort: number) { const allPorts = webConfigs.map((config) => config.configuration.port).filter((port) => port) const duplicatedPort = allPorts.find((port, index) => allPorts.indexOf(port) !== index) diff --git a/packages/app/src/cli/services/dev/create-extension.test.ts b/packages/app/src/cli/services/dev/create-extension.test.ts deleted file mode 100644 index 84f3d30b31f..00000000000 --- a/packages/app/src/cli/services/dev/create-extension.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {createExtension} from './create-extension.js' -import {extensionCreateResponse, testDeveloperPlatformClient} from '../../models/app/app.test-data.js' -import {describe, expect, test} from 'vitest' - -describe('createExtension', () => { - test('sends request to create extension and returns it', async () => { - // Given - const developerPlatformClient = testDeveloperPlatformClient() - - const variables = { - apiKey: '123', - type: 'CHECKOUT_POST_PURCHASE', - title: 'my-ext', - config: '{}', - context: null, - handle: 'my-ext', - } - - // When - const got = await createExtension('123', 'CHECKOUT_POST_PURCHASE', 'my-ext', developerPlatformClient) - - // Then - expect(got).toEqual(extensionCreateResponse.extensionCreate.extensionRegistration) - expect(developerPlatformClient.createExtension).toHaveBeenCalledWith(variables) - }) - - test('sends request to create extension with context and returns it', async () => { - // Given - const developerPlatformClient = testDeveloperPlatformClient() - - const variables = { - apiKey: '321', - type: 'PAYMENTS_EXTENSION', - title: 'my-ext', - config: '{}', - context: 'offsite.payments.render', - handle: 'my-ext', - } - - // When - const got = await createExtension( - '321', - 'PAYMENTS_EXTENSION', - 'my-ext', - developerPlatformClient, - 'offsite.payments.render', - ) - - // Then - expect(got).toEqual(extensionCreateResponse.extensionCreate.extensionRegistration) - expect(developerPlatformClient.createExtension).toHaveBeenCalledWith(variables) - }) -}) diff --git a/packages/app/src/cli/services/dev/create-extension.ts b/packages/app/src/cli/services/dev/create-extension.ts deleted file mode 100644 index fbedebd1b4f..00000000000 --- a/packages/app/src/cli/services/dev/create-extension.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {ExtensionCreateSchema, ExtensionCreateVariables} from '../../api/graphql/extension_create.js' -import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' -import {AbortError} from '@shopify/cli-kit/node/error' - -export interface ExtensionRegistration { - id: string - uuid: string - type: string - title: string - draftVersion?: { - config: string - registrationId: string - lastUserInteractionAt: string - validationErrors: { - field: string[] - message: string - }[] - } -} - -export async function createExtension( - apiKey: string, - graphQLType: string, - handle: string, - developerPlatformClient: DeveloperPlatformClient, - context?: string, -): Promise { - const variables: ExtensionCreateVariables = { - apiKey, - type: graphQLType, - title: handle, - config: JSON.stringify({}), - context: context ?? null, - handle, - } - const result: ExtensionCreateSchema = await developerPlatformClient.createExtension(variables) - - if (result.extensionCreate.userErrors?.length > 0) { - const errors = result.extensionCreate.userErrors.map((error) => error.message).join(', ') - throw new AbortError(errors) - } - - return result.extensionCreate.extensionRegistration -} diff --git a/packages/app/src/cli/services/dev/extension/server.ts b/packages/app/src/cli/services/dev/extension/server.ts index 456c8364c61..bee668bd034 100644 --- a/packages/app/src/cli/services/dev/extension/server.ts +++ b/packages/app/src/cli/services/dev/extension/server.ts @@ -1,14 +1,12 @@ import { corsMiddleware, - devConsoleAssetsMiddleware, - devConsoleIndexMiddleware, getExtensionAssetMiddleware, getExtensionPayloadMiddleware, getExtensionPointMiddleware, getExtensionsPayloadMiddleware, getLogMiddleware, noCacheMiddleware, - redirectToDevConsoleMiddleware, + redirectToExtensionsMiddleware, } from './server/middlewares.js' import {ExtensionsPayloadStore, ExtensionsPayloadStoreOptions} from './payload/store.js' import {ExtensionInstance} from '../../../models/extensions/extension-instance.js' @@ -28,15 +26,14 @@ export function setupHTTPServer(options: SetupHTTPServerOptions) { httpApp.use(getLogMiddleware(options)) httpApp.use(corsMiddleware) httpApp.use(noCacheMiddleware) - httpRouter.use('/extensions/dev-console', devConsoleIndexMiddleware) - httpRouter.use('/extensions/dev-console/assets/**:assetPath', devConsoleAssetsMiddleware) + httpRouter.use('/extensions/dev-console', redirectToExtensionsMiddleware) httpRouter.use('/extensions/:extensionId', getExtensionPayloadMiddleware(options)) httpRouter.use('/extensions/:extensionId/', getExtensionPayloadMiddleware(options)) httpRouter.use('/extensions/:extensionId/:extensionPointTarget', getExtensionPointMiddleware(options)) httpRouter.use('/extensions/:extensionId/assets/**:assetPath', getExtensionAssetMiddleware(options)) httpRouter.use('/extensions', getExtensionsPayloadMiddleware(options)) httpRouter.use('/extensions/', getExtensionsPayloadMiddleware(options)) - httpRouter.use('/', redirectToDevConsoleMiddleware) + httpRouter.use('/', redirectToExtensionsMiddleware) httpApp.use(httpRouter) diff --git a/packages/app/src/cli/services/dev/extension/server/middlewares.test.ts b/packages/app/src/cli/services/dev/extension/server/middlewares.test.ts index 206d63ed971..88b8fffb033 100644 --- a/packages/app/src/cli/services/dev/extension/server/middlewares.test.ts +++ b/packages/app/src/cli/services/dev/extension/server/middlewares.test.ts @@ -4,7 +4,7 @@ import { getExtensionPayloadMiddleware, fileServerMiddleware, noCacheMiddleware, - redirectToDevConsoleMiddleware, + redirectToExtensionsMiddleware, getExtensionPointMiddleware, } from './middlewares.js' import * as utilities from './utilities.js' @@ -100,13 +100,13 @@ describe('noCacheMiddleware()', () => { }) }) -describe('redirectToDevConsoleMiddleware()', () => { - test('redirects to /extensions/dev-console', async () => { +describe('redirectToExtensionsMiddleware()', () => { + test('redirects to /extensions', async () => { const event = getMockEvent() - await redirectToDevConsoleMiddleware(event) + await redirectToExtensionsMiddleware(event) - expect(h3.sendRedirect).toHaveBeenCalledWith(event, '/extensions/dev-console', 307) + expect(h3.sendRedirect).toHaveBeenCalledWith(event, '/extensions', 307) }) }) diff --git a/packages/app/src/cli/services/dev/extension/server/middlewares.ts b/packages/app/src/cli/services/dev/extension/server/middlewares.ts index 1f1789662a3..3c3c553553b 100644 --- a/packages/app/src/cli/services/dev/extension/server/middlewares.ts +++ b/packages/app/src/cli/services/dev/extension/server/middlewares.ts @@ -4,9 +4,9 @@ import {getUIExtensionPayload} from '../payload.js' import {getHTML} from '../templates.js' import {getWebSocketUrl} from '../../extension.js' import {resolveOutputDir} from '../../../build/steps/include-assets/generate-manifest.js' -import {fileExists, isDirectory, readFile, findPathUp} from '@shopify/cli-kit/node/fs' +import {fileExists, isDirectory, readFile} from '@shopify/cli-kit/node/fs' import {sendRedirect, defineEventHandler, getRequestHeader, getRouterParams, setResponseHeader} from 'h3' -import {joinPath, resolvePath, isSubpath, extname, moduleDirectory} from '@shopify/cli-kit/node/path' +import {joinPath, resolvePath, isSubpath, extname} from '@shopify/cli-kit/node/path' import {outputDebug} from '@shopify/cli-kit/node/output' import type {H3Event} from 'h3' @@ -25,8 +25,8 @@ export const noCacheMiddleware = defineEventHandler((event) => { setResponseHeader(event, 'Cache-Control', 'no-cache') }) -export const redirectToDevConsoleMiddleware = defineEventHandler(async (event) => { - return sendRedirect(event, '/extensions/dev-console', 307) +export const redirectToExtensionsMiddleware = defineEventHandler(async (event) => { + return sendRedirect(event, '/extensions', 307) }) export async function fileServerMiddleware(event: H3Event, options: {filePath: string}) { @@ -113,44 +113,6 @@ export function getExtensionsPayloadMiddleware({payloadStore}: GetExtensionsMidd }) } -export const devConsoleIndexMiddleware = defineEventHandler(async (event) => { - const rootDirectory = await findPathUp(joinPath('assets', 'dev-console'), { - type: 'directory', - cwd: moduleDirectory(import.meta.url), - }) - - if (!rootDirectory) { - return sendError(event, { - statusCode: 404, - statusMessage: `Could not find root directory for dev console`, - }) - } - - return fileServerMiddleware(event, { - filePath: rootDirectory, - }) -}) - -export const devConsoleAssetsMiddleware = defineEventHandler(async (event) => { - const {assetPath = ''} = getRouterParams(event) - - const rootDirectory = await findPathUp(joinPath('assets', 'dev-console', 'extensions', 'dev-console', 'assets'), { - type: 'directory', - cwd: moduleDirectory(import.meta.url), - }) - - if (!rootDirectory) { - return sendError(event, { - statusCode: 404, - statusMessage: `Could not find root directory for dev console asset`, - }) - } - - return fileServerMiddleware(event, { - filePath: joinPath(rootDirectory, assetPath), - }) -}) - export function getLogMiddleware({devOptions}: GetExtensionsMiddlewareOptions) { return defineEventHandler((event) => { outputDebug(`UI extensions server received a ${event.method} request to URL ${event.path}`, devOptions.stdout) diff --git a/packages/app/src/cli/services/dev/fetch.test.ts b/packages/app/src/cli/services/dev/fetch.test.ts index 406a04dc4b3..26e0d0870e8 100644 --- a/packages/app/src/cli/services/dev/fetch.test.ts +++ b/packages/app/src/cli/services/dev/fetch.test.ts @@ -45,9 +45,8 @@ afterEach(() => { }) describe('fetchOrganizations', async () => { - test('returns fetched organizations from Partners and App Management for 1P development', async () => { + test('returns fetched organizations from available developer platform clients', async () => { // Given - vi.stubEnv('SHOPIFY_CLI_1P_DEV', 'true') vi.mocked(blockPartnersAccess).mockReturnValue(false) const partnersClient: PartnersClient = testDeveloperPlatformClient({ organizations: () => Promise.resolve([ORG1]), diff --git a/packages/app/src/cli/services/dev/fetch.ts b/packages/app/src/cli/services/dev/fetch.ts index 7248acc98d0..e16cb8ff155 100644 --- a/packages/app/src/cli/services/dev/fetch.ts +++ b/packages/app/src/cli/services/dev/fetch.ts @@ -1,5 +1,4 @@ import {Organization, OrganizationStore} from '../../models/organization.js' -import {FindAppPreviewModeSchema} from '../../api/graphql/find_app_preview_mode.js' import {fetchCurrentAccountInformation} from '../context/partner-account-info.js' import { DeveloperPlatformClient, @@ -94,14 +93,6 @@ export async function fetchOrganizations(): Promise { return organizations } -export async function fetchAppPreviewMode( - apiKey: string, - developerPlatformClient: DeveloperPlatformClient, -): Promise { - const res: FindAppPreviewModeSchema = await developerPlatformClient.appPreviewMode({apiKey}) - return res.app?.developmentStorePreviewEnabled -} - export async function fetchOrgFromId( id: string, developerPlatformClient: DeveloperPlatformClient, diff --git a/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts b/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts index 96af8edb562..0ab4f8645d6 100644 --- a/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts +++ b/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.test.ts @@ -3,7 +3,6 @@ import {DevSessionStatusManager} from './dev-session-status-manager.js' import {DeveloperPlatformClient} from '../../../../utilities/developer-platform-client.js' import {AppLinkedInterface} from '../../../../models/app/app.js' import {AppEventWatcher} from '../../app-events/app-event-watcher.js' -import {buildAppURLForWeb} from '../../../../utilities/app/app-url.js' import { testAppAccessConfigExtension, testAppLinked, @@ -20,7 +19,6 @@ import {AbortSignal, AbortController} from '@shopify/cli-kit/node/abort' import {flushPromises} from '@shopify/cli-kit/node/promises' import * as outputContext from '@shopify/cli-kit/node/ui/components' import {readdir} from '@shopify/cli-kit/node/fs' -import {firstPartyDev} from '@shopify/cli-kit/node/context/local' import {SerialBatchProcessor} from '@shopify/cli-kit/node/serial-batch-processor' vi.mock('@shopify/cli-kit/node/fs') @@ -29,14 +27,6 @@ vi.mock('@shopify/cli-kit/node/http') vi.mock('../../../../utilities/app/app-url.js') vi.mock('node-fetch') vi.mock('../../../bundle.js') -vi.mock('@shopify/cli-kit/node/context/local', async (importOriginal) => { - const original = await importOriginal() - return { - ...original, - firstPartyDev: vi.fn().mockReturnValue(false), - } -}) - describe('setupDevSessionProcess', () => { test('returns a dev session process with correct configuration', async () => { // Given @@ -50,7 +40,6 @@ describe('setupDevSessionProcess', () => { appId: 'app123', appWatcher: {} as AppEventWatcher, appPreviewURL: 'https://test.preview.url', - appLocalProxyURL: 'https://test.local.url', devSessionStatusManager: new DevSessionStatusManager(), } @@ -72,7 +61,6 @@ describe('setupDevSessionProcess', () => { appId: options.appId, appWatcher: options.appWatcher, appPreviewURL: options.appPreviewURL, - appLocalProxyURL: options.appLocalProxyURL, devSessionStatusManager: options.devSessionStatusManager, }, }) @@ -108,7 +96,6 @@ describe('pushUpdatesForDevSession', () => { appId: 'app123', organizationId: 'org123', appPreviewURL: 'https://test.preview.url', - appLocalProxyURL: 'https://test.local.url', devSessionStatusManager, } }) @@ -197,7 +184,6 @@ describe('pushUpdatesForDevSession', () => { test('handles scope changes and displays updated message', async () => { // Given - vi.mocked(buildAppURLForWeb).mockResolvedValue('https://test.myshopify.com/admin/apps/test') const appAccess = await testAppAccessConfigExtension(false, undefined, false) const event = {extensionEvents: [{type: 'updated', extension: appAccess}], app} const contextSpy = vi.spyOn(outputContext, 'useConcurrentOutputContext') @@ -219,9 +205,8 @@ describe('pushUpdatesForDevSession', () => { contextSpy.mockRestore() }) - test('updates preview URL to appPreviewURL by default (local dev console only for 1P devs)', async () => { - // Given - dev console is NOT shown by default (only for 1P devs) - vi.mocked(firstPartyDev).mockReturnValue(false) + test('updates preview URL to appPreviewURL when previewable extensions change', async () => { + // Given const extension = await testUIExtension({type: 'ui_extension'}) const newApp = testAppLinked({allExtensions: [extension]}) @@ -236,24 +221,6 @@ describe('pushUpdatesForDevSession', () => { expect(devSessionStatusManager.status.previewURL).toBe(options.appPreviewURL) }) - test('updates preview URL to appLocalProxyURL when 1P dev has previewable extensions', async () => { - // Given - dev console is shown for 1P devs with previewable extensions - vi.mocked(firstPartyDev).mockReturnValue(true) - const extension = await testUIExtension({type: 'ui_extension'}) - const newApp = testAppLinked({allExtensions: [extension]}) - - // When - await pushUpdatesForDevSession({stderr, stdout, abortSignal: abortController.signal}, options) - await appWatcher.start({stdout, stderr, signal: abortController.signal}) - await flushPromises() - appWatcher.emit('all', {app: newApp, extensionEvents: [{type: 'updated', extension}]}) - await flushPromises() - - // Then - expect(devSessionStatusManager.status.previewURL).toBe(options.appLocalProxyURL) - vi.mocked(firstPartyDev).mockReturnValue(false) - }) - test('updates preview URL to appPreviewURL when no previewable extensions', async () => { // Given const extension = await testFlowActionExtension() diff --git a/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.ts b/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.ts index a9d708a1c24..28c6a504850 100644 --- a/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.ts +++ b/packages/app/src/cli/services/dev/processes/dev-session/dev-session-process.ts @@ -15,7 +15,6 @@ export interface DevSessionProcessOptions { appId: string appWatcher: AppEventWatcher appPreviewURL: string - appLocalProxyURL: string devSessionStatusManager: DevSessionStatusManager } diff --git a/packages/app/src/cli/services/dev/processes/dev-session/dev-session.ts b/packages/app/src/cli/services/dev/processes/dev-session/dev-session.ts index 3c2856e6048..6a6c15d68f7 100644 --- a/packages/app/src/cli/services/dev/processes/dev-session/dev-session.ts +++ b/packages/app/src/cli/services/dev/processes/dev-session/dev-session.ts @@ -16,7 +16,7 @@ import {endHRTimeInMs, startHRTime} from '@shopify/cli-kit/node/hrtime' import {ClientError} from 'graphql-request' import {JsonMapType} from '@shopify/cli-kit/node/toml' import {AbortError} from '@shopify/cli-kit/node/error' -import {firstPartyDev, isUnitTest} from '@shopify/cli-kit/node/context/local' +import {isUnitTest} from '@shopify/cli-kit/node/context/local' import {dirname, joinPath} from '@shopify/cli-kit/node/path' import {readdir} from '@shopify/cli-kit/node/fs' import {SerialBatchProcessor} from '@shopify/cli-kit/node/serial-batch-processor' @@ -260,18 +260,13 @@ export class DevSession { } /** - * Update the preview URL, it only changes if we move between a non-previewable state and a previewable state. - * (i.e. if we go from a state with no extensions to a state with ui-extensions or vice versa) - * Use local dev console only for 1P developers (SHOPIFY_CLI_1P_DEV is enabled). + * Update the preview URL when extension availability changes. * @param event - The app event */ private updatePreviewURL(event: AppEvent) { - const hasPreview = event.app.allExtensions.filter((ext) => ext.isPreviewable).length > 0 - const useDevConsole = firstPartyDev() && hasPreview - const newPreviewURL = useDevConsole ? this.options.appLocalProxyURL : this.options.appPreviewURL const hasExtensions = event.app.nonConfigExtensions.length > 0 this.statusManager.updateStatus({ - previewURL: newPreviewURL, + previewURL: this.options.appPreviewURL, appEmbedded: event.app.configuration.embedded, hasExtensions, }) diff --git a/packages/app/src/cli/services/dev/processes/draftable-extension.ts b/packages/app/src/cli/services/dev/processes/draftable-extension.ts deleted file mode 100644 index a31ed3a11af..00000000000 --- a/packages/app/src/cli/services/dev/processes/draftable-extension.ts +++ /dev/null @@ -1,112 +0,0 @@ -import {BaseProcess, DevProcessFunction} from './types.js' -import {updateExtensionDraft} from '../update-extension.js' -import {ExtensionInstance} from '../../../models/extensions/extension-instance.js' -import {AppInterface} from '../../../models/app/app.js' -import {PartnersAppForIdentifierMatching, ensureDeploymentIdsPresence} from '../../context/identifiers.js' -import {getAppIdentifiers} from '../../../models/app/identifiers.js' -import {installJavy} from '../../function/build.js' -import {DeveloperPlatformClient} from '../../../utilities/developer-platform-client.js' -import {AppEvent, AppEventWatcher, EventType} from '../app-events/app-event-watcher.js' -import {AbortError} from '@shopify/cli-kit/node/error' -import {useConcurrentOutputContext} from '@shopify/cli-kit/node/ui/components' - -interface DraftableExtensionOptions { - extensions: ExtensionInstance[] - developerPlatformClient: DeveloperPlatformClient - apiKey: string - remoteExtensionIds: {[key: string]: string} - proxyUrl: string - localApp: AppInterface - appWatcher: AppEventWatcher -} - -export interface DraftableExtensionProcess extends BaseProcess { - type: 'draftable-extension' -} - -export const pushUpdatesForDraftableExtensions: DevProcessFunction = async ( - {stderr, stdout}, - {developerPlatformClient, apiKey, remoteExtensionIds: remoteExtensions, localApp: app, appWatcher}, -) => { - // Force the download of the javy binary in advance to avoid later problems, - // as it might be done multiple times in parallel. https://github.com/Shopify/cli/issues/2877 - await installJavy(app) - - const draftableExtensions = app.draftableExtensions.map((ext) => ext.handle) - - const handleAppEvent = async (event: AppEvent) => { - const extensionEvents = event.extensionEvents - .filter((ev) => ev.type === EventType.Updated) - .filter((ev) => ev.buildResult?.status === 'ok') - .filter((ev) => draftableExtensions.includes(ev.extension.handle)) - - const promises = extensionEvents.map(async (extensionEvent) => { - const extension = extensionEvent.extension - const registrationId = remoteExtensions[extension.localIdentifier] - if (!registrationId) throw new AbortError(`Extension ${extension.localIdentifier} not found on remote app.`) - await useConcurrentOutputContext({outputPrefix: extension.outputPrefix}, async () => { - await updateExtensionDraft({ - extension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: app.configuration, - bundlePath: appWatcher.buildOutputPath, - }) - }) - }) - await Promise.all(promises) - } - - appWatcher.onEvent(handleAppEvent).onStart(handleAppEvent) -} - -export async function setupDraftableExtensionsProcess({ - localApp, - apiKey, - developerPlatformClient, - remoteApp, - ...options -}: Omit & { - remoteApp: PartnersAppForIdentifierMatching -}): Promise { - const draftableExtensions = localApp.draftableExtensions - if (draftableExtensions.length === 0) { - return - } - - const prodEnvIdentifiers = getAppIdentifiers({app: localApp}) - - const {extensionIds: remoteExtensionIds, extensions: extensionsUuids} = await ensureDeploymentIdsPresence({ - app: localApp, - remoteApp, - appId: apiKey, - appName: remoteApp.title, - force: true, - release: true, - developerPlatformClient, - envIdentifiers: prodEnvIdentifiers, - includeDraftExtensions: true, - }) - - // Update the local app with the remote extension UUIDs. - // Extensions are initialized with a random dev UUID when running the dev command - // which is sent over WS messages for live reload in dev preview of UI Extensions. - localApp.updateExtensionUUIDS(extensionsUuids) - - return { - type: 'draftable-extension', - prefix: 'extensions', - function: pushUpdatesForDraftableExtensions, - options: { - localApp, - apiKey, - developerPlatformClient, - ...options, - extensions: draftableExtensions, - remoteExtensionIds, - }, - } -} diff --git a/packages/app/src/cli/services/dev/processes/setup-dev-processes.test.ts b/packages/app/src/cli/services/dev/processes/setup-dev-processes.test.ts index 06ad0ad0f00..de0626c6c3a 100644 --- a/packages/app/src/cli/services/dev/processes/setup-dev-processes.test.ts +++ b/packages/app/src/cli/services/dev/processes/setup-dev-processes.test.ts @@ -4,21 +4,16 @@ import {sendWebhook} from './uninstall-webhook.js' import {WebProcess, launchWebProcess} from './web.js' import {PreviewableExtensionProcess, launchPreviewableExtensionProcess} from './previewable-extension.js' import {launchGraphiQLServer} from './graphiql.js' -import {pushUpdatesForDraftableExtensions} from './draftable-extension.js' import {pushUpdatesForDevSession} from './dev-session/dev-session-process.js' import {runThemeAppExtensionsServer} from './theme-app-extension.js' import {launchAppWatcher} from './app-watcher-process.js' import { - testAppAccessConfigExtension, - testAppConfigExtensions, testAppWithConfig, testDeveloperPlatformClient, - testSingleWebhookSubscriptionExtension, testTaxCalculationExtension, testThemeExtensions, testUIExtension, testFunctionExtension, - testWebhookExtensions, testOrganizationApp, testAppLinked, testOrganization, @@ -26,7 +21,6 @@ import { testProject, } from '../../../models/app/app.test-data.js' import {WebType} from '../../../models/app/app.js' -import {ensureDeploymentIdsPresence} from '../../context/identifiers.js' import {DeveloperPlatformClient} from '../../../utilities/developer-platform-client.js' import {AppEventWatcher} from '../app-events/app-event-watcher.js' import * as loader from '../../../models/app/loader.js' @@ -37,16 +31,13 @@ import {Config} from '@oclif/core' import {getEnvironmentVariables} from '@shopify/cli-kit/node/environment' import {isStorefrontPasswordProtected} from '@shopify/theme' import {fetchTheme} from '@shopify/cli-kit/node/themes/api' -import {firstPartyDev} from '@shopify/cli-kit/node/context/local' import {adminFqdn} from '@shopify/cli-kit/node/context/fqdn' -vi.mock('../../context/identifiers.js') vi.mock('@shopify/cli-kit/node/session.js') vi.mock('../fetch.js') vi.mock('@shopify/cli-kit/node/environment') vi.mock('@shopify/theme') vi.mock('@shopify/cli-kit/node/themes/api') -vi.mock('@shopify/cli-kit/node/context/local') vi.mock('@shopify/cli-kit/node/context/fqdn', async (importOriginal) => { const original = await importOriginal() return { @@ -56,14 +47,6 @@ vi.mock('@shopify/cli-kit/node/context/fqdn', async (importOriginal) => { }) beforeEach(() => { - // mocked for draft extensions - vi.mocked(ensureDeploymentIdsPresence).mockResolvedValue({ - extensionIds: {}, - app: 'app-id', - extensions: {}, - extensionsNonUuidManaged: {}, - }) - // mocked for theme app extensions vi.mocked(ensureAuthenticatedAdmin).mockResolvedValue({ storeFqdn: 'store.myshopify.io', @@ -79,8 +62,6 @@ beforeEach(() => { role: 'theme', processing: false, }) - // By default, firstPartyDev is false (local dev console only shown for 1P devs) - vi.mocked(firstPartyDev).mockReturnValue(false) vi.mocked(adminFqdn).mockResolvedValue('admin.shopify.com') }) @@ -178,7 +159,6 @@ describe('setup-dev-processes', () => { graphiqlKey, }) - // Dev console is NOT shown by default (only shown for 1P devs) expect(res.previewUrl).toBe('https://admin.shopify.com/store/store/apps/api-key?dev-console=show') expect(res.processes[0]).toMatchObject({ type: 'web', @@ -233,20 +213,8 @@ describe('setup-dev-processes', () => { appId: '1234', }, }) - expect(res.processes[3]).toMatchObject({ - type: 'draftable-extension', - prefix: 'extensions', - function: pushUpdatesForDraftableExtensions, - options: { - localApp, - apiKey: 'api-key', - developerPlatformClient, - extensions: expect.arrayContaining([draftable]), - remoteExtensionIds: {}, - proxyUrl: 'https://example.com/proxy', - }, - }) - expect(res.processes[4]).toMatchObject({ + const themeProcess = res.processes.find((process) => process.type === 'theme-app-extensions') + expect(themeProcess).toMatchObject({ type: 'theme-app-extensions', prefix: 'theme-extensions', function: runThemeAppExtensionsServer, @@ -266,7 +234,8 @@ describe('setup-dev-processes', () => { themeExtensionPort: 9293, }, }) - expect(res.processes[5]).toMatchObject({ + const sendWebhookProcess = res.processes.find((process) => process.type === 'send-webhook') + expect(sendWebhookProcess).toMatchObject({ type: 'send-webhook', prefix: 'webhooks', function: sendWebhook, @@ -380,8 +349,8 @@ describe('setup-dev-processes', () => { expect(res.graphiqlUrl).toBe(`http://localhost:${graphiqlPort}/graphiql?key=${encodeURIComponent(expectedKey)}`) }) - test('process list includes dev-session when useDevSession is true', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({supportsDevSessions: true}) + test('process list includes dev-session', async () => { + const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient() const storeFqdn = 'store.myshopify.io' const storeId = '123456789' const remoteAppUpdated = true @@ -529,7 +498,8 @@ describe('setup-dev-processes', () => { graphiqlKey, }) - expect(res.processes[6]).toMatchObject({ + const appLogsProcess = res.processes.find((process) => process.type === 'app-logs-subscribe') + expect(appLogsProcess).toMatchObject({ type: 'app-logs-subscribe', prefix: 'app-logs', function: subscribeAndStartPolling, @@ -631,109 +601,4 @@ describe('setup-dev-processes', () => { expect(logsProcess?.options).toHaveProperty('localApp') expect(logsProcess?.options).toHaveProperty('appWatcher') }) - - test('pushUpdatesForDraftableExtensions does not include config extensions except app_access', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient() - const storeFqdn = 'store.myshopify.io' - const storeId = '123456789' - const remoteAppUpdated = true - const graphiqlPort = 1234 - const commandOptions: DevConfig['commandOptions'] = { - ...appContextResult, - subscriptionProductUrl: '/products/999999', - checkoutCartUrl: '/cart/999999:1', - theme: '1', - directory: '', - update: false, - commandConfig: new Config({root: ''}), - skipDependenciesInstallation: false, - tunnel: {mode: 'auto'}, - } - const network: DevConfig['network'] = { - proxyUrl: 'https://example.com/proxy', - proxyPort: 444, - backendPort: 111, - frontendPort: 222, - currentUrls: { - applicationUrl: 'https://example.com/application', - redirectUrlWhitelist: ['https://example.com/redirect'], - }, - } - const previewable = await testUIExtension({type: 'checkout_ui_extension'}) - const draftable = await testTaxCalculationExtension() - const nonDraftableSingleUidStrategyExtension = await testAppConfigExtensions() - const draftableSingleUidStrategyExtension = await testAppAccessConfigExtension() - const webhookSubscriptionModuleExtension = await testSingleWebhookSubscriptionExtension() - const webhooksModuleExtension = await testWebhookExtensions() - const theme = await testThemeExtensions() - const localApp = testAppWithConfig({ - config: {}, - app: { - webs: [ - { - directory: 'web', - configuration: { - roles: [WebType.Backend, WebType.Frontend], - commands: {dev: 'npm exec remix dev'}, - webhooks_path: '/webhooks', - hmr_server: { - http_paths: ['/ping'], - }, - }, - }, - ], - allExtensions: [ - previewable, - draftable, - theme, - nonDraftableSingleUidStrategyExtension, - draftableSingleUidStrategyExtension, - webhookSubscriptionModuleExtension, - webhooksModuleExtension, - ], - }, - }) - vi.spyOn(loader, 'reloadApp').mockResolvedValue(localApp) - - const remoteApp: DevConfig['remoteApp'] = { - apiKey: 'api-key', - apiSecretKeys: [{secret: 'api-secret'}], - id: '1234', - title: 'App', - organizationId: '5678', - grantedScopes: [], - flags: [], - developerPlatformClient, - } - - const graphiqlKey = 'somekey' - - const res = await setupDevProcesses({ - localApp, - commandOptions, - network, - remoteApp, - remoteAppUpdated, - storeFqdn, - storeId, - developerPlatformClient, - partnerUrlsUpdated: true, - graphiqlPort, - graphiqlKey, - }) - - expect(res.processes[3]).toMatchObject({ - type: 'draftable-extension', - prefix: 'extensions', - function: pushUpdatesForDraftableExtensions, - options: { - localApp, - apiKey: 'api-key', - developerPlatformClient, - extensions: expect.arrayContaining([draftable, theme, previewable, draftableSingleUidStrategyExtension]), - remoteExtensionIds: {}, - proxyUrl: 'https://example.com/proxy', - }, - }) - }) }) diff --git a/packages/app/src/cli/services/dev/processes/setup-dev-processes.ts b/packages/app/src/cli/services/dev/processes/setup-dev-processes.ts index 9feb2b29f07..f0ec1c92b1c 100644 --- a/packages/app/src/cli/services/dev/processes/setup-dev-processes.ts +++ b/packages/app/src/cli/services/dev/processes/setup-dev-processes.ts @@ -1,7 +1,6 @@ import {BaseProcess, DevProcessFunction} from './types.js' import {PreviewThemeAppExtensionsProcess, setupPreviewThemeAppExtensionsProcess} from './theme-app-extension.js' import {PreviewableExtensionProcess, setupPreviewableExtensionsProcess} from './previewable-extension.js' -import {DraftableExtensionProcess, setupDraftableExtensionsProcess} from './draftable-extension.js' import {SendWebhookProcess, setupSendUninstallWebhookProcess} from './uninstall-webhook.js' import {GraphiQLServerProcess, setupGraphiQLServerProcess} from './graphiql.js' import {WebProcess, setupWebProcesses} from './web.js' @@ -15,7 +14,7 @@ import {AppLinkedInterface, getAppScopes, WebType} from '../../../models/app/app import {OrganizationApp} from '../../../models/organization.js' import {DevOptions} from '../../dev.js' import {LocalhostCert, getProxyingWebServer} from '../../../utilities/app/http-reverse-proxy.js' -import {buildAppURLForAdmin, buildAppURLForWeb} from '../../../utilities/app/app-url.js' +import {buildAppURLForAdmin} from '../../../utilities/app/app-url.js' import {ApplicationURLs} from '../urls.js' import {DeveloperPlatformClient} from '../../../utilities/developer-platform-client.js' import {AppEventWatcher} from '../app-events/app-event-watcher.js' @@ -23,7 +22,6 @@ import {reloadApp} from '../../../models/app/loader.js' import {resolveGraphiQLKey} from '@shopify/cli-kit/node/graphiql/server' import {getAvailableTCPPort} from '@shopify/cli-kit/node/tcp' import {isTruthy} from '@shopify/cli-kit/node/context/utilities' -import {firstPartyDev} from '@shopify/cli-kit/node/context/local' import {getEnvironmentVariables} from '@shopify/cli-kit/node/environment' import {outputInfo} from '@shopify/cli-kit/node/output' import {adminFqdn} from '@shopify/cli-kit/node/context/fqdn' @@ -42,7 +40,6 @@ type DevProcessDefinition = | WebProcess | ProxyServerProcess | PreviewableExtensionProcess - | DraftableExtensionProcess | GraphiQLServerProcess | DevSessionProcess | AppLogsSubscribeProcess @@ -99,26 +96,9 @@ export async function setupDevProcesses({ const reloadedApp = await reloadApp(localApp) const appWatcher = new AppEventWatcher(reloadedApp, network.proxyUrl) - // Decide on the appropriate preview URL for a session with these processes - // - 1P developers with previewable extensions: use local dev console - // - 1P developers without previewable extensions: use legacy OAuth redirect URL - // - 3P developers: use unified admin URL - const anyPreviewableExtensions = reloadedApp.allExtensions.some((ext) => ext.isPreviewable) - const devConsoleURL = `${network.proxyUrl}/extensions/dev-console` - const is1PDev = firstPartyDev() - - // appPreviewUrl is the direct app URL (used by GraphiQL and dev session fallback) - // previewURL is what's shown to the user (may be dev console for 1P devs) - let appPreviewUrl: string - if (is1PDev) { - appPreviewUrl = buildAppURLForWeb(storeFqdn, apiKey) - } else { - const adminDomain = await adminFqdn() - appPreviewUrl = buildAppURLForAdmin(storeFqdn, apiKey, adminDomain) - } - - const useDevConsole = is1PDev && anyPreviewableExtensions - const previewURL = useDevConsole ? devConsoleURL : appPreviewUrl + const adminDomain = await adminFqdn() + const appPreviewUrl = buildAppURLForAdmin(storeFqdn, apiKey, adminDomain) + const previewURL = appPreviewUrl const resolvedGraphiqlKey = resolveGraphiQLKey(graphiqlKey, apiSecret, storeFqdn) const graphiqlURL = shouldRenderGraphiQL @@ -171,28 +151,18 @@ export async function setupDevProcesses({ appDirectory: reloadedApp.directory, appWatcher, }), - developerPlatformClient.supportsDevSessions - ? await setupDevSessionProcess({ - app: reloadedApp, - apiKey, - developerPlatformClient, - url: network.proxyUrl, - appId: remoteApp.id, - organizationId: remoteApp.organizationId, - storeFqdn, - appWatcher, - appPreviewURL: appPreviewUrl, - appLocalProxyURL: devConsoleURL, - devSessionStatusManager, - }) - : await setupDraftableExtensionsProcess({ - localApp: reloadedApp, - remoteApp, - apiKey, - developerPlatformClient, - proxyUrl: network.proxyUrl, - appWatcher, - }), + await setupDevSessionProcess({ + app: reloadedApp, + apiKey, + developerPlatformClient, + url: network.proxyUrl, + appId: remoteApp.id, + organizationId: remoteApp.organizationId, + storeFqdn, + appWatcher, + appPreviewURL: appPreviewUrl, + devSessionStatusManager, + }), await setupPreviewThemeAppExtensionsProcess({ remoteApp, localApp: reloadedApp, diff --git a/packages/app/src/cli/services/dev/select-store.test.ts b/packages/app/src/cli/services/dev/select-store.test.ts index 9cf01784501..75f88a12268 100644 --- a/packages/app/src/cli/services/dev/select-store.test.ts +++ b/packages/app/src/cli/services/dev/select-store.test.ts @@ -13,7 +13,6 @@ import {describe, expect, vi, test} from 'vitest' vi.mock('../../prompts/dev') vi.mock('./fetch') -vi.mock('@shopify/cli-kit/node/context/local') vi.mock('@shopify/cli-kit/node/system') vi.mock('@shopify/cli-kit/node/ui') @@ -239,7 +238,7 @@ describe('selectStore', async () => { expect(res).toContain('https://dev.shopify.com/dashboard/1234/stores') }) - test('enables backend search if the DeveloperPlatformClient supports it', async () => { + test('enables backend search', async () => { // Given vi.mocked(selectStorePrompt).mockResolvedValueOnce(STORE1) @@ -247,7 +246,7 @@ describe('selectStore', async () => { const got = await selectStore( {stores: [STORE1, STORE2], hasMorePages: false}, ORG1, - testDeveloperPlatformClient({clientName: ClientName.Partners, supportsStoreSearch: true}), + testDeveloperPlatformClient({clientName: ClientName.Partners}), ) // Then diff --git a/packages/app/src/cli/services/dev/select-store.ts b/packages/app/src/cli/services/dev/select-store.ts index d02c8969ee0..000ef277971 100644 --- a/packages/app/src/cli/services/dev/select-store.ts +++ b/packages/app/src/cli/services/dev/select-store.ts @@ -11,7 +11,6 @@ import { import {ClientName, DeveloperPlatformClient, Paginateable} from '../../utilities/developer-platform-client.js' import {sleep} from '@shopify/cli-kit/node/system' import {renderInfo, renderTasks} from '@shopify/cli-kit/node/ui' -import {firstPartyDev} from '@shopify/cli-kit/node/context/local' import {AbortError, BugError, CancelExecution} from '@shopify/cli-kit/node/error' import {outputSuccess} from '@shopify/cli-kit/node/output' @@ -31,10 +30,7 @@ export async function selectStore( developerPlatformClient: DeveloperPlatformClient, ): Promise { const showDomainOnPrompt = developerPlatformClient.clientName === ClientName.AppManagement - let onSearchForStoresByName - if (developerPlatformClient.supportsStoreSearch) { - onSearchForStoresByName = async (term: string) => developerPlatformClient.devStoresForOrg(org.id, term) - } + const onSearchForStoresByName = async (term: string) => developerPlatformClient.devStoresForOrg(org.id, term) // If no stores, guide the developer through creating one // Then, with a store selected, make sure its transfer-disabled, prompting to convert if needed let store = await selectStorePrompt({ @@ -130,7 +126,7 @@ export async function convertToTransferDisabledStoreIfNeeded( developerPlatformClient: DeveloperPlatformClient, conversionMode: 'prompt-first' | 'never', ): Promise { - if (store.transferDisabled || firstPartyDev()) return true + if (store.transferDisabled) return true if (!store.transferDisabled && !store.convertableToPartnerTest) { throw new AbortError( diff --git a/packages/app/src/cli/services/dev/ui.test.tsx b/packages/app/src/cli/services/dev/ui.test.tsx index fceb2eebf76..ad6e27c29e8 100644 --- a/packages/app/src/cli/services/dev/ui.test.tsx +++ b/packages/app/src/cli/services/dev/ui.test.tsx @@ -1,5 +1,4 @@ import {renderDev} from './ui.js' -import {Dev} from './ui/components/Dev.js' import {DevSessionUI} from './ui/components/DevSessionUI.js' import {DevSessionStatusManager} from './processes/dev-session/dev-session-status-manager.js' import {testDeveloperPlatformClient} from '../../models/app/app.test-data.js' @@ -9,17 +8,8 @@ import {AbortController} from '@shopify/cli-kit/node/abort' import {terminalSupportsPrompting} from '@shopify/cli-kit/node/system' vi.mock('@shopify/cli-kit/node/system') -vi.mock('./ui/components/Dev.js') -vi.mock('../context.js') vi.mock('./ui/components/DevSessionUI.js') -const developerPreview = { - fetchMode: vi.fn(async () => true), - enable: vi.fn(async () => true), - disable: vi.fn(async () => {}), - update: vi.fn(async (_state: boolean) => true), -} - const developerPlatformClient = testDeveloperPlatformClient() const devSessionStatusManager = new DevSessionStatusManager() @@ -35,36 +25,18 @@ describe('ui', () => { prefix: 'prefix', action: vi.fn(async (_stdout, _stderr, _signal) => {}), } - - const processes = [concurrentProcess] - const previewUrl = 'https://lala.cloudflare.io/' - const graphiqlUrl = 'https://lala.cloudflare.io/graphiql' - const shopFqdn = 'mystore.shopify.io' - const graphiqlPort = 1234 - const app = { - canEnablePreviewMode: true, - developmentStorePreviewEnabled: false, - apiKey: '123', - id: '123', - developerPlatformClient, - extensions: [], - } - const abortController = new AbortController() await renderDev({ - processes, - previewUrl, - graphiqlUrl, - graphiqlPort, - app, + processes: [concurrentProcess], + previewUrl: 'https://lala.cloudflare.io/', + graphiqlUrl: 'https://lala.cloudflare.io/graphiql', + app: {id: '123', developerPlatformClient}, abortController, - developerPreview, - shopFqdn, + shopFqdn: 'mystore.shopify.io', devSessionStatusManager, }) - expect(vi.mocked(Dev)).not.toHaveBeenCalled() expect(concurrentProcess.action).toHaveBeenNthCalledWith( 1, process.stdout, @@ -81,23 +53,12 @@ describe('ui', () => { action: vi.fn(async (_stdout, _stderr, _signal) => {}), } - const abortController = new AbortController() - await renderDev({ processes: [concurrentProcess], previewUrl: 'https://lala.cloudflare.io/', graphiqlUrl: 'https://lala.cloudflare.io/graphiql', - graphiqlPort: 1234, - app: { - canEnablePreviewMode: true, - developmentStorePreviewEnabled: false, - apiKey: '123', - id: '123', - developerPlatformClient, - extensions: [], - }, - abortController, - developerPreview, + app: {id: '123', developerPlatformClient}, + abortController: new AbortController(), shopFqdn: 'mystore.shopify.io', devSessionStatusManager, }) @@ -109,165 +70,28 @@ describe('ui', () => { write.mockRestore() }) - test("enable dev preview when terminal doesn't support TTY and the app supports it", async () => { - vi.mocked(terminalSupportsPrompting).mockReturnValue(false) - const concurrentProcess = { - prefix: 'prefix', - action: vi.fn(async (_stdout, _stderr, _signal) => {}), - } - - const processes = [concurrentProcess] - const previewUrl = 'https://lala.cloudflare.io/' - const graphiqlUrl = 'https://lala.cloudflare.io/graphiql' - const shopFqdn = 'mystore.shopify.io' - const graphiqlPort = 1234 - const app = { - canEnablePreviewMode: true, - developmentStorePreviewEnabled: false, - apiKey: '123', - id: '123', - developerPlatformClient, - extensions: [], - } - - const abortController = new AbortController() - - await renderDev({ - processes, - previewUrl, - graphiqlUrl, - graphiqlPort, - app, - abortController, - developerPreview, - shopFqdn, - devSessionStatusManager, - }) - abortController.abort() - - expect(developerPreview.enable).toHaveBeenCalled() - expect(developerPreview.disable).toHaveBeenCalled() - }) - - test("don't enable dev preview when terminal doesn't support TTY and the app doesn't supports it", async () => { - vi.mocked(terminalSupportsPrompting).mockReturnValue(false) - const concurrentProcess = { - prefix: 'prefix', - action: vi.fn(async (_stdout, _stderr, _signal) => {}), - } - - const processes = [concurrentProcess] - const previewUrl = 'https://lala.cloudflare.io/' - const graphiqlUrl = 'https://lala.cloudflare.io/graphiql' - const shopFqdn = 'mystore.shopify.io' - const graphiqlPort = 1234 - const app = { - canEnablePreviewMode: false, - developmentStorePreviewEnabled: false, - apiKey: '123', - id: '123', - developerPlatformClient, - extensions: [], - } - - const abortController = new AbortController() - - await renderDev({ - processes, - previewUrl, - graphiqlUrl, - graphiqlPort, - app, - abortController, - developerPreview, - shopFqdn, - devSessionStatusManager, - }) - abortController.abort() - - expect(developerPreview.enable).not.toHaveBeenCalled() - expect(developerPreview.disable).not.toHaveBeenCalled() - }) - - test('uses ink when terminal supports TTY', async () => { + test('renders DevSessionUI when terminal supports TTY', async () => { vi.mocked(terminalSupportsPrompting).mockReturnValue(true) const concurrentProcess = { prefix: 'prefix', action: vi.fn(async (_stdout, _stderr, _signal) => {}), } - - const processes = [concurrentProcess] - const previewUrl = 'https://lala.cloudflare.io/' - const graphiqlUrl = 'https://lala.cloudflare.io/graphiql' - const shopFqdn = 'mystore.shopify.io' - const graphiqlPort = 1234 - const app = { - canEnablePreviewMode: true, - developmentStorePreviewEnabled: false, - apiKey: '123', - id: '123', - developerPlatformClient, - extensions: [], - } - const abortController = new AbortController() // eslint-disable-next-line @typescript-eslint/no-floating-promises renderDev({ - processes, - previewUrl, - graphiqlUrl, - graphiqlPort, - app, - abortController, - developerPreview, - shopFqdn, - devSessionStatusManager, - }) - - await new Promise((resolve) => setTimeout(resolve, 10)) - - expect(vi.mocked(Dev)).toHaveBeenCalled() - expect(concurrentProcess.action).not.toHaveBeenCalled() - }) - - test('renders DevSessionUI when terminal supports TTY and app supports dev sessions', async () => { - vi.mocked(terminalSupportsPrompting).mockReturnValue(true) - const concurrentProcess = { - prefix: 'prefix', - action: vi.fn(async (_stdout, _stderr, _signal) => {}), - } - - const processes = [concurrentProcess] - const previewUrl = 'https://lala.cloudflare.io/' - const graphiqlUrl = 'https://lala.cloudflare.io/graphiql' - const shopFqdn = 'mystore.shopify.io' - const graphiqlPort = 1234 - const app = { - canEnablePreviewMode: true, - developmentStorePreviewEnabled: false, - apiKey: '123', - id: '123', - developerPlatformClient: { - ...developerPlatformClient, - supportsDevSessions: true, - devSessionDelete: vi.fn(), + processes: [concurrentProcess], + previewUrl: 'https://lala.cloudflare.io/', + graphiqlUrl: 'https://lala.cloudflare.io/graphiql', + app: { + id: '123', + developerPlatformClient: { + ...developerPlatformClient, + devSessionDelete: vi.fn(), + }, }, - extensions: [], - } - - const abortController = new AbortController() - - // eslint-disable-next-line @typescript-eslint/no-floating-promises - renderDev({ - processes, - previewUrl, - graphiqlUrl, - graphiqlPort, - app, abortController, - developerPreview, - shopFqdn, + shopFqdn: 'mystore.shopify.io', devSessionStatusManager, }) @@ -275,7 +99,7 @@ describe('ui', () => { expect(vi.mocked(DevSessionUI)).toHaveBeenCalledWith( expect.objectContaining({ - processes, + processes: [concurrentProcess], abortController, devSessionStatusManager, onAbort: expect.any(Function), @@ -283,48 +107,38 @@ describe('ui', () => { // React 19 no longer passes legacy context as second argument undefined, ) - expect(vi.mocked(Dev)).not.toHaveBeenCalled() + expect(concurrentProcess.action).not.toHaveBeenCalled() }) test('calls devSessionDelete when DevSessionUI aborts', async () => { vi.mocked(terminalSupportsPrompting).mockReturnValue(true) - const processes = [ - { - prefix: 'prefix', - action: vi.fn(async (_stdout, _stderr, _signal) => {}), - }, - ] const app = { - canEnablePreviewMode: false, - developmentStorePreviewEnabled: false, - apiKey: '123', id: '123', developerPlatformClient: { ...developerPlatformClient, - supportsDevSessions: true, devSessionDelete: vi.fn(), }, - extensions: [], } const shopFqdn = 'mystore.shopify.io' - const abortController = new AbortController() // eslint-disable-next-line @typescript-eslint/no-floating-promises renderDev({ - processes, + processes: [ + { + prefix: 'prefix', + action: vi.fn(async (_stdout, _stderr, _signal) => {}), + }, + ], previewUrl: '', graphiqlUrl: '', - graphiqlPort: 1234, app, - abortController, - developerPreview, + abortController: new AbortController(), shopFqdn, devSessionStatusManager, }) await new Promise((resolve) => setTimeout(resolve, 10)) - // Get the onAbort callback that was passed to DevSessionUI const onAbort = vi.mocked(DevSessionUI).mock.calls[0]?.[0]?.onAbort await onAbort?.() diff --git a/packages/app/src/cli/services/dev/ui.tsx b/packages/app/src/cli/services/dev/ui.tsx index af9fa1e5273..9eb23042433 100644 --- a/packages/app/src/cli/services/dev/ui.tsx +++ b/packages/app/src/cli/services/dev/ui.tsx @@ -1,11 +1,23 @@ -import {Dev, DevProps} from './ui/components/Dev.js' import {DevSessionUI} from './ui/components/DevSessionUI.js' import {DevSessionStatusManager} from './processes/dev-session/dev-session-status-manager.js' +import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' +import {OutputProcess} from '@shopify/cli-kit/node/output' +import {AbortController} from '@shopify/cli-kit/node/abort' import React from 'react' import {render} from '@shopify/cli-kit/node/ui' import {terminalSupportsPrompting} from '@shopify/cli-kit/node/system' -import {isTruthy} from '@shopify/cli-kit/node/context/utilities' -import {isUnitTest} from '@shopify/cli-kit/node/context/local' + +interface DevProps { + processes: OutputProcess[] + previewUrl: string + graphiqlUrl?: string + abortController: AbortController + shopFqdn: string + app: { + id: string + developerPlatformClient: DeveloperPlatformClient + } +} export async function renderDev({ processes, @@ -13,8 +25,6 @@ export async function renderDev({ app, abortController, graphiqlUrl, - graphiqlPort, - developerPreview, shopFqdn, devSessionStatusManager, appURL, @@ -30,17 +40,7 @@ export async function renderDev({ configPath?: string localURL?: string }) { - if (!terminalSupportsPrompting()) { - await renderDevNonInteractive({ - processes, - previewUrl, - graphiqlUrl, - app, - abortController, - developerPreview, - shopFqdn, - }) - } else if (app.developerPlatformClient.supportsDevSessions) { + if (terminalSupportsPrompting()) { return render( , - { - exitOnCtrlC: false, - }, - ) } + + await renderDevNonInteractive({ + processes, + previewUrl, + graphiqlUrl, + abortController, + }) } async function renderDevNonInteractive({ processes, previewUrl, graphiqlUrl, - app: {canEnablePreviewMode}, abortController, - developerPreview, -}: Omit) { - if (canEnablePreviewMode) { - await developerPreview.enable() - abortController?.signal.addEventListener('abort', async () => { - await developerPreview.disable() - }) - } +}: Pick) { process.stdout.write(`\nPreview URL: ${previewUrl}\n`) if (graphiqlUrl) { process.stdout.write(`GraphiQL URL (Admin API): ${graphiqlUrl}\n`) @@ -105,13 +87,3 @@ async function renderDevNonInteractive({ }), ) } - -// We should make this better later, but for now, we'll hardcode and see how it's received. -function isEditionWeek() { - if (isTruthy(process.env.IS_EDITION_WEEK)) return true - if (isUnitTest()) return false - const editionStart = new Date('2024-01-31T17:00:00.000Z') - const editionWeekEnd = new Date('2024-02-07T17:00:00.000Z') - const now = new Date() - return now >= editionStart && now <= editionWeekEnd -} diff --git a/packages/app/src/cli/services/dev/ui/components/Dev.test.tsx b/packages/app/src/cli/services/dev/ui/components/Dev.test.tsx deleted file mode 100644 index 2808a12dbba..00000000000 --- a/packages/app/src/cli/services/dev/ui/components/Dev.test.tsx +++ /dev/null @@ -1,948 +0,0 @@ -import {calculatePrefixColumnSize, Dev} from './Dev.js' -import {testDeveloperPlatformClient, testUIExtension} from '../../../../models/app/app.test-data.js' -import { - getLastFrameAfterUnmount, - render, - sendInputAndWait, - sendInputAndWaitForContent, - Stdin, - waitForContent, - waitForInputsToBeReady, -} from '@shopify/cli-kit/node/testing/ui' -import {AbortController, AbortSignal} from '@shopify/cli-kit/node/abort' -import React from 'react' -import {describe, expect, test, vi} from 'vitest' -import {unstyled} from '@shopify/cli-kit/node/output' -import {openURL, sleep} from '@shopify/cli-kit/node/system' -import {Writable} from 'stream' - -vi.mock('@shopify/cli-kit/node/system', async () => { - const actual: any = await vi.importActual('@shopify/cli-kit/node/system') - return { - ...actual, - openURL: vi.fn(), - } -}) - -vi.mock('../../../context.js') -vi.mock('../../fetch.js') -vi.mock('../../processes/dev-session.js') -vi.mock('@shopify/cli-kit/node/hooks/postrun', async () => { - const actual: any = await vi.importActual('@shopify/cli-kit/node/hooks/postrun') - return { - ...actual, - waitForPostRunHookAndExit: vi.fn(), - } -}) - -const developerPlatformClient = testDeveloperPlatformClient() - -const testApp = { - canEnablePreviewMode: true, - developmentStorePreviewEnabled: false, - apiKey: '123', - id: '123', - developerPlatformClient, - extensions: [], -} - -const developerPreview = { - fetchMode: vi.fn(async () => true), - enable: vi.fn(async () => true), - disable: vi.fn(async () => {}), - update: vi.fn(async (_state: boolean) => true), -} - -describe('Dev', () => { - test('renders a stream of concurrent outputs from sub-processes, shortcuts and a preview url', async () => { - // Given - let backendPromiseResolve: () => void - let frontendPromiseResolve: () => void - - const backendPromise = new Promise(function (resolve, _reject) { - backendPromiseResolve = resolve - }) - - const frontendPromise = new Promise(function (resolve, _reject) { - frontendPromiseResolve = resolve - }) - - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - - backendPromiseResolve() - }, - } - - const frontendProcess = { - prefix: 'frontend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - await backendPromise - - stdout.write('first frontend message') - stdout.write('second frontend message') - stdout.write('third frontend message') - - frontendPromiseResolve() - }, - } - // When - - const renderInstance = render( - , - ) - - await frontendPromise - // Wait for React 19 to render the process output - await waitForContent(renderInstance, 'third frontend message') - - // Then - expect(unstyled(renderInstance.lastFrame()!.replace(/\d/g, '0'))).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - 00:00:00 │ frontend │ first frontend message - 00:00:00 │ frontend │ second frontend message - 00:00:00 │ frontend │ third frontend message - - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test("doesn't render shortcuts if the stdin is not a TTY", async () => { - // Given - let backendPromiseResolve: () => void - let frontendPromiseResolve: () => void - - const backendPromise = new Promise(function (resolve, _reject) { - backendPromiseResolve = resolve - }) - - const frontendPromise = new Promise(function (resolve, _reject) { - frontendPromiseResolve = resolve - }) - - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - - backendPromiseResolve() - }, - } - - const frontendProcess = { - prefix: 'frontend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - await backendPromise - - stdout.write('first frontend message') - stdout.write('second frontend message') - stdout.write('third frontend message') - - frontendPromiseResolve() - - // await promise that never resolves - await new Promise(() => {}) - }, - } - // When - - const renderInstance = render( - , - {stdin: new Stdin({isTTY: false})}, - ) - - await frontendPromise - // Wait for React 19 to render the process output - await waitForContent(renderInstance, 'third frontend message') - - // Then - expect(unstyled(renderInstance.lastFrame()!.replace(/\d/g, '0'))).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - 00:00:00 │ frontend │ first frontend message - 00:00:00 │ frontend │ second frontend message - 00:00:00 │ frontend │ third frontend message - - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('opens the previewUrl when p is pressed', async () => { - // When - const renderInstance = render( - , - ) - - await waitForInputsToBeReady() - await sendInputAndWait(renderInstance, 10, 'p') - // Then - expect(vi.mocked(openURL)).toHaveBeenNthCalledWith(1, 'https://shopify.com') - - renderInstance.unmount() - }) - - test('quits when q is pressed', async () => { - // Given - const abortController = new AbortController() - const abort = vi.spyOn(abortController, 'abort') - - // When - const renderInstance = render( - , - ) - - const promise = renderInstance.waitUntilExit() - - await waitForInputsToBeReady() - renderInstance.stdin.write('q') - - await promise - // Then - expect(abort).toHaveBeenCalledOnce() - }) - - test('quits when ctrl+c is pressed', async () => { - // Given - const abortController = new AbortController() - const abort = vi.spyOn(abortController, 'abort') - - // When - const renderInstance = render( - , - ) - - const promise = renderInstance.waitUntilExit() - - await waitForInputsToBeReady() - await sendInputAndWait(renderInstance, 10, '\u0003') - - await promise - // Then - expect(abort).toHaveBeenCalledOnce() - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('abortController can be used to exit from outside and should preserve static output', async () => { - // Given - const abortController = new AbortController() - - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - - // await promise that never resolves - await new Promise(() => {}) - }, - } - - // When - - const renderInstance = render( - , - ) - - const promise = renderInstance.waitUntilExit() - - // Wait for process output to render before aborting - await waitForContent(renderInstance, 'first backend message') - - abortController.abort() - - await promise - - expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - " - `) - expect(developerPreview.disable).toHaveBeenCalledOnce() - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('abortController can be used to exit with an error', async () => { - // Given - const abortController = new AbortController() - - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - - // await promise that never resolves - await new Promise(() => {}) - }, - } - - // When - - const renderInstance = render( - , - ) - - const promise = renderInstance.waitUntilExit() - - // Wait for process output to render before aborting - await waitForContent(renderInstance, 'first backend message') - - abortController.abort('something went wrong') - - await promise - - expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - " - `) - expect(developerPreview.disable).toHaveBeenCalledOnce() - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('accepts inputs when the processes resolve', async () => { - // Given - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - }, - } - - // When - const renderInstance = render( - , - ) - - await waitForContent(renderInstance, 'first backend message') - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - - await waitForInputsToBeReady() - await sendInputAndWait(renderInstance, 10, 'p') - expect(vi.mocked(openURL)).toHaveBeenNthCalledWith(1, 'https://shopify.com') - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('when a process throws an error it calls abort on the abortController', async () => { - // Given - const backendProcess = { - prefix: 'backend', - action: async (_stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - throw new Error('something went wrong') - }, - } - - const abortController = new AbortController() - const abort = vi.spyOn(abortController, 'abort') - - // When - const renderInstance = render( - , - ) - - await expect(renderInstance.waitUntilExit()).rejects.toThrow('something went wrong') - expect(abort).toHaveBeenNthCalledWith(1, new Error('something went wrong')) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('polls for preview mode', async () => { - // Given - vi.mocked(developerPreview.fetchMode).mockReset() - vi.mocked(developerPreview.enable).mockReset() - vi.mocked(developerPreview.fetchMode).mockResolvedValue(true) - - // When - const renderInstance = render( - , - ) - - // Then - // Wait for polling to call fetchMode multiple times (avoids timing-dependent flakiness) - await vi.waitFor( - () => { - expect(developerPreview.fetchMode.mock.calls.length).toBeGreaterThanOrEqual(2) - }, - {timeout: 2000, interval: 10}, - ) - - // enable should be called once at startup - expect(developerPreview.enable).toHaveBeenCalledTimes(1) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test("doesn't poll for preview mode when the app does not support it", async () => { - // Given - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - }, - } - - // Use a locally-scoped mock to isolate from any leaked polling intervals - // from previous tests that might call the module-level developerPreview mock - const localDeveloperPreview = { - fetchMode: vi.fn(async () => true), - enable: vi.fn(async () => true), - disable: vi.fn(async () => {}), - update: vi.fn(async (_state: boolean) => true), - } - - // When - const renderInstance = render( - , - ) - - // Then - // Wait to ensure no polling occurs - await sleep(0.05) - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - expect(localDeveloperPreview.enable).not.toHaveBeenCalled() - expect(localDeveloperPreview.fetchMode).not.toHaveBeenCalled() - - // Verify 'd' input doesn't trigger update when app doesn't support preview - await waitForInputsToBeReady() - await sendInputAndWait(renderInstance, 10, 'd') - expect(localDeveloperPreview.update).not.toHaveBeenCalled() - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('shows an error message when polling for preview mode fails', async () => { - vi.mocked(developerPreview.fetchMode).mockReset() - vi.mocked(developerPreview.fetchMode).mockRejectedValue(new Error('fail')) - - // When - const renderInstance = render( - , - ) - - await waitForContent(renderInstance, 'Failed to fetch') - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d\d:\d\d:\d\d/g, '00:00:00')).toMatchInlineSnapshot(` - " - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:1234/graphiql - Failed to fetch the latest status of the development store preview, trying again in 5 seconds. - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('enables preview mode when pressing d', async () => { - // Given - vi.mocked(developerPreview.update).mockResolvedValueOnce(true) - - const renderInstance = render( - , - ) - - await waitForInputsToBeReady() - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - " - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - - await waitForInputsToBeReady() - await sendInputAndWait(renderInstance, 10, 'd') - expect(developerPreview.update).toHaveBeenCalledOnce() - - await waitForContent(renderInstance, 'off') - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - " - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✖ off - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test("shows an error message if enabling preview mode by pressing d doesn't succeed", async () => { - // Given - vi.mocked(developerPreview.update).mockResolvedValueOnce(false) - - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - }, - } - - const renderInstance = render( - , - ) - - await waitForInputsToBeReady() - await sendInputAndWaitForContent(renderInstance, 'Failed to turn off development store preview.', 'd') - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - Failed to turn off development store preview. - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('shows an error message if enabling preview mode by pressing d throws an exception', async () => { - // Given - vi.mocked(developerPreview.update).mockRejectedValueOnce(new Error('something went wrong')) - - const backendProcess = { - prefix: 'backend', - action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => { - stdout.write('first backend message') - stdout.write('second backend message') - stdout.write('third backend message') - }, - } - - const renderInstance = render( - , - ) - - await waitForInputsToBeReady() - await sendInputAndWaitForContent(renderInstance, 'Failed to turn off development store preview.', 'd') - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - "00:00:00 │ backend │ first backend message - 00:00:00 │ backend │ second backend message - 00:00:00 │ backend │ third backend message - - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - Failed to turn off development store preview. - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('enables preview mode at startup', async () => { - // Given - const renderInstance = render( - , - ) - - await waitForInputsToBeReady() - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - " - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - - await waitForInputsToBeReady() - - expect(developerPreview.enable).toHaveBeenCalledOnce() - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('shows an error message if enabling preview mode at startup fails', async () => { - // Given - vi.mocked(developerPreview.enable).mockRejectedValueOnce(new Error('something went wrong')) - - const renderInstance = render( - , - ) - - await waitForContent(renderInstance, 'Failed to turn on development store preview automatically.') - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - " - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✖ off - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - Failed to turn on development store preview automatically. - Try turning it on manually by pressing \`d\`. - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) - - test('shows an error if handling input throws an error', async () => { - vi.mocked(openURL).mockRejectedValueOnce(new Error('something went wrong')) - - const renderInstance = render( - , - ) - - await waitForInputsToBeReady() - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - " - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - " - `) - - await waitForInputsToBeReady() - await sendInputAndWaitForContent(renderInstance, 'Failed to handle your input.', 'p') - - expect(unstyled(renderInstance.lastFrame()!).replace(/\d/g, '0')).toMatchInlineSnapshot(` - " - ──────────────────────────────────────────────────────────────────────────────────────────────────── - - › Press d │ toggle development store preview: ✔ on - › Press g │ open GraphiQL (Admin API) in your browser - › Press p │ preview in your browser - › Press q │ quit - - Preview URL: https://shopify.com - GraphiQL URL: http://localhost:0000/graphiql - Failed to handle your input. - " - `) - - // unmount so that polling is cleared after every test - renderInstance.unmount() - }) -}) - -describe('calculatePrefixColumnSize', () => { - test('returns max size of processes and extensions', async () => { - // Given - const processes = [ - {prefix: '1', action: async () => {}}, - {prefix: '12', action: async () => {}}, - {prefix: '123', action: async () => {}}, - ] - const extensions = [ - await testUIExtension({configuration: {name: 'Extension 1', handle: '1234', type: 'ui_extension'}}), - await testUIExtension({configuration: {name: 'Extension 2', handle: '12345', type: 'ui_extension'}}), - await testUIExtension({configuration: {name: 'Extension 3', handle: '123456', type: 'ui_extension'}}), - ] - - // When - const result = calculatePrefixColumnSize(processes, extensions) - - // Then - expect(result).toBe(6) - }) -}) diff --git a/packages/app/src/cli/services/dev/ui/components/Dev.tsx b/packages/app/src/cli/services/dev/ui/components/Dev.tsx deleted file mode 100644 index 32f7f163666..00000000000 --- a/packages/app/src/cli/services/dev/ui/components/Dev.tsx +++ /dev/null @@ -1,275 +0,0 @@ -import metadata from '../../../../metadata.js' -import {DeveloperPlatformClient} from '../../../../utilities/developer-platform-client.js' -import {ExtensionInstance} from '../../../../models/extensions/extension-instance.js' -import {OutputProcess} from '@shopify/cli-kit/node/output' -import {ConcurrentOutput, Link} from '@shopify/cli-kit/node/ui/components' -import {useAbortSignal} from '@shopify/cli-kit/node/ui/hooks' -import React, {FunctionComponent, useEffect, useMemo, useRef, useState} from 'react' -import {AbortController, AbortSignal} from '@shopify/cli-kit/node/abort' -import {Box, Text, useInput, useStdin} from '@shopify/cli-kit/node/ink' -import {handleCtrlC} from '@shopify/cli-kit/node/ui' -import {openURL} from '@shopify/cli-kit/node/system' -import figures from '@shopify/cli-kit/node/figures' -import {waitForPostRunHookAndExit} from '@shopify/cli-kit/node/hooks/postrun' -import {Writable} from 'stream' - -export interface DeveloperPreviewController { - fetchMode: () => Promise - enable: () => Promise - disable: () => Promise - update: (state: boolean) => Promise -} - -export interface DevProps { - processes: OutputProcess[] - abortController: AbortController - previewUrl: string - graphiqlUrl?: string - graphiqlPort: number - app: { - canEnablePreviewMode: boolean - developmentStorePreviewEnabled?: boolean - id: string - apiKey: string - developerPlatformClient: DeveloperPlatformClient - extensions: ExtensionInstance[] - } - pollingTime?: number - developerPreview: DeveloperPreviewController - isEditionWeek?: boolean - shopFqdn: string -} - -const calculatePrefixColumnSize = (processes: OutputProcess[], extensions: ExtensionInstance[]) => { - return Math.max( - ...processes.map((process) => process.prefix.length), - ...extensions.map((extension) => extension.handle.length), - ) -} - -const Dev: FunctionComponent = ({ - abortController, - processes, - previewUrl, - graphiqlUrl = '', - graphiqlPort, - app, - pollingTime = 5000, - developerPreview, - isEditionWeek, -}) => { - const {canEnablePreviewMode, developmentStorePreviewEnabled} = app - - const {isRawModeSupported: canUseShortcuts} = useStdin() - const pollingInterval = useRef() - const localhostGraphiqlUrl = `http://localhost:${graphiqlPort}/graphiql` - - const [isShuttingDownMessage, setIsShuttingDownMessage] = useState(undefined) - const [devPreviewEnabled, setDevPreviewEnabled] = useState(true) - const [error, setError] = useState(undefined) - - const {isAborted} = useAbortSignal(abortController.signal, async (err) => { - if (err) { - setIsShuttingDownMessage('Shutting down dev because of an error ...') - } else { - setIsShuttingDownMessage('Shutting down dev ...') - waitForPostRunHookAndExit() - } - clearInterval(pollingInterval.current) - await developerPreview.disable() - }) - - const errorHandledProcesses = useMemo(() => { - return processes.map((process) => { - return { - ...process, - action: async (stdout: Writable, stderr: Writable, signal: AbortSignal) => { - try { - return await process.action(stdout, stderr, signal) - // eslint-disable-next-line no-catch-all/no-catch-all - } catch (error) { - abortController.abort(error) - } - }, - } - }) - }, [processes, abortController]) - - useEffect(() => { - const pollDevPreviewMode = async () => { - try { - const enabled = await developerPreview.fetchMode() - setDevPreviewEnabled(enabled ?? false) - setError('') - // eslint-disable-next-line no-catch-all/no-catch-all - } catch (_) { - setError('Failed to fetch the latest status of the development store preview, trying again in 5 seconds.') - } - } - - const enablePreviewMode = async () => { - // Enable dev preview on app dev start - try { - await developerPreview.enable() - setError('') - // eslint-disable-next-line no-catch-all/no-catch-all - } catch (_) { - setError( - 'Failed to turn on development store preview automatically.\nTry turning it on manually by pressing `d`.', - ) - setDevPreviewEnabled(Boolean(developmentStorePreviewEnabled)) - } - } - - if (canEnablePreviewMode) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - enablePreviewMode() - - const startPolling = () => { - return setInterval( - // eslint-disable-next-line @typescript-eslint/no-misused-promises - () => pollDevPreviewMode(), - pollingTime, - ) - } - - pollingInterval.current = startPolling() - } - - return () => { - clearInterval(pollingInterval.current) - } - }, [canEnablePreviewMode]) - - useInput( - (input, key) => { - handleCtrlC(input, key, () => abortController.abort()) - - const onInput = async () => { - try { - setError('') - - if (input === 'p' && previewUrl) { - await metadata.addPublicMetadata(() => ({ - cmd_dev_preview_url_opened: true, - })) - await openURL(previewUrl) - } else if (input === 'g' && graphiqlUrl) { - await metadata.addPublicMetadata(() => ({ - cmd_dev_graphiql_opened: true, - })) - await openURL(localhostGraphiqlUrl) - } else if (input === 'q') { - abortController.abort() - } else if (input === 'e' && isEditionWeek) { - await openURL('https://shopify.link/yQmk') - } else if (input === 'd' && canEnablePreviewMode) { - await metadata.addPublicMetadata(() => ({ - cmd_dev_dev_preview_toggle_used: true, - })) - const newDevPreviewEnabled = !devPreviewEnabled - setDevPreviewEnabled(newDevPreviewEnabled) - try { - const developerPreviewUpdateSucceded = await developerPreview.update(newDevPreviewEnabled) - if (!developerPreviewUpdateSucceded) { - throw new Error(`Failed to turn ${newDevPreviewEnabled ? 'on' : 'off'} development store preview.`) - } - // eslint-disable-next-line no-catch-all/no-catch-all - } catch (_) { - setDevPreviewEnabled(devPreviewEnabled) - setError(`Failed to turn ${newDevPreviewEnabled ? 'on' : 'off'} development store preview.`) - } - } - // eslint-disable-next-line no-catch-all/no-catch-all - } catch (_) { - setError('Failed to handle your input.') - } - } - - // eslint-disable-next-line @typescript-eslint/no-floating-promises - onInput() - }, - {isActive: Boolean(canUseShortcuts)}, - ) - - const now = new Date() - const season = now.getMonth() > 3 ? 'Summer' : 'Winter' - const year = now.getFullYear() - - return ( - <> - - {/* eslint-disable-next-line no-negated-condition */} - {!isAborted ? ( - - {canUseShortcuts ? ( - - {isEditionWeek ? ( - - {figures.pointerSmall} Press e {figures.lineVertical} check out {season} Edition - {` ${year}`}, live NOW with 100+ product announcements! - - ) : null} - {canEnablePreviewMode ? ( - - {figures.pointerSmall} Press d {figures.lineVertical} toggle development store - preview: {} - {devPreviewEnabled ? ✔ on : ✖ off} - - ) : null} - {graphiqlUrl ? ( - - {figures.pointerSmall} Press g {figures.lineVertical} open GraphiQL (Admin API) in - your browser - - ) : null} - - {figures.pointerSmall} Press p {figures.lineVertical} preview in your browser - - - {figures.pointerSmall} Press q {figures.lineVertical} quit - - - ) : null} - - - {isShuttingDownMessage ? ( - {isShuttingDownMessage} - ) : ( - <> - - Preview URL: - - {graphiqlUrl ? ( - - GraphiQL URL: - - ) : null} - - )} - - - {error ? {error} : null} - - ) : null} - - ) -} - -export {Dev, calculatePrefixColumnSize} diff --git a/packages/app/src/cli/services/dev/update-extension.test.ts b/packages/app/src/cli/services/dev/update-extension.test.ts deleted file mode 100644 index 67304d3b8b7..00000000000 --- a/packages/app/src/cli/services/dev/update-extension.test.ts +++ /dev/null @@ -1,447 +0,0 @@ -import {updateExtensionDraft} from './update-extension.js' -import { - placeholderAppConfiguration, - testFunctionExtension, - testDeveloperPlatformClient, - testPaymentExtensions, - testThemeExtensions, - testUIExtension, -} from '../../models/app/app.test-data.js' -import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' -import {ExtensionUpdateDraftMutationVariables} from '../../api/graphql/partners/generated/update-draft.js' -import {inTemporaryDirectory, mkdir, writeFile} from '@shopify/cli-kit/node/fs' -import {outputInfo} from '@shopify/cli-kit/node/output' -import {describe, expect, vi, test} from 'vitest' -import {dirname, joinPath} from '@shopify/cli-kit/node/path' -import {randomUUID} from '@shopify/cli-kit/node/crypto' - -vi.mock('@shopify/cli-kit/node/crypto') -vi.mock('@shopify/cli-kit/node/output') - -const apiKey = 'mock-api-key' -const registrationId = 'mock-registration-id' -const handle = 'mock-handle' -const stdout = {write: vi.fn()} as any -const stderr = {write: vi.fn()} as any - -describe('updateExtensionDraft()', () => { - test('updates draft successfully and outputs debug message', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient() - await inTemporaryDirectory(async (tmpDir) => { - const configuration = { - runtime_context: 'strict', - settings: {type: 'object'}, - type: 'web_pixel_extension', - handle, - uid: 'uid1', - } as any - - const mockExtension = await testUIExtension({ - devUUID: '1', - configuration, - directory: tmpDir, - uid: 'uid1', - }) - - await mkdir(joinPath(tmpDir, 'uid1', 'dist')) - const outputPath = mockExtension.getOutputPathForDirectory(tmpDir) - await writeFile(outputPath, 'test content') - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(developerPlatformClient.updateExtension).toHaveBeenCalledWith({ - apiKey, - context: '', - handle, - registrationId, - config: - '{"runtime_context":"strict","runtime_configuration_definition":{"type":"object"},"serialized_script":"dGVzdCBjb250ZW50"}', - }) - - // Check if outputDebug is called with success message - expect(outputInfo).toHaveBeenCalledWith( - `Draft updated successfully for extension: ${mockExtension.localIdentifier}`, - stdout, - ) - }) - }) - - test('updates draft successfully with context for extension with target', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient() - const mockExtension = await testPaymentExtensions() - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: 'dir', - }) - - expect(developerPlatformClient.updateExtension).toHaveBeenCalledWith({ - apiKey, - context: 'payments.offsite.render', - handle: mockExtension.handle, - registrationId, - config: '{}', - }) - - // Check if outputDebug is called with success message - expect(outputInfo).toHaveBeenCalledWith( - `Draft updated successfully for extension: ${mockExtension.localIdentifier}`, - stdout, - ) - }) - - test('updates draft successfully when extension doesnt support esbuild', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient() - await inTemporaryDirectory(async (tmpDir) => { - const configuration = { - production_api_base_url: 'url1', - benchmark_api_base_url: 'url2', - type: 'tax_calculation', - handle, - } as any - - const mockExtension = await testUIExtension({ - devUUID: '1', - configuration, - directory: tmpDir, - }) - - await mkdir(joinPath(tmpDir, 'dist')) - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(developerPlatformClient.updateExtension).toHaveBeenCalledWith({ - apiKey, - context: '', - handle, - registrationId, - config: '{"production_api_base_url":"url1","benchmark_api_base_url":"url2"}', - }) - - // Check if outputDebug is called with success message - expect(outputInfo).toHaveBeenCalledWith( - `Draft updated successfully for extension: ${mockExtension.localIdentifier}`, - stdout, - ) - }) - }) - - test('updates draft successfully for theme app extension', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient() - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testThemeExtensions(tmpDir) - - const filepath = 'blocks/block1.liquid' - const content = 'test content' - const base64Content = Buffer.from(content).toString('base64') - await mkdir(joinPath(tmpDir, 'blocks')) - await writeFile(joinPath(tmpDir, filepath), content) - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(developerPlatformClient.updateExtension).toHaveBeenCalledWith({ - apiKey, - context: '', - handle: mockExtension.handle, - registrationId, - config: JSON.stringify({ - theme_extension: { - files: {[filepath]: base64Content}, - }, - }), - }) - }) - }) - - test('updates draft successfully for function app extension', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient() - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testFunctionExtension({dir: tmpDir}) - const moduleId = 'moduleId' - - vi.mocked(randomUUID).mockReturnValue(moduleId) - - const filepath = 'index.wasm' - const content = 'test content' - const base64Content = Buffer.from(content).toString('base64') - await mkdir(joinPath(mockExtension.directory, 'dist')) - const outputPath = mockExtension.outputPath - await mkdir(dirname(outputPath)) - await writeFile(outputPath, content) - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(developerPlatformClient.updateExtension).toHaveBeenCalledWith({ - apiKey, - context: '', - handle: mockExtension.handle, - registrationId, - config: JSON.stringify({ - title: 'test function extension', - module_id: moduleId, - description: 'description', - app_key: 'mock-api-key', - api_type: 'product_discounts', - api_version: '2022-07', - enable_creation_ui: true, - localization: {}, - uploaded_files: {'dist/index.wasm': base64Content}, - }), - }) - }) - }) - - test('handles user errors with stderr message', async () => { - const errorResponse = { - extensionUpdateDraft: { - clientMutationId: 'client-mutation-id', - userErrors: [ - {field: ['field'], message: 'Error1'}, - {field: ['field'], message: 'Error2'}, - ], - }, - } - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - updateExtension: (_extensionInput: ExtensionUpdateDraftMutationVariables) => Promise.resolve(errorResponse), - }) - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testUIExtension({ - devUUID: '1', - directory: tmpDir, - type: 'web_pixel_extension', - uid: 'uid1', - }) - - await mkdir(joinPath(tmpDir, mockExtension.uid, 'dist')) - const outputPath = mockExtension.getOutputPathForDirectory(tmpDir) - await writeFile(outputPath, 'test content') - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(stderr.write).toHaveBeenCalledWith('Error updating extension draft for test-ui-extension: Error1, Error2') - }) - }) - - test('handles system error with errors array', async () => { - const systemError = { - errors: [{message: 'Network error'}, {message: 'Timeout error'}], - } - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - updateExtension: (_extensionInput: ExtensionUpdateDraftMutationVariables) => Promise.reject(systemError), // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors -- testing non-Error rejection handling, - }) - - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testUIExtension({ - devUUID: '1', - directory: tmpDir, - type: 'web_pixel_extension', - uid: 'uid1', - }) - - await mkdir(joinPath(tmpDir, 'uid1', 'dist')) - const outputPath = mockExtension.getOutputPathForDirectory(tmpDir) - await writeFile(outputPath, 'test content') - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(stderr.write).toHaveBeenCalledWith( - 'Error updating extension draft for test-ui-extension: Network error, Timeout error', - ) - }) - }) - - test('handles system error with message string', async () => { - const systemError = {message: 'API connection failed'} - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - updateExtension: (_extensionInput: ExtensionUpdateDraftMutationVariables) => Promise.reject(systemError), // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors -- testing non-Error rejection handling, - }) - - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testUIExtension({ - devUUID: '1', - directory: tmpDir, - type: 'web_pixel_extension', - uid: 'uid1', - }) - - await mkdir(joinPath(tmpDir, 'uid1', 'dist')) - const outputPath = mockExtension.getOutputPathForDirectory(tmpDir) - await writeFile(outputPath, 'test content') - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(stderr.write).toHaveBeenCalledWith( - 'Error updating extension draft for test-ui-extension: API connection failed', - ) - }) - }) - - test('handles string error', async () => { - const systemError = 'Connection timeout' - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - updateExtension: (_extensionInput: ExtensionUpdateDraftMutationVariables) => Promise.reject(systemError), // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors -- testing non-Error rejection handling, - }) - - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testUIExtension({ - devUUID: '1', - directory: tmpDir, - type: 'web_pixel_extension', - uid: 'uid1', - }) - - await mkdir(joinPath(tmpDir, 'uid1', 'dist')) - const outputPath = mockExtension.getOutputPathForDirectory(tmpDir) - await writeFile(outputPath, 'test content') - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(stderr.write).toHaveBeenCalledWith( - 'Error updating extension draft for test-ui-extension: Connection timeout', - ) - }) - }) - - test('handles null/undefined error with fallback message', async () => { - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - updateExtension: (_extensionInput: ExtensionUpdateDraftMutationVariables) => Promise.reject(null), // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors -- testing null rejection handling, - }) - - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testUIExtension({ - devUUID: '1', - directory: tmpDir, - type: 'web_pixel_extension', - uid: 'uid1', - }) - - await mkdir(joinPath(tmpDir, 'uid1', 'dist')) - const outputPath = mockExtension.getOutputPathForDirectory(tmpDir) - await writeFile(outputPath, 'test content') - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(stderr.write).toHaveBeenCalledWith('Error updating extension draft for test-ui-extension: Unknown error') - }) - }) - - test('handles object error without errors or message properties', async () => { - const systemError = {status: 500, code: 'INTERNAL_ERROR'} - const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient({ - updateExtension: (_extensionInput: ExtensionUpdateDraftMutationVariables) => Promise.reject(systemError), // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors -- testing non-Error rejection handling, - }) - - await inTemporaryDirectory(async (tmpDir) => { - const mockExtension = await testUIExtension({ - devUUID: '1', - directory: tmpDir, - type: 'web_pixel_extension', - uid: 'uid1', - }) - - await mkdir(joinPath(tmpDir, 'uid1', 'dist')) - const outputPath = mockExtension.getOutputPathForDirectory(tmpDir) - await writeFile(outputPath, 'test content') - - await updateExtensionDraft({ - extension: mockExtension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration: placeholderAppConfiguration, - bundlePath: tmpDir, - }) - - expect(stderr.write).toHaveBeenCalledWith('Error updating extension draft for test-ui-extension: Unknown error') - }) - }) -}) diff --git a/packages/app/src/cli/services/dev/update-extension.ts b/packages/app/src/cli/services/dev/update-extension.ts deleted file mode 100644 index 7252018f7b5..00000000000 --- a/packages/app/src/cli/services/dev/update-extension.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { - ExtensionUpdateDraftMutation, - ExtensionUpdateDraftMutationVariables, -} from '../../api/graphql/partners/generated/update-draft.js' -import {AppConfiguration} from '../../models/app/app.js' -import {ExtensionInstance} from '../../models/extensions/extension-instance.js' -import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' -import {themeExtensionConfig} from '../deploy/theme-extension-config.js' -import {readFile} from '@shopify/cli-kit/node/fs' -import {outputInfo} from '@shopify/cli-kit/node/output' -import {Writable} from 'stream' - -interface UpdateExtensionDraftOptions { - extension: ExtensionInstance - developerPlatformClient: DeveloperPlatformClient - apiKey: string - registrationId: string - stdout: Writable - stderr: Writable - appConfiguration: AppConfiguration - bundlePath: string -} - -export async function updateExtensionDraft({ - extension, - developerPlatformClient, - apiKey, - registrationId, - stdout, - stderr, - appConfiguration, - bundlePath, -}: UpdateExtensionDraftOptions) { - let encodedFile: string | undefined - const outputPath = extension.getOutputPathForDirectory(bundlePath) - if (extension.features.includes('esbuild')) { - const content = await readFile(outputPath) - if (!content) return - encodedFile = Buffer.from(content).toString('base64') - } - - let config - if (extension.isThemeExtension) { - // When updating just the theme extension draft, upload the files as part of the config. - config = await themeExtensionConfig(extension) - } else { - config = (await extension.deployConfig({apiKey, appConfiguration})) ?? {} - } - - const draftableConfig: {[key: string]: unknown} = { - ...config, - serialized_script: encodedFile, - } - if (extension.isFunctionExtension) { - // For function drafts we need to use the `extension.outputPath` instead of `bundlePath` - // The wasm in the bundle path is encoded in base64. - const compiledFiles = await readFile(extension.outputPath, {encoding: 'base64'}) - draftableConfig.uploaded_files = {'dist/index.wasm': compiledFiles} - } - const extensionInput: ExtensionUpdateDraftMutationVariables = { - apiKey, - config: JSON.stringify(draftableConfig), - handle: extension.handle, - context: extension.contextValue, - registrationId, - } - - let mutationResult: ExtensionUpdateDraftMutation | undefined - let errors: {message: string}[] = [] - try { - mutationResult = await developerPlatformClient.updateExtension(extensionInput) - // eslint-disable-next-line no-catch-all/no-catch-all - } catch (error: unknown) { - errors = [{message: 'Unknown error'}] - - if (error && typeof error === 'object') { - const errorObj = error as {errors?: {message: string}[]; message?: string} - if (errorObj.errors?.length) { - errors = errorObj.errors - } else if (errorObj.message) { - errors = [{message: errorObj.message}] - } - } else if (typeof error === 'string') { - errors = [{message: error}] - } - } - const userErrors = mutationResult?.extensionUpdateDraft?.userErrors - if (userErrors?.length) { - errors.push(...userErrors) - } - if (errors.length > 0) { - const errorMessages = errors.map((error: {message: string}) => error.message).join(', ') - stderr.write(`${extension.draftMessages.errorMessage}: ${errorMessages}`) - } else { - const draftUpdateSuccesMessage = extension.draftMessages.successMessage - if (draftUpdateSuccesMessage) outputInfo(draftUpdateSuccesMessage, stdout) - } -} diff --git a/packages/app/src/cli/services/dev/urls.test.ts b/packages/app/src/cli/services/dev/urls.test.ts index e21ec3aff65..204efbe56f9 100644 --- a/packages/app/src/cli/services/dev/urls.test.ts +++ b/packages/app/src/cli/services/dev/urls.test.ts @@ -206,7 +206,6 @@ describe('shouldOrPromptUpdateURLs', () => { appDirectory: '/path', newApp: true, apiKey: 'api-key', - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], @@ -227,7 +226,6 @@ describe('shouldOrPromptUpdateURLs', () => { appDirectory: '/path', cachedUpdateURLs: true, apiKey: 'api-key', - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], @@ -248,7 +246,6 @@ describe('shouldOrPromptUpdateURLs', () => { appDirectory: '/path', cachedUpdateURLs: false, apiKey: 'api-key', - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], @@ -268,7 +265,6 @@ describe('shouldOrPromptUpdateURLs', () => { currentURLs, appDirectory: '/path', apiKey: 'api-key', - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], @@ -289,7 +285,6 @@ describe('shouldOrPromptUpdateURLs', () => { currentURLs, appDirectory: '/path', apiKey: 'api-key', - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], @@ -310,7 +305,6 @@ describe('shouldOrPromptUpdateURLs', () => { currentURLs, appDirectory: '/path', apiKey: 'api-key', - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], @@ -335,7 +329,6 @@ describe('shouldOrPromptUpdateURLs', () => { appDirectory: '/path', apiKey: 'api-key', localApp: testApp({configuration: {...DEFAULT_CONFIG, client_id: 'different'}}) as AppLinkedInterface, - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], @@ -360,7 +353,6 @@ describe('shouldOrPromptUpdateURLs', () => { appDirectory: '/path', apiKey: 'api-key', localApp: localApp as AppLinkedInterface, - developerPlatformClient: testDeveloperPlatformClient(), newURLs: { applicationUrl: 'https://example.com/home', redirectUrlWhitelist: ['https://example.com/auth/callback'], diff --git a/packages/app/src/cli/services/dev/urls.ts b/packages/app/src/cli/services/dev/urls.ts index 8db28d4a880..5065743a545 100644 --- a/packages/app/src/cli/services/dev/urls.ts +++ b/packages/app/src/cli/services/dev/urls.ts @@ -227,7 +227,6 @@ interface ShouldOrPromptUpdateURLsOptions { localApp?: AppLinkedInterface apiKey: string newURLs: ApplicationURLs - developerPlatformClient: DeveloperPlatformClient } export async function shouldOrPromptUpdateURLs(options: ShouldOrPromptUpdateURLsOptions): Promise { @@ -236,12 +235,7 @@ export async function shouldOrPromptUpdateURLs(options: ShouldOrPromptUpdateURLs let shouldUpdateURLs: boolean = options.cachedUpdateURLs === true if (options.cachedUpdateURLs === undefined) { - shouldUpdateURLs = await updateURLsPrompt( - options.developerPlatformClient.supportsDevSessions, - options.currentURLs.applicationUrl, - options.currentURLs.redirectUrlWhitelist, - options.newURLs, - ) + shouldUpdateURLs = await updateURLsPrompt(options.currentURLs.applicationUrl, options.newURLs) if (options.localApp) { const localConfiguration = options.localApp.configuration diff --git a/packages/app/src/cli/services/extensions/common.ts b/packages/app/src/cli/services/extensions/common.ts index b218e096010..79ad12eaeed 100644 --- a/packages/app/src/cli/services/extensions/common.ts +++ b/packages/app/src/cli/services/extensions/common.ts @@ -1,7 +1,6 @@ import {AppInterface} from '../../models/app/app.js' import {blocks, configurationFileNames} from '../../constants.js' import {ExtensionFlavor} from '../../models/app/template.js' -import {DeveloperPlatformClient} from '../../utilities/developer-platform-client.js' import {joinPath} from '@shopify/cli-kit/node/path' import {fileExists, mkdir, touchFile} from '@shopify/cli-kit/node/fs' import {AbortError} from '@shopify/cli-kit/node/error' @@ -31,29 +30,3 @@ export async function ensureExtensionDirectoryExists({name, app}: {name: string; await touchFile(joinPath(extensionDirectory, configurationFileNames.lockFile)) return extensionDirectory } - -export async function canEnablePreviewMode({ - localApp, - developerPlatformClient, - apiKey, - organizationId, -}: { - localApp: AppInterface - developerPlatformClient: DeveloperPlatformClient - apiKey: string - organizationId: string -}) { - const {dashboardManagedExtensionRegistrations} = ( - await developerPlatformClient.appExtensionRegistrations({ - id: apiKey, - apiKey, - organizationId, - }) - ).app - if (dashboardManagedExtensionRegistrations.length > 0) return true - const themeExtensions = localApp.allExtensions.filter((ext) => ext.isThemeExtension) - if (themeExtensions.length > 0) return true - if (localApp.allExtensions.length > 0) return true - - return false -} diff --git a/packages/app/src/cli/services/format-config-info-body.test.ts b/packages/app/src/cli/services/format-config-info-body.test.ts index 60384d04379..0b7a2dace5c 100644 --- a/packages/app/src/cli/services/format-config-info-body.test.ts +++ b/packages/app/src/cli/services/format-config-info-body.test.ts @@ -137,62 +137,6 @@ describe('formatConfigInfoBody', () => { }) }) - test('if includeConfigOnDeploy is true, it shows an item for includeConfigOnDeploy', () => { - // GIVEN - const options = { - appName: 'test-app', - includeConfigOnDeploy: true, - } - - // WHEN - const result = formatConfigInfoBody(options) - - // THEN - const body = result as Token[] - expect(body[0]).toMatchObject({ - list: { - items: expect.arrayContaining(['Include config: Yes']), - }, - }) - }) - - test('if includeConfigOnDeploy is false, it shows an item for includeConfigOnDeploy with No', () => { - // GIVEN - const options = { - appName: 'test-app', - includeConfigOnDeploy: false, - } - - // WHEN - const result = formatConfigInfoBody(options) - - // THEN - const body = result as Token[] - expect(body[0]).toMatchObject({ - list: { - items: expect.arrayContaining(['Include config: No']), - }, - }) - }) - - test('if includeConfigOnDeploy is undefined, it does not show an item for includeConfigOnDeploy', () => { - // GIVEN - const options = { - appName: 'test-app', - } - - // WHEN - const result = formatConfigInfoBody(options) - - // THEN - const body = result as Token[] - expect(body[0]).toMatchObject({ - list: { - items: expect.not.arrayContaining([expect.stringMatching(/^Include config:/)]), - }, - }) - }) - test('if there are messages, it shows each message as a distinct paragraph', () => { // GIVEN const message1: Token[] = ['First message'] diff --git a/packages/app/src/cli/services/format-config-info-body.ts b/packages/app/src/cli/services/format-config-info-body.ts index 61e15a1ad14..3cbd4546032 100644 --- a/packages/app/src/cli/services/format-config-info-body.ts +++ b/packages/app/src/cli/services/format-config-info-body.ts @@ -5,7 +5,6 @@ interface FormatConfigInfoBodyOptions { org?: string devStores?: string[] updateURLs?: string - includeConfigOnDeploy?: boolean messages?: Token[][] } @@ -36,7 +35,6 @@ export function formatConfigInfoBody({ org, devStores, updateURLs, - includeConfigOnDeploy, messages, }: FormatConfigInfoBodyOptions): TokenItem { const items = [`App: ${appName}`] @@ -45,7 +43,6 @@ export function formatConfigInfoBody({ devStores.forEach((storeUrl) => items.push(`Dev store: ${storeUrl}`)) } if (updateURLs) items.push(`Update URLs: ${updateURLs}`) - if (includeConfigOnDeploy !== undefined) items.push(`Include config: ${includeConfigOnDeploy ? 'Yes' : 'No'}`) let body: Token[] = [{list: {items}}] diff --git a/packages/app/src/cli/services/import-extensions.ts b/packages/app/src/cli/services/import-extensions.ts index 9c72206eaf1..a1429f81ec7 100644 --- a/packages/app/src/cli/services/import-extensions.ts +++ b/packages/app/src/cli/services/import-extensions.ts @@ -79,7 +79,7 @@ async function handleExtensionDirectory({ } export async function importExtensions(options: ImportOptions) { - const {app, remoteApp, developerPlatformClient, extensionTypes, extensions, buildExtensionConfig, all} = options + const {app, remoteApp, extensionTypes, extensions, buildExtensionConfig, all} = options let extensionsToMigrate = extensions.filter((ext) => extensionTypes.includes(ext.type.toLowerCase())) extensionsToMigrate = filterOutImportedExtensions(app, extensionsToMigrate) @@ -131,7 +131,6 @@ export async function importExtensions(options: ImportOptions) { app: remoteApp.apiKey, }, command: 'import-extensions', - developerPlatformClient, }) } diff --git a/packages/app/src/cli/services/release.ts b/packages/app/src/cli/services/release.ts index cd0e50d4578..4d3101fe85e 100644 --- a/packages/app/src/cli/services/release.ts +++ b/packages/app/src/cli/services/release.ts @@ -56,9 +56,8 @@ export async function release(options: ReleaseOptions) { extensionIdentifiersBreakdown, appTitle: remoteApp.title, release: true, - force: options.force, - allowUpdates: options.allowUpdates, - allowDeletes: options.allowDeletes, + allowUpdates: options.force || options.allowUpdates, + allowDeletes: options.force || options.allowDeletes, }) if (!confirmed) throw new AbortSilentError() interface Context { diff --git a/packages/app/src/cli/utilities/app-command.ts b/packages/app/src/cli/utilities/app-command.ts index ddf87484447..39f050c74e6 100644 --- a/packages/app/src/cli/utilities/app-command.ts +++ b/packages/app/src/cli/utilities/app-command.ts @@ -1,12 +1,15 @@ import {configurationFileNames} from '../constants.js' import {AppInterface} from '../models/app/app.js' import BaseCommand from '@shopify/cli-kit/node/base-command' +import {authAliasFlag} from '@shopify/cli-kit/node/cli' interface AppCommandOutput { app: AppInterface } export default abstract class AppCommand extends BaseCommand { + static baseFlags = authAliasFlag + environmentsFilename(): string { return configurationFileNames.appEnvironments } diff --git a/packages/app/src/cli/utilities/developer-platform-client.ts b/packages/app/src/cli/utilities/developer-platform-client.ts index b058f1b407f..f092e6d1d1b 100644 --- a/packages/app/src/cli/utilities/developer-platform-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client.ts @@ -11,17 +11,11 @@ import { import {AllAppExtensionRegistrationsQuerySchema} from '../api/graphql/all_app_extension_registrations.js' import {AppDeploySchema, AppDeployVariables} from '../api/graphql/app_deploy.js' -import {ExtensionCreateSchema, ExtensionCreateVariables} from '../api/graphql/extension_create.js' import { ConvertDevToTransferDisabledSchema, ConvertDevToTransferDisabledStoreVariables, } from '../api/graphql/convert_dev_to_transfer_disabled_store.js' import {AppVersionsQuerySchema} from '../api/graphql/get_versions_list.js' -import { - DevelopmentStorePreviewUpdateInput, - DevelopmentStorePreviewUpdateSchema, -} from '../api/graphql/development_preview.js' -import {FindAppPreviewModeSchema, FindAppPreviewModeVariables} from '../api/graphql/find_app_preview_mode.js' import {AppReleaseSchema} from '../api/graphql/app_release.js' import {AppVersionsDiffSchema} from '../api/graphql/app_versions_diff.js' import {SendSampleWebhookSchema, SendSampleWebhookVariables} from '../services/webhook/request-sample.js' @@ -43,10 +37,6 @@ import { import {RemoteSpecification} from '../api/graphql/extension_specifications.js' import {MigrateAppModuleSchema, MigrateAppModuleVariables} from '../api/graphql/extension_migrate_app_module.js' import {AppManifest} from '../models/app/app.js' -import { - ExtensionUpdateDraftMutation, - ExtensionUpdateDraftMutationVariables, -} from '../api/graphql/partners/generated/update-draft.js' import {DevSessionCreateMutation} from '../api/graphql/app-dev/generated/dev-session-create.js' import {DevSessionUpdateMutation} from '../api/graphql/app-dev/generated/dev-session-update.js' import {DevSessionDeleteMutation} from '../api/graphql/app-dev/generated/dev-session-delete.js' @@ -62,7 +52,6 @@ import {TokenItem} from '@shopify/cli-kit/node/ui' import {blockPartnersAccess} from '@shopify/cli-kit/node/environment' import {UnauthorizedHandler} from '@shopify/cli-kit/node/api/graphql' import {JsonMapType} from '@shopify/cli-kit/node/toml' -import {firstPartyDev} from '@shopify/cli-kit/node/context/local' export type {Store} from '../api/graphql/business-platform-organizations/generated/types.js' @@ -109,8 +98,6 @@ function selectDeveloperPlatformClientByOrg(organization: Organization): Develop } function defaultDeveloperPlatformClient(): DeveloperPlatformClient { - if (firstPartyDev() && !blockPartnersAccess()) return PartnersClient.getInstance() - return AppManagementClient.getInstance() } @@ -234,12 +221,8 @@ export interface TemplateSpecificationsOptions { export interface DeveloperPlatformClient { readonly clientName: ClientName readonly webUiName: string - readonly supportsAtomicDeployments: boolean - readonly supportsDevSessions: boolean - readonly supportsStoreSearch: boolean readonly organizationSource: OrganizationSource readonly bundleFormat: 'zip' | 'br' - readonly supportsDashboardManagedExtensions: boolean session: () => Promise /** * This is an unsafe method that should only be used when the session is expired. @@ -272,15 +255,11 @@ export interface DeveloperPlatformClient { appVersionByTag: (app: MinimalOrganizationApp, tag: string) => Promise appVersionsDiff: (app: MinimalOrganizationApp, version: AppVersionIdentifiers) => Promise generateSignedUploadUrl: (app: MinimalAppIdentifiers) => Promise - createExtension: (input: ExtensionCreateVariables) => Promise - updateExtension: (input: ExtensionUpdateDraftMutationVariables) => Promise deploy: (input: AppDeployOptions) => Promise release: (input: {app: MinimalOrganizationApp; version: AppVersionIdentifiers}) => Promise convertToTransferDisabledStore: ( input: ConvertDevToTransferDisabledStoreVariables, ) => Promise - updateDeveloperPreview: (input: DevelopmentStorePreviewUpdateInput) => Promise - appPreviewMode: (input: FindAppPreviewModeVariables) => Promise sendSampleWebhook: (input: SendSampleWebhookVariables, organizationId: string) => Promise apiVersions: (organizationId: string) => Promise topics: (input: WebhookTopicsVariables, organizationId: string) => Promise diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts index 3bb3ee7528c..07b32c020bd 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts @@ -44,16 +44,10 @@ import { } from '../../api/graphql/all_app_extension_registrations.js' import {AppDeploySchema} from '../../api/graphql/app_deploy.js' import {AppVersionsQuerySchema as AppVersionsQuerySchemaInterface} from '../../api/graphql/get_versions_list.js' -import {ExtensionCreateSchema, ExtensionCreateVariables} from '../../api/graphql/extension_create.js' import { ConvertDevToTransferDisabledSchema, ConvertDevToTransferDisabledStoreVariables, } from '../../api/graphql/convert_dev_to_transfer_disabled_store.js' -import {FindAppPreviewModeSchema, FindAppPreviewModeVariables} from '../../api/graphql/find_app_preview_mode.js' -import { - DevelopmentStorePreviewUpdateInput, - DevelopmentStorePreviewUpdateSchema, -} from '../../api/graphql/development_preview.js' import {AppReleaseSchema} from '../../api/graphql/app_release.js' import {AppVersionsDiffSchema} from '../../api/graphql/app_versions_diff.js' import { @@ -75,10 +69,6 @@ import { MigrateToUiExtensionSchema, } from '../../api/graphql/extension_migrate_to_ui_extension.js' import {MigrateAppModuleSchema, MigrateAppModuleVariables} from '../../api/graphql/extension_migrate_app_module.js' -import { - ExtensionUpdateDraftMutation, - ExtensionUpdateDraftMutationVariables, -} from '../../api/graphql/partners/generated/update-draft.js' import {AppHomeSpecIdentifier} from '../../models/extensions/specifications/app_config_app_home.js' import {BrandingSpecIdentifier} from '../../models/extensions/specifications/app_config_branding.js' import {AppAccessSpecIdentifier} from '../../models/extensions/specifications/app_config_app_access.js' @@ -201,12 +191,8 @@ export class AppManagementClient implements DeveloperPlatformClient { public readonly clientName = ClientName.AppManagement public readonly webUiName = 'Developer Dashboard' - public readonly supportsAtomicDeployments = true - public readonly supportsDevSessions = true - public readonly supportsStoreSearch = true public readonly organizationSource = OrganizationSource.BusinessPlatform public readonly bundleFormat = 'br' - public readonly supportsDashboardManagedExtensions = false private _session: Session | undefined private constructor(session?: Session) { @@ -748,10 +734,6 @@ export class AppManagementClient implements DeveloperPlatformClient { } } - async updateExtension(_extensionInput: ExtensionUpdateDraftMutationVariables): Promise { - throw new BugError('Not implemented: updateExtension') - } - async deploy({ appManifest, appId, @@ -907,26 +889,12 @@ export class AppManagementClient implements DeveloperPlatformClient { } } - async createExtension(_input: ExtensionCreateVariables): Promise { - throw new BugError('Not implemented: createExtension') - } - async convertToTransferDisabledStore( _input: ConvertDevToTransferDisabledStoreVariables, ): Promise { throw new BugError('Not implemented: convertToTransferDisabledStore') } - async updateDeveloperPreview( - _input: DevelopmentStorePreviewUpdateInput, - ): Promise { - throw new BugError('Not implemented: updateDeveloperPreview') - } - - async appPreviewMode(_input: FindAppPreviewModeVariables): Promise { - throw new BugError('Not implemented: appPreviewMode') - } - async sendSampleWebhook(input: SendSampleWebhookVariables, organizationId: string): Promise { const query = CliTesting const variables = { diff --git a/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts b/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts index b80967269a5..fa2dafdc36e 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts @@ -39,11 +39,6 @@ import { GenerateSignedUploadUrlSchema, GenerateSignedUploadUrlVariables, } from '../../api/graphql/generate_signed_upload_url.js' -import { - ExtensionCreateQuery, - ExtensionCreateSchema, - ExtensionCreateVariables, -} from '../../api/graphql/extension_create.js' import { ConvertDevToTransferDisabledStoreQuery, ConvertDevToTransferDisabledSchema, @@ -60,16 +55,6 @@ import { AppVersionsQueryVariables, AppVersionsQuerySchema, } from '../../api/graphql/get_versions_list.js' -import { - DevelopmentStorePreviewUpdateInput, - DevelopmentStorePreviewUpdateQuery, - DevelopmentStorePreviewUpdateSchema, -} from '../../api/graphql/development_preview.js' -import { - FindAppPreviewModeQuery, - FindAppPreviewModeSchema, - FindAppPreviewModeVariables, -} from '../../api/graphql/find_app_preview_mode.js' import { AppVersionsDiffQuery, AppVersionsDiffSchema, @@ -133,11 +118,6 @@ import { import {AppLogsSubscribeMutation, AppLogsSubscribeResponse} from '../../api/graphql/subscribe_to_app_logs.js' import {AllOrgs} from '../../api/graphql/partners/generated/all-orgs.js' -import { - ExtensionUpdateDraft, - ExtensionUpdateDraftMutation, - ExtensionUpdateDraftMutationVariables, -} from '../../api/graphql/partners/generated/update-draft.js' import {FindAppQuery, FindAppQuerySchema, FindAppQueryVariables} from '../../api/graphql/find_app.js' import { FindOrganizationQuery, @@ -213,12 +193,8 @@ export class PartnersClient implements DeveloperPlatformClient { public readonly clientName = ClientName.Partners public readonly webUiName = 'Partner Dashboard' - public readonly supportsAtomicDeployments = false - public readonly supportsDevSessions = false - public readonly supportsStoreSearch = false public readonly organizationSource = OrganizationSource.Partners public readonly bundleFormat = 'zip' - public readonly supportsDashboardManagedExtensions = true private _session: Session | undefined private constructor(session?: Session) { @@ -462,14 +438,6 @@ export class PartnersClient implements DeveloperPlatformClient { } } - async createExtension(input: ExtensionCreateVariables): Promise { - return this.request(ExtensionCreateQuery, input) - } - - async updateExtension(extensionInput: ExtensionUpdateDraftMutationVariables): Promise { - return this.requestDoc(ExtensionUpdateDraft, extensionInput) - } - async deploy(deployInput: AppDeployOptions): Promise { const {organizationId, ...deployOptions} = deployInput // Enforce the type @@ -527,16 +495,6 @@ export class PartnersClient implements DeveloperPlatformClient { // This is a no-op for partners } - async updateDeveloperPreview( - input: DevelopmentStorePreviewUpdateInput, - ): Promise { - return this.request(DevelopmentStorePreviewUpdateQuery, input) - } - - async appPreviewMode(input: FindAppPreviewModeVariables): Promise { - return this.request(FindAppPreviewModeQuery, input) - } - async sendSampleWebhook( input: SendSampleWebhookVariables, _organizationId: string, diff --git a/packages/cli-kit/src/private/node/analytics/error-grouping.test.ts b/packages/cli-kit/src/private/node/analytics/error-grouping.test.ts new file mode 100644 index 00000000000..a87c5cedf80 --- /dev/null +++ b/packages/cli-kit/src/private/node/analytics/error-grouping.test.ts @@ -0,0 +1,162 @@ +import {errorGroupingHash, errorGroupingSignals, resolveErrorGrouping} from './error-grouping.js' +import {GraphQLClientError} from '../api/headers.js' +import {AbortError} from '../../../public/node/error.js' +import {ClientError} from 'graphql-request' +import {describe, expect, test} from 'vitest' + +function clientError(status: number, code?: string): ClientError { + const errors = code ? [{message: 'boom', extensions: {code}}] : undefined + return new ClientError({status, errors, headers: {}} as any, {query: 'q'} as any) +} + +function clientErrorWithErrors(status: number, errors: unknown[]): ClientError { + return new ClientError({status, errors, headers: {}} as any, {query: 'q'} as any) +} + +describe('errorGroupingSignals', () => { + test('reads status, code, and class from a GraphQLClientError', () => { + const error = new GraphQLClientError('Forbidden', 403, [{extensions: {code: 'ACCESS_DENIED'}}]) + + expect(errorGroupingSignals(error)).toEqual({ + httpStatus: 403, + code: 'ACCESS_DENIED', + errorClass: 'GraphQLClientError', + }) + }) + + test('reads status and code from a raw graphql-request ClientError', () => { + const error = clientError(429, 'THROTTLED') + + expect(errorGroupingSignals(error)).toEqual({ + httpStatus: 429, + code: 'THROTTLED', + errorClass: 'ClientError', + }) + }) + + test('returns only the class name for a generic Error', () => { + expect(errorGroupingSignals(new Error('boom'))).toEqual({errorClass: 'Error'}) + }) + + test('returns an empty object for a non-Error value', () => { + expect(errorGroupingSignals('boom')).toEqual({}) + }) + + test('ignores a non-array errors value', () => { + const error = new GraphQLClientError('weird', 400, 'not-an-array' as any) + + expect(errorGroupingSignals(error)).toEqual({httpStatus: 400, errorClass: 'GraphQLClientError'}) + }) +}) + +describe('errorGroupingHash — structured decision table', () => { + test.each<[string, ClientError | GraphQLClientError, string]>([ + ['THROTTLED code -> rate_limit', clientError(400, 'THROTTLED'), 'theme:rate_limit:http-400-throttled'], + ['HTTP 429 -> rate_limit', clientError(429), 'theme:rate_limit:http-429'], + ['HTTP 401 -> authentication', clientError(401), 'theme:authentication:http-401'], + ['HTTP 403 -> permission', clientError(403), 'theme:permission:http-403'], + ['ACCESS_DENIED code -> permission', clientError(400, 'ACCESS_DENIED'), 'theme:permission:http-400-access-denied'], + ['HTTP 500 -> server', clientError(500), 'theme:server:http-500'], + ['HTTP 503 -> server', clientError(503), 'theme:server:http-503'], + ])('%s', (_, error, expected) => { + expect(errorGroupingHash(error, 'theme')).toEqual(expected) + }) + + test('403 wins over a 401-looking authentication category (permission, not authentication)', () => { + const error = new GraphQLClientError('Forbidden', 403, [{extensions: {code: 'ACCESS_DENIED'}}]) + + expect(errorGroupingHash(error, 'store')).toEqual('store:permission:http-403-access-denied') + }) + + test('prefixes the hash with the provided slice name', () => { + expect(errorGroupingHash(clientError(429), 'app')).toEqual('app:rate_limit:http-429') + expect(errorGroupingHash(clientError(429), 'cli')).toEqual('cli:rate_limit:http-429') + }) +}) + +describe('errorGroupingHash — message fallback', () => { + test('recovers an HTTP status flattened into an AbortError message', () => { + const error = new AbortError('The request responded unsuccessfully with the HTTP status 500') + + expect(errorGroupingHash(error, 'theme')).toEqual('theme:server:http-500') + }) + + test('recovers a graphql-request style "(Code: NNN)" status from a message', () => { + const error = new Error('GraphQL Error (Code: 401): {"response":{"status":401}}') + + expect(errorGroupingHash(error, 'store')).toEqual('store:authentication:http-401') + }) + + test('falls back to the keyword categorizer for an untyped, signal-less error', () => { + const error = new Error('connect ETIMEDOUT 1.2.3.4:443') + const hash = errorGroupingHash(error, 'cli') + + expect(hash).toMatch(/^cli:network:/) + }) + + test('returns undefined for an unknown error so stack-trace grouping is preserved', () => { + expect(errorGroupingHash(new Error('something nobody has categorized'), 'cli')).toBeUndefined() + }) + + test('returns undefined for a non-Error value', () => { + expect(errorGroupingHash(undefined, 'cli')).toBeUndefined() + }) +}) + +describe('errorGroupingHash — multi-error & nested codes (review #3/#5)', () => { + test('recognizes the GraphQL string code "429" as rate_limit, even at HTTP 200', () => { + // Mirrors errorsIncludeStatus429 in private/node/api.ts. + expect(errorGroupingHash(clientError(200, '429'), 'theme')).toEqual('theme:rate_limit:http-200-429') + }) + + test('scans every error, not just the first, for a routable code', () => { + const error = clientErrorWithErrors(200, [{message: 'noise'}, {extensions: {code: 'THROTTLED'}}]) + + expect(errorGroupingHash(error, 'theme')).toEqual('theme:rate_limit:http-200-throttled') + }) + + test('recognizes a nested App Management app_errors access_denied as permission', () => { + const error = clientErrorWithErrors(200, [{extensions: {app_errors: {errors: [{category: 'access_denied'}]}}}]) + + expect(errorGroupingHash(error, 'app')).toEqual('app:permission:http-200-access-denied') + }) +}) + +describe('errorGroupingHash — precedence & merge (review #2/#4)', () => { + test('401 wins over a co-occurring ACCESS_DENIED code (authentication, by decision)', () => { + const error = new GraphQLClientError('Unauthenticated', 401, [{extensions: {code: 'ACCESS_DENIED'}}]) + + // HTTP 401 is authoritative; the access-denied code is still recorded in the signature. + expect(errorGroupingHash(error, 'theme')).toEqual('theme:authentication:http-401-access-denied') + }) + + test('an absent object code does not erase a code recovered from the message', () => { + const error = new GraphQLClientError( + 'GraphQL Error (Code: 500): {"response":{"errors":[{"extensions":{"code":"INTERNAL"}}]}}', + 500, + ) + + const {signals, category} = resolveErrorGrouping(error, 'theme') + expect(category).toEqual('server') + expect(signals.httpStatus).toEqual(500) + expect(signals.code).toEqual('INTERNAL') + }) +}) + +describe('resolveErrorGrouping', () => { + test('returns hash, category, and signals together for the metadata path', () => { + expect(resolveErrorGrouping(clientError(403, 'ACCESS_DENIED'), 'store')).toEqual({ + hash: 'store:permission:http-403-access-denied', + category: 'permission', + signals: {httpStatus: 403, code: 'ACCESS_DENIED', errorClass: 'ClientError'}, + }) + }) + + test('returns an undefined hash but still-useful signals for an unknown error', () => { + const result = resolveErrorGrouping(new Error('nothing categorizes this'), 'cli') + + expect(result.hash).toBeUndefined() + expect(result.category).toBeUndefined() + expect(result.signals.errorClass).toEqual('Error') + }) +}) diff --git a/packages/cli-kit/src/private/node/analytics/error-grouping.ts b/packages/cli-kit/src/private/node/analytics/error-grouping.ts new file mode 100644 index 00000000000..05e1673b578 --- /dev/null +++ b/packages/cli-kit/src/private/node/analytics/error-grouping.ts @@ -0,0 +1,230 @@ +import {categorizeError, ErrorCategory, formatErrorMessage} from './error-categorizer.js' +import {graphQLErrorCodes, isPermissionCode, isRateLimitCode} from './graphql-error-codes.js' +import {GraphQLClientError} from '../api/headers.js' +import {slugify} from '../../../public/common/string.js' +import {ClientError} from 'graphql-request' + +/** + * Structured signals extracted from an error, used to group it into a meaningful Bugsnag bucket. + * + * These are read from the *original* typed error (before it is flattened to a generic `Error` + * for reporting), so we group on facts the error already carries rather than by re-parsing a + * stringified message. + */ +interface ErrorGroupingSignals { + httpStatus?: number + code?: string + errorClass?: string +} + +/** + * The fully resolved grouping decision for an error: the Bugsnag grouping hash (or `undefined` to + * fall back to stack-trace grouping), the semantic category, and the structured signals that drove + * the decision. The reporter uses a single resolution for both `event.groupingHash` and the + * `error_grouping` metadata so they can never disagree. + */ +interface ResolvedErrorGrouping { + hash?: string + category?: string + signals: ErrorGroupingSignals +} + +/** + * Extracts structured grouping signals from an error object. + * + * Only assigns a field when a value is actually present, so the result can be safely merged over + * message-derived signals without an explicit `undefined` erasing a recovered value. + * + * @param error - The original error (any type). + * @returns The HTTP status, GraphQL error code, and error class name when available. + */ +export function errorGroupingSignals(error: unknown): ErrorGroupingSignals { + const signals: ErrorGroupingSignals = {} + + if (error instanceof Error) { + signals.errorClass = error.constructor.name + } + + // GraphQLClientError (handleErrors: true, status < 500) preserves the status and errors array. + if (error instanceof GraphQLClientError) { + if (error.statusCode !== undefined) signals.httpStatus = error.statusCode + const code = routableCode(error.errors) + if (code !== undefined) signals.code = code + return signals + } + + // Raw graphql-request ClientError (handleErrors: false) exposes the full response. + if (error instanceof ClientError) { + const status = error.response?.status + if (status !== undefined) signals.httpStatus = status + const code = routableCode(error.response?.errors) + if (code !== undefined) signals.code = code + } + + return signals +} + +/** + * Resolves the full grouping decision for an error: hash, category, and the signals behind it. + * + * Categories are resolved structured-first (HTTP status / GraphQL code), falling back to the + * shared keyword categorizer only for untyped errors. When no meaningful category can be + * resolved, `hash` is `undefined` so the caller leaves `event.groupingHash` unset and Bugsnag's + * default stack-trace grouping applies — this avoids merging genuinely distinct unknown bugs. + * + * @param error - The original error (any type). + * @param sliceName - The product slice (`app`, `theme`, `store`, `hydrogen`, or `cli`). + * @returns The resolved hash (or `undefined`), category, and structured signals. + */ +export function resolveErrorGrouping(error: unknown, sliceName: string): ResolvedErrorGrouping { + const message = errorMessage(error) + // Object signals are authoritative; message-derived signals fill gaps (e.g. 5xx errors that the + // API layer flattens into an AbortError, dropping the structured status field). Merge field by + // field so an absent object signal never clobbers one recovered from the message. + const fromError = errorGroupingSignals(error) + const fromMessage = signalsFromMessage(message) + const signals: ErrorGroupingSignals = { + httpStatus: fromError.httpStatus ?? fromMessage.httpStatus, + code: fromError.code ?? fromMessage.code, + errorClass: fromError.errorClass ?? fromMessage.errorClass, + } + + const structuredCategory = categoryFromSignals(signals) + if (structuredCategory) { + return { + hash: `${sliceName}:${structuredCategory}:${structuredSignature(signals)}`, + category: structuredCategory, + signals, + } + } + + const groupingError = new Error(stripJsonDump(message)) + const category = categorizeError(groupingError) + if (category === ErrorCategory.Unknown) { + return {hash: undefined, category: undefined, signals} + } + + const categoryName = category.toLowerCase() + return { + hash: `${sliceName}:${categoryName}:${formatErrorMessage(groupingError, category)}`, + category: categoryName, + signals, + } +} + +/** + * Builds a Bugsnag grouping hash of the form `${slice}:${category}:${signature}`. + * + * Thin wrapper over {@link resolveErrorGrouping} for callers that only need the hash. + * + * @param error - The original error (any type). + * @param sliceName - The product slice (`app`, `theme`, `store`, `hydrogen`, or `cli`). + * @returns The grouping hash, or `undefined` to fall back to stack-trace grouping. + */ +export function errorGroupingHash(error: unknown, sliceName: string): string | undefined { + return resolveErrorGrouping(error, sliceName).hash +} + +/** + * Resolves a semantic category from structured signals using an explicit decision table. + * + * Precedence is deliberate: + * - rate limit (`THROTTLED`/`429` code or HTTP 429) wins first — it is the most actionable bucket. + * - HTTP 401 is authoritative for `authentication`: a request the server rejected as + * unauthenticated is an authentication problem even if a GraphQL code also reports access-denied. + * `ACCESS_DENIED` in practice pairs with HTTP 403, which is handled by the permission branch. + * - 403 / `ACCESS_DENIED` (incl. nested App Management `access_denied`) → `permission`. + * + * Returns `undefined` when no structured signal is present. + */ +function categoryFromSignals(signals: ErrorGroupingSignals): string | undefined { + const {httpStatus, code} = signals + + if (isRateLimitCode(code) || httpStatus === 429) return 'rate_limit' + if (httpStatus === 401) return 'authentication' + if (httpStatus === 403 || isPermissionCode(code)) return 'permission' + if (httpStatus !== undefined && httpStatus >= 500) return 'server' + + return undefined +} + +/** + * Builds a stable, low-cardinality signature slug from structured signals. + */ +function structuredSignature(signals: ErrorGroupingSignals): string { + const parts: string[] = [] + if (signals.httpStatus !== undefined) parts.push(`http-${signals.httpStatus}`) + if (signals.code) parts.push(signals.code) + if (parts.length === 0 && signals.errorClass) parts.push(signals.errorClass) + + return slugify(parts.join('-')).slice(0, 50) +} + +/** + * Recovers structured signals from an error message string. Handles both error shapes seen from + * the API layer: graphql-request's `GraphQL Error (Code: NNN): {json}` and the cli-kit wrapper's + * `... responded unsuccessfully with the HTTP status NNN ...`. + */ +function signalsFromMessage(message: string): ErrorGroupingSignals { + const signals: ErrorGroupingSignals = {} + + const statusMatch = message.match(/HTTP status (\d{3})/i) ?? message.match(/\(Code: (\d{3})\)/i) + if (statusMatch?.[1]) signals.httpStatus = Number(statusMatch[1]) + + const payload = parseEmbeddedJson(message) + if (signals.httpStatus === undefined && payload?.response?.status !== undefined) { + signals.httpStatus = payload.response.status + } + const code = routableCode(payload?.response?.errors) + if (code !== undefined) signals.code = code + + return signals +} + +interface EmbeddedGraphQLPayload { + response?: { + status?: number + errors?: unknown + } +} + +/** + * Parses the JSON blob embedded in a graphql-request ClientError message, if present. + */ +function parseEmbeddedJson(message: string): EmbeddedGraphQLPayload | undefined { + const jsonStart = message.indexOf('{') + if (jsonStart === -1) return undefined + + try { + return JSON.parse(message.slice(jsonStart)) as EmbeddedGraphQLPayload + // eslint-disable-next-line no-catch-all/no-catch-all + } catch { + return undefined + } +} + +/** + * Picks the most routing-relevant code from a GraphQL `errors` value. + * + * Scans every error (not just the first) and prefers a code we route on — a rate-limit code, then + * a permission code — so a benign leading code can't mask a `THROTTLED` or `ACCESS_DENIED` further + * down the array. Falls back to the first code present for visibility. + */ +function routableCode(errors: unknown): string | undefined { + const codes = graphQLErrorCodes(errors) + return codes.find(isRateLimitCode) ?? codes.find(isPermissionCode) ?? codes[0] +} + +/** + * Strips a trailing JSON dump (`...: {json}`) from a message so the keyword categorizer sees the + * human-readable prefix rather than the serialized request/response (which contains the literal + * `request`, mis-routing to the network category). + */ +function stripJsonDump(message: string): string { + return message.split(': {')[0] ?? message +} + +function errorMessage(error: unknown): string { + if (error instanceof Error) return error.message + return typeof error === 'string' ? error : '' +} diff --git a/packages/cli-kit/src/private/node/analytics/graphql-error-codes.test.ts b/packages/cli-kit/src/private/node/analytics/graphql-error-codes.test.ts new file mode 100644 index 00000000000..445cdde70b0 --- /dev/null +++ b/packages/cli-kit/src/private/node/analytics/graphql-error-codes.test.ts @@ -0,0 +1,41 @@ +import {graphQLErrorCodes, hasRateLimitCode, isPermissionCode, isRateLimitCode} from './graphql-error-codes.js' +import {describe, expect, test} from 'vitest' + +describe('graphQLErrorCodes', () => { + test('reads top-level extensions.code from every error, in order', () => { + const errors = [{extensions: {code: 'FIRST'}}, {message: 'no code'}, {extensions: {code: 'THROTTLED'}}] + + expect(graphQLErrorCodes(errors)).toEqual(['FIRST', 'THROTTLED']) + }) + + test('reads nested App Management app_errors categories', () => { + const errors = [{extensions: {app_errors: {errors: [{category: 'access_denied'}, {category: 'other'}]}}}] + + expect(graphQLErrorCodes(errors)).toEqual(['access_denied', 'other']) + }) + + test('returns an empty array for a string errors value (some 401 responses)', () => { + expect(graphQLErrorCodes('unauthenticated')).toEqual([]) + expect(graphQLErrorCodes(undefined)).toEqual([]) + }) +}) + +describe('code predicates', () => { + test('isRateLimitCode recognizes THROTTLED and the string 429', () => { + expect(isRateLimitCode('THROTTLED')).toBe(true) + expect(isRateLimitCode('429')).toBe(true) + expect(isRateLimitCode('ACCESS_DENIED')).toBe(false) + expect(isRateLimitCode(undefined)).toBe(false) + }) + + test('isPermissionCode recognizes ACCESS_DENIED and nested access_denied', () => { + expect(isPermissionCode('ACCESS_DENIED')).toBe(true) + expect(isPermissionCode('access_denied')).toBe(true) + expect(isPermissionCode('THROTTLED')).toBe(false) + }) + + test('hasRateLimitCode scans all errors, not just the first', () => { + expect(hasRateLimitCode([{message: 'a'}, {extensions: {code: '429'}}])).toBe(true) + expect(hasRateLimitCode([{extensions: {code: 'OTHER'}}])).toBe(false) + }) +}) diff --git a/packages/cli-kit/src/private/node/analytics/graphql-error-codes.ts b/packages/cli-kit/src/private/node/analytics/graphql-error-codes.ts new file mode 100644 index 00000000000..78126c604a4 --- /dev/null +++ b/packages/cli-kit/src/private/node/analytics/graphql-error-codes.ts @@ -0,0 +1,79 @@ +/** + * Pure helpers for reading routing-relevant codes out of a GraphQL error response. + * + * This module is intentionally dependency-free: it is imported by both the grouping logic + * (`error-grouping.ts`) and the crash-report suppression logic (`../../public/node/error.ts`). + * `error.ts` cannot import `error-grouping.ts` directly — that would create an + * `error.ts → headers.ts → error.ts` import cycle — so the shared scanning logic lives here, + * where it imports nothing from cli-kit. + */ + +/** GraphQL `extensions.code` values we treat as rate limiting. */ +const RATE_LIMIT_CODES = new Set(['THROTTLED', '429']) + +/** + * GraphQL `extensions.code` values (and nested App Management `app_errors` categories) we treat as + * a permission / access-denied signal. The top-level admin code is `ACCESS_DENIED`; the App + * Management nested shape uses the lowercase category `access_denied`. + */ +const PERMISSION_CODES = new Set(['ACCESS_DENIED', 'access_denied']) + +/** + * Collects every routing-relevant code from a GraphQL `errors` value. + * + * Scans *all* errors (not just the first), reading both the top-level `extensions.code` and the + * nested App Management shape `extensions.app_errors.errors[].category`. The API can also return + * `errors` as a string (e.g. some 401s), which yields no codes. + * + * @param errors - The `errors` value from a GraphQL response (array, string, or undefined). + * @returns Every string code/category found, in document order. + */ +export function graphQLErrorCodes(errors: unknown): string[] { + if (!Array.isArray(errors)) return [] + + return errors.flatMap((entry) => { + const found: string[] = [] + const error = entry as {extensions?: {code?: unknown; app_errors?: {errors?: unknown}}} | undefined + + const code = error?.extensions?.code + if (typeof code === 'string') found.push(code) + + const appErrors = error?.extensions?.app_errors?.errors + if (Array.isArray(appErrors)) { + for (const appError of appErrors) { + const category = (appError as {category?: unknown} | undefined)?.category + if (typeof category === 'string') found.push(category) + } + } + + return found + }) +} + +/** + * Whether a single code is a rate-limit signal (`THROTTLED` or `429`). + * + * Mirrors the established shape detected by `errorsIncludeStatus429` in `private/node/api.ts`, + * where `extensions.code === '429'` signals rate limiting even at HTTP 200. + */ +export function isRateLimitCode(code: string | undefined): boolean { + return code !== undefined && RATE_LIMIT_CODES.has(code) +} + +/** + * Whether a single code/category is a permission / access-denied signal. + */ +export function isPermissionCode(code: string | undefined): boolean { + return code !== undefined && PERMISSION_CODES.has(code) +} + +/** + * Whether any GraphQL error carries a rate-limit code. Convenience for suppression logic that only + * needs a boolean over the raw `errors` value. + * + * @param errors - The `errors` value from a GraphQL response. + * @returns True when a rate-limit code is present in any error. + */ +export function hasRateLimitCode(errors: unknown): boolean { + return graphQLErrorCodes(errors).some(isRateLimitCode) +} diff --git a/packages/cli-kit/src/private/node/api/headers.test.ts b/packages/cli-kit/src/private/node/api/headers.test.ts index c27668fc7ad..ca5fc50ae76 100644 --- a/packages/cli-kit/src/private/node/api/headers.test.ts +++ b/packages/cli-kit/src/private/node/api/headers.test.ts @@ -1,7 +1,7 @@ import {buildHeaders, sanitizedHeadersOutput, GraphQLClientError} from './headers.js' import {CLI_KIT_VERSION} from '../../../public/common/version.js' import {randomUUID} from '../../../public/node/crypto.js' -import {firstPartyDev, isUnitTest} from '../../../public/node/context/local.js' +import {isUnitTest} from '../../../public/node/context/local.js' import {test, vi, expect, describe, beforeEach} from 'vitest' @@ -14,30 +14,9 @@ beforeEach(() => { }) describe('common API methods', () => { - test('headers are built correctly when firstPartyDev yields true', () => { + test('headers are built correctly', () => { // Given vi.mocked(randomUUID).mockReturnValue('random-uuid') - vi.mocked(firstPartyDev).mockReturnValue(true) - // When - const headers = buildHeaders('my-token') - - // Then - const version = CLI_KIT_VERSION - expect(headers).toEqual({ - 'Content-Type': 'application/json', - 'Keep-Alive': 'timeout=30', - 'X-Shopify-Access-Token': 'Bearer my-token', - 'User-Agent': `Shopify CLI; v=${version}`, - authorization: 'Bearer my-token', - 'Sec-CH-UA-PLATFORM': process.platform, - 'X-Shopify-Cli-Employee': '1', - }) - }) - - test('when user is not employee, do not include header', () => { - // Given - vi.mocked(randomUUID).mockReturnValue('random-uuid') - vi.mocked(firstPartyDev).mockReturnValue(false) // When const headers = buildHeaders('my-token') @@ -58,7 +37,6 @@ describe('common API methods', () => { (prefix) => { // Given vi.mocked(randomUUID).mockReturnValue('random-uuid') - vi.mocked(firstPartyDev).mockReturnValue(false) const token = `${prefix}_my_token` // When const headers = buildHeaders(token) diff --git a/packages/cli-kit/src/private/node/api/headers.ts b/packages/cli-kit/src/private/node/api/headers.ts index 47095a323ce..c5947d24582 100644 --- a/packages/cli-kit/src/private/node/api/headers.ts +++ b/packages/cli-kit/src/private/node/api/headers.ts @@ -1,5 +1,5 @@ import {CLI_KIT_VERSION} from '../../../public/common/version.js' -import {firstPartyDev, isUnitTest, isVerbose} from '../../../public/node/context/local.js' +import {isUnitTest, isVerbose} from '../../../public/node/context/local.js' import {AbortError} from '../../../public/node/error.js' import https from 'https' @@ -60,7 +60,6 @@ export function buildHeaders(token?: string): Record { // 'Sec-CH-UA': secCHUA, This header requires the Git sha. 'Sec-CH-UA-PLATFORM': process.platform, 'Content-Type': 'application/json', - ...(firstPartyDev() && {'X-Shopify-Cli-Employee': '1'}), } if (token) { const authString = token.match(/^shp(at|ua|ca|tka)/) ? token : `Bearer ${token}` diff --git a/packages/cli-kit/src/private/node/constants.ts b/packages/cli-kit/src/private/node/constants.ts index a38e83f2d90..4063fbd99ee 100644 --- a/packages/cli-kit/src/private/node/constants.ts +++ b/packages/cli-kit/src/private/node/constants.ts @@ -19,7 +19,6 @@ export const environmentVariables = { doctor: 'SHOPIFY_CLI_DOCTOR', enableCliRedirect: 'SHOPIFY_CLI_ENABLE_CLI_REDIRECT', env: 'SHOPIFY_CLI_ENV', - firstPartyDev: 'SHOPIFY_CLI_1P_DEV', noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS', optOutInstrumentation: 'OPT_OUT_INSTRUMENTATION', appAutomationToken: 'SHOPIFY_APP_AUTOMATION_TOKEN', diff --git a/packages/cli-kit/src/private/node/session.test.ts b/packages/cli-kit/src/private/node/session.test.ts index 8d3593fd1be..d781fff189a 100644 --- a/packages/cli-kit/src/private/node/session.test.ts +++ b/packages/cli-kit/src/private/node/session.test.ts @@ -4,6 +4,7 @@ import { getLastSeenUserIdAfterAuth, OAuthApplications, OAuthSession, + setCommandSessionId, setLastSeenAuthMethod, setLastSeenUserIdAfterAuth, } from './session.js' @@ -19,7 +20,7 @@ import {ApplicationToken, IdentityToken, Sessions} from './session/schema.js' import {validateSession} from './session/validate.js' import {applicationId} from './session/identity.js' import {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js' -import {getCurrentSessionId} from './conf-store.js' +import {getCurrentSessionId, setCurrentSessionId} from './conf-store.js' import * as fqdnModule from '../../public/node/context/fqdn.js' import {themeToken} from '../../public/node/context/local.js' import {partnersRequest} from '../../public/node/api/partners.js' @@ -133,6 +134,7 @@ beforeEach(() => { vi.mocked(allDefaultScopes).mockImplementation((scopes) => scopes ?? []) setLastSeenUserIdAfterAuth(undefined as any) setLastSeenAuthMethod('none') + setCommandSessionId(undefined) vi.mocked(requestDeviceAuthorization).mockResolvedValue({ deviceCode: 'device_code', @@ -313,6 +315,34 @@ describe('when existing session is valid', () => { expect(fetchSessions).toHaveBeenCalledOnce() }) + test('uses the command selected session without changing the current session ID', async () => { + // Given + const selectedUserId = 'selected-user-id' + const sessions: Sessions = { + [fqdn]: { + [userId]: { + identity: validIdentityToken, + applications: {}, + }, + [selectedUserId]: { + identity: {...validIdentityToken, userId: selectedUserId}, + applications: appTokens, + }, + }, + } + vi.mocked(validateSession).mockResolvedValueOnce('ok') + vi.mocked(fetchSessions).mockResolvedValue(sessions) + setCommandSessionId(selectedUserId) + + // When + const got = await ensureAuthenticated(defaultApplications) + + // Then + expect(getCurrentSessionId).not.toHaveBeenCalled() + expect(validateSession).toHaveBeenCalledWith(expect.any(Array), expect.any(Object), sessions[fqdn]![selectedUserId]) + expect(got).toEqual({...validTokens, userId: selectedUserId}) + }) + test('overwrites partners token if provided with a custom CLI token', async () => { // Given vi.mocked(validateSession).mockResolvedValueOnce('ok') @@ -350,6 +380,32 @@ describe('when existing session is valid', () => { await expect(getLastSeenAuthMethod()).resolves.toEqual('device_auth') expect(fetchSessions).toHaveBeenCalledOnce() }) + + test('refreshes the command selected session without changing the current session ID', async () => { + // Given + const selectedUserId = 'selected-user-id' + const sessions: Sessions = { + [fqdn]: { + [selectedUserId]: { + identity: {...validIdentityToken, userId: selectedUserId}, + applications: appTokens, + }, + }, + } + vi.mocked(validateSession).mockResolvedValueOnce('needs_refresh') + vi.mocked(fetchSessions).mockResolvedValue(sessions) + vi.mocked(refreshAccessToken).mockResolvedValueOnce({...validIdentityToken, userId: selectedUserId}) + setCommandSessionId(selectedUserId) + + // When + const got = await ensureAuthenticated(defaultApplications) + + // Then + expect(refreshAccessToken).toHaveBeenCalled() + expect(storeSessions).toHaveBeenCalledWith(sessions) + expect(setCurrentSessionId).not.toHaveBeenCalled() + expect(got).toEqual({...validTokens, userId: selectedUserId}) + }) }) describe('when existing session is expired', () => { diff --git a/packages/cli-kit/src/private/node/session.ts b/packages/cli-kit/src/private/node/session.ts index 3b750d1cdcb..3eb9f9e5ee6 100644 --- a/packages/cli-kit/src/private/node/session.ts +++ b/packages/cli-kit/src/private/node/session.ts @@ -16,7 +16,7 @@ import {isThemeAccessSession} from './api/rest.js' import {getCurrentSessionId, setCurrentSessionId} from './conf-store.js' import {UserEmailQueryString, UserEmailQuery} from './api/graphql/business-platform-destinations/user-email.js' import {outputContent, outputToken, outputDebug, outputCompleted} from '../../public/node/output.js' -import {firstPartyDev, themeToken} from '../../public/node/context/local.js' +import {themeToken} from '../../public/node/context/local.js' import {AbortError} from '../../public/node/error.js' import {normalizeStoreFqdn, identityFqdn} from '../../public/node/context/fqdn.js' import {getIdentityTokenInformation, getAppAutomationToken} from '../../public/node/environment.js' @@ -118,6 +118,7 @@ type AuthMethod = 'partners_token' | 'device_auth' | 'theme_access_token' | 'cus let userId: undefined | string let authMethod: AuthMethod = 'none' +let commandSessionId: string | undefined /** * Retrieves a stable user identifier for analytics, or `'unknown'` if none applies. @@ -179,6 +180,10 @@ export function setLastSeenAuthMethod(method: AuthMethod) { authMethod = method } +export function setCommandSessionId(sessionId: string | undefined) { + commandSessionId = sessionId +} + export interface EnsureAuthenticatedAdditionalOptions { noPrompt?: boolean forceRefresh?: boolean @@ -210,8 +215,8 @@ export async function ensureAuthenticated( const sessions = (await sessionStore.fetch()) ?? {} - let currentSessionId = getCurrentSessionId() - if (!currentSessionId) { + let currentSessionId = forceNewSession ? undefined : (commandSessionId ?? getCurrentSessionId()) + if (!currentSessionId && !commandSessionId) { const userIds = Object.keys(sessions[fqdn] ?? {}) if (userIds.length > 0) currentSessionId = userIds[0] } @@ -260,7 +265,7 @@ ${outputToken.json(applications)} // Save the new session info if it has changed if (!isEmpty(newSession)) { await sessionStore.store(updatedSessions) - setCurrentSessionId(newSessionId) + if (!commandSessionId) setCurrentSessionId(newSessionId) } const tokens = await tokensFor(applications, completeSession) @@ -296,10 +301,6 @@ async function executeCompleteFlow(applications: OAuthApplications, existingAlia const scopes = getFlattenScopes(applications) const exchangeScopes = getExchangeScopes(applications) const store = applications.adminApi?.storeFqdn - if (firstPartyDev()) { - outputDebug(outputContent`Authenticating as Shopify Employee...`) - scopes.push('employee') - } let identityToken: IdentityToken const identityTokenInformation = getIdentityTokenInformation() diff --git a/packages/cli-kit/src/private/node/session/validate.test.ts b/packages/cli-kit/src/private/node/session/validate.test.ts index 12f8300b683..51df0fc5662 100644 --- a/packages/cli-kit/src/private/node/session/validate.test.ts +++ b/packages/cli-kit/src/private/node/session/validate.test.ts @@ -140,6 +140,20 @@ describe('validateSession', () => { expect(got).toBe('needs_full_auth') }) + test('returns needs_full_auth if cached identity has employee scope', async () => { + // Given + const session = { + identity: {...validIdentity, scopes: [...validIdentity.scopes, 'employee']}, + applications: validApplications, + } + + // When + const got = await validateSession(requestedScopes, defaultApps, session) + + // Then + expect(got).toBe('needs_full_auth') + }) + test('returns needs_refresh if identity is expired', async () => { // Given const session = { diff --git a/packages/cli-kit/src/private/node/session/validate.ts b/packages/cli-kit/src/private/node/session/validate.ts index d4b79799284..362457b2bb1 100644 --- a/packages/cli-kit/src/private/node/session/validate.ts +++ b/packages/cli-kit/src/private/node/session/validate.ts @@ -2,7 +2,6 @@ import {ApplicationToken, IdentityToken, Session, validateCachedIdentityTokenStr import {applicationId} from './identity.js' import {sessionConstants} from '../constants.js' -import {firstPartyDev} from '../../../public/node/context/local.js' import {OAuthApplications} from '../session.js' import {outputDebug} from '../../../public/node/output.js' @@ -13,7 +12,7 @@ type ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok' */ function validateScopes(requestedScopes: string[], identity: IdentityToken) { const currentScopes = identity.scopes - if (firstPartyDev() !== currentScopes.includes('employee')) return false + if (currentScopes.includes('employee')) return false return requestedScopes.every((scope) => currentScopes.includes(scope)) } diff --git a/packages/cli-kit/src/public/node/base-command.ts b/packages/cli-kit/src/public/node/base-command.ts index 2cb2cf4b5a2..1da872612e0 100644 --- a/packages/cli-kit/src/public/node/base-command.ts +++ b/packages/cli-kit/src/public/node/base-command.ts @@ -2,6 +2,7 @@ import {isDevelopment} from './context/local.js' import {addPublicMetadata} from './metadata.js' import {AbortError} from './error.js' import {outputContent, outputResult, outputToken} from './output.js' +import {setCurrentSessionAlias} from './session.js' import {terminalSupportsPrompting} from './system.js' import {hashString} from './crypto.js' import {isTruthy} from './context/utilities.js' @@ -17,6 +18,7 @@ export type ArgOutput = OutputArgs export type FlagOutput = OutputFlags interface EnvironmentFlags { + 'auth-alias'?: string environment?: string[] path?: string } @@ -95,7 +97,7 @@ abstract class BaseCommand extends Command { } protected async parse< - TFlags extends FlagOutput & {path?: string; verbose?: boolean}, + TFlags extends FlagOutput & {path?: string; verbose?: boolean; 'auth-alias'?: string}, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput, >( @@ -104,6 +106,7 @@ abstract class BaseCommand extends Command { ): Promise & {argv: string[]}> { let result = await super.parse(options, argv) result = await this.resultWithEnvironment(result, options, argv) + await setCurrentSessionAlias(result.flags['auth-alias']) await addFromParsedFlags(result.flags) return {...result, ...{argv: result.argv as string[]}} } diff --git a/packages/cli-kit/src/public/node/cli.ts b/packages/cli-kit/src/public/node/cli.ts index 10a6a2eb006..14b2add6c1f 100644 --- a/packages/cli-kit/src/public/node/cli.ts +++ b/packages/cli-kit/src/public/node/cli.ts @@ -153,6 +153,13 @@ export const jsonFlag = { }), } +export const authAliasFlag = { + 'auth-alias': Flags.string({ + description: 'Alias of the Shopify account to use for authentication.', + env: 'SHOPIFY_FLAG_AUTH_ALIAS', + }), +} + /** * Builds a `--port` flag that only accepts a valid port number. The flag parses its * value as an integer and rejects anything that isn't a whole number between 1 and diff --git a/packages/cli-kit/src/public/node/context/local.ts b/packages/cli-kit/src/public/node/context/local.ts index ad816399db9..c39093c65e6 100644 --- a/packages/cli-kit/src/public/node/context/local.ts +++ b/packages/cli-kit/src/public/node/context/local.ts @@ -135,16 +135,6 @@ export function alwaysLogMetrics(env = process.env): boolean { return isTruthy(env[environmentVariables.alwaysLogMetrics]) } -/** - * Returns true if the CLI User is 1P. - * - * @param env - The environment variables from the environment of the current process. - * @returns True if SHOPIFY_CLI_1P is truthy. - */ -export function firstPartyDev(env = process.env): boolean { - return isTruthy(env[environmentVariables.firstPartyDev]) -} - /** * Returns true if the CLI can run the "doctor-release" command. * diff --git a/packages/cli-kit/src/public/node/error-handler.test.ts b/packages/cli-kit/src/public/node/error-handler.test.ts index 8f101ab55d4..261894a1577 100644 --- a/packages/cli-kit/src/public/node/error-handler.test.ts +++ b/packages/cli-kit/src/public/node/error-handler.test.ts @@ -6,13 +6,14 @@ import * as error from './error.js' import {hashString} from './crypto.js' import {isLocalEnvironment} from '../../private/node/context/service.js' import {getLastSeenUserIdAfterAuth} from '../../private/node/session.js' +import {GraphQLClientError} from '../../private/node/api/headers.js' import {settings} from '@oclif/core' import {beforeEach, describe, expect, test, vi} from 'vitest' const onNotify = vi.fn() const capturedEventHandler = vi.fn() -let lastBugsnagEvent: {addMetadata: ReturnType} | undefined +let lastBugsnagEvent: {addMetadata: ReturnType; groupingHash?: string} | undefined vi.mock('process') vi.mock('@bugsnag/js', () => { @@ -303,4 +304,61 @@ describe('sends errors to Bugsnag', () => { expect(lastBugsnagEvent).toBeDefined() expect(lastBugsnagEvent!.addMetadata).toHaveBeenCalledWith('custom', {slice_name: 'cli'}) }) + + test('sets a structured groupingHash and error_grouping metadata for a typed API error', async () => { + await metadata.addSensitiveMetadata(() => ({ + commandStartOptions: {startTime: Date.now(), startCommand: 'theme dev', startArgs: []}, + })) + const apiError = new GraphQLClientError('Forbidden', 403, [{extensions: {code: 'ACCESS_DENIED'}}]) + + await sendErrorToBugsnag(apiError, 'unexpected_error') + + expect(lastBugsnagEvent).toBeDefined() + expect(lastBugsnagEvent!.groupingHash).toEqual('theme:permission:http-403-access-denied') + expect(lastBugsnagEvent!.addMetadata).toHaveBeenCalledWith('error_grouping', { + slice_name: 'theme', + category: 'permission', + http_status: 403, + error_code: 'ACCESS_DENIED', + error_class: 'GraphQLClientError', + }) + }) + + test('emits message-derived signals and category in metadata for a flattened API error', async () => { + await metadata.addSensitiveMetadata(() => ({ + commandStartOptions: {startTime: Date.now(), startCommand: 'theme dev', startArgs: []}, + })) + // A 5xx the API layer flattened into an AbortError: the structured status field is gone, but it + // is recoverable from the message and must still reach both the hash and the metadata. + const flattened = new Error('The request responded unsuccessfully with the HTTP status 503') + + await sendErrorToBugsnag(flattened, 'unexpected_error') + + expect(lastBugsnagEvent!.groupingHash).toEqual('theme:server:http-503') + expect(lastBugsnagEvent!.addMetadata).toHaveBeenCalledWith('error_grouping', { + slice_name: 'theme', + category: 'server', + http_status: 503, + error_code: undefined, + error_class: 'Error', + }) + }) + + test('leaves groupingHash unset for an unknown error but still tags error_grouping metadata', async () => { + await metadata.addSensitiveMetadata(() => ({ + commandStartOptions: {startTime: Date.now(), startCommand: 'app dev', startArgs: []}, + })) + + await sendErrorToBugsnag(new Error('something nobody has categorized'), 'unexpected_error') + + expect(lastBugsnagEvent).toBeDefined() + expect(lastBugsnagEvent!.groupingHash).toBeUndefined() + expect(lastBugsnagEvent!.addMetadata).toHaveBeenCalledWith('error_grouping', { + slice_name: 'app', + category: undefined, + http_status: undefined, + error_code: undefined, + error_class: 'Error', + }) + }) }) diff --git a/packages/cli-kit/src/public/node/error-handler.ts b/packages/cli-kit/src/public/node/error-handler.ts index d639c9d3d33..7e6617c11e5 100644 --- a/packages/cli-kit/src/public/node/error-handler.ts +++ b/packages/cli-kit/src/public/node/error-handler.ts @@ -12,6 +12,7 @@ import { } from './error.js' import {outputDebug, outputInfo} from './output.js' import {getEnvironmentData} from '../../private/node/analytics.js' +import {resolveErrorGrouping} from '../../private/node/analytics/error-grouping.js' import {isLocalEnvironment} from '../../private/node/context/service.js' import {bugsnagApiKey, reportingRateLimit} from '../../private/node/constants.js' import {CLI_KIT_VERSION} from '../common/version.js' @@ -26,7 +27,15 @@ import {realpath} from 'fs/promises' // Allowed slice names for error analytics grouping. // Hardcoded list per product slices to keep analytics consistent. -const ALLOWED_SLICE_NAMES = new Set(['app', 'theme', 'hydrogen', 'store']) +const ALLOWED_SLICE_NAMES = new Set(['app', 'theme', 'hydrogen', 'store', 'organization']) + +// Derives the product slice from the command that was running (e.g. `theme dev` -> `theme`), +// defaulting to `cli` when the command is unknown or not in the allow-list. +function sliceNameFromStartCommand(startCommand: string | undefined): string { + if (!startCommand) return 'cli' + const firstWord = startCommand.trim().split(/\s+/)[0] ?? 'cli' + return ALLOWED_SLICE_NAMES.has(firstWord) ? firstWord : 'cli' +} export async function errorHandler( error: Error & {exitCode?: number | undefined}, @@ -147,11 +156,29 @@ export async function sendErrorToBugsnag( // Attach command metadata so we know which CLI command triggered the error const {commandStartOptions} = metadata.getAllSensitiveMetadata() const {startCommand} = commandStartOptions ?? {} + const sliceName = sliceNameFromStartCommand(startCommand) if (startCommand) { - const firstWord = startCommand.trim().split(/\s+/)[0] ?? 'cli' - const sliceName = ALLOWED_SLICE_NAMES.has(firstWord) ? firstWord : 'cli' event.addMetadata('custom', {slice_name: sliceName}) } + + // Group on structured signals from the *original* error (not the flattened + // `reportableError`), and emit those signals as metadata so backend dashboards and + // routing work without depending on the grouping hash or on CLI version adoption. + // A single resolution drives both the hash and the metadata so they can never disagree: + // the metadata carries the resolved category and the same (message-merged) signals. + // When no meaningful category resolves we leave `groupingHash` unset so Bugsnag's + // stack-trace grouping applies and distinct unknown bugs are not merged. + const {hash: groupingHash, category, signals} = resolveErrorGrouping(error, sliceName) + if (groupingHash) { + event.groupingHash = groupingHash + } + event.addMetadata('error_grouping', { + slice_name: sliceName, + category, + http_status: signals.httpStatus, + error_code: signals.code, + error_class: signals.errorClass, + }) } const errorHandler = (error: unknown) => { if (error) { diff --git a/packages/cli-kit/src/public/node/error.test.ts b/packages/cli-kit/src/public/node/error.test.ts index 1bba30c0633..b80d0054526 100644 --- a/packages/cli-kit/src/public/node/error.test.ts +++ b/packages/cli-kit/src/public/node/error.test.ts @@ -1,7 +1,13 @@ import {AbortError, BugError, handler, cleanSingleStackTracePath, shouldReportErrorAsUnexpected} from './error.js' import {renderFatalError} from './ui.js' +import {ClientError} from 'graphql-request' import {describe, expect, test, vi} from 'vitest' +function clientError(status: number, code?: string): ClientError { + const errors = code ? [{message: 'boom', extensions: {code}}] : undefined + return new ClientError({status, errors, headers: {}} as any, {query: 'q'} as any) +} + vi.mock('./ui.js') describe('handler', () => { @@ -82,4 +88,33 @@ describe('shouldReportErrorAsUnexpected helper', () => { test('returns false for unsupported platform errors', () => { expect(shouldReportErrorAsUnexpected(new Error('Unsupported platform: win32 arm64 LE'))).toBe(false) }) + + test('returns false for a raw ClientError that is rate limited (HTTP 429)', () => { + expect(shouldReportErrorAsUnexpected(clientError(429))).toBe(false) + }) + + test('returns false for a raw ClientError that is unauthenticated (HTTP 401)', () => { + expect(shouldReportErrorAsUnexpected(clientError(401))).toBe(false) + }) + + test('returns false for a raw ClientError with a THROTTLED code', () => { + expect(shouldReportErrorAsUnexpected(clientError(400, 'THROTTLED'))).toBe(false) + }) + + test('returns false for a raw ClientError with a GraphQL "429" code at HTTP 200', () => { + // Matches errorsIncludeStatus429 in private/node/api.ts. + expect(shouldReportErrorAsUnexpected(clientError(200, '429'))).toBe(false) + }) + + test('returns false for a rate-limit code on a later error entry, not just the first', () => { + const error = new ClientError( + {status: 200, errors: [{message: 'noise'}, {extensions: {code: 'THROTTLED'}}], headers: {}} as any, + {query: 'q'} as any, + ) + expect(shouldReportErrorAsUnexpected(error)).toBe(false) + }) + + test('returns true for a raw ClientError that is a genuine failure (HTTP 500)', () => { + expect(shouldReportErrorAsUnexpected(clientError(500))).toBe(true) + }) }) diff --git a/packages/cli-kit/src/public/node/error.ts b/packages/cli-kit/src/public/node/error.ts index c2a7852c65c..9f84774cef9 100644 --- a/packages/cli-kit/src/public/node/error.ts +++ b/packages/cli-kit/src/public/node/error.ts @@ -1,8 +1,10 @@ import {normalizePath} from './path.js' import {OutputMessage, stringifyMessage, TokenizedString} from './output.js' import {InlineToken, TokenItem, tokenItemToString} from '../../private/node/ui/components/TokenizedText.js' +import {hasRateLimitCode} from '../../private/node/analytics/graphql-error-codes.js' import {Errors} from '@oclif/core' +import {ClientError} from 'graphql-request' import type {AlertCustomSection} from './ui.js' @@ -193,6 +195,12 @@ export function shouldReportErrorAsUnexpected(error: unknown): boolean { if (!isFatal(error)) { // this means its not one of the CLI wrapped errors if (error instanceof Error) { + // Raw API errors that slip through unwrapped (e.g. the handleErrors:false path) are expected + // environmental conditions, not CLI bugs. Treat them as expected so they don't pollute crash + // reporting. + if (isExpectedApiError(error)) { + return false + } const message = error.message return !errorMessageImpliesEnvironmentIssue(message) } @@ -204,6 +212,33 @@ export function shouldReportErrorAsUnexpected(error: unknown): boolean { return false } +/** + * Detects raw graphql-request `ClientError`s that are expected environmental conditions rather than + * CLI bugs. These reach the reporter as plain `Error`s (not `FatalError`s) and would otherwise be + * reported as unexpected. Two distinct cases, both kept out of crash reporting: + * + * HTTP 401 (unauthenticated) is not "transient" in the retry sense — it means the user's session + * token is expired or invalid, a credential/environment condition (see issue #7891). Rate limiting + * (HTTP 429, or a `THROTTLED`/`429` GraphQL code on any error in the response) matches the shape + * detected by `errorsIncludeStatus429` in `private/node/api.ts`. + * + * Scoped to the external `ClientError` type only — importing the cli-kit `GraphQLClientError` + * wrapper here would create an `error.ts → headers.ts → error.ts` import cycle. + * + * @param error - Error to be checked. + * @returns A boolean indicating if the error is a known expected API error. + */ +function isExpectedApiError(error: Error): boolean { + if (!(error instanceof ClientError)) { + return false + } + const status = error.response?.status + if (status === 401 || status === 429) { + return true + } + return hasRateLimitCode(error.response?.errors) +} + /** * Stack traces usually have file:// - we strip that and also remove the Windows drive designation. * diff --git a/packages/cli-kit/src/public/node/metadata.test.ts b/packages/cli-kit/src/public/node/metadata.test.ts index 6ec183a9fa7..a935fc7eec0 100644 --- a/packages/cli-kit/src/public/node/metadata.test.ts +++ b/packages/cli-kit/src/public/node/metadata.test.ts @@ -1,11 +1,24 @@ import {createRuntimeMetadataContainer} from './metadata.js' import * as errorHandler from './error-handler.js' -import {sleep} from './system.js' import {describe, expect, test, vi} from 'vitest' import {performance} from 'node:perf_hooks' vi.mock('./error-handler.js') +function mockPerformanceClock() { + let currentTime = 0 + const nowSpy = vi.spyOn(performance, 'now').mockImplementation(() => currentTime) + + return { + advanceBy(milliseconds: number) { + currentTime += milliseconds + }, + restore() { + nowSpy.mockRestore() + }, + } +} + describe('runtime metadata', () => { test('can manage data', async () => { const container = createRuntimeMetadataContainer< @@ -88,22 +101,31 @@ describe('runtime metadata', () => { */ const container = createRuntimeMetadataContainer<{a: number; b: number; c: number; d: number; e: number}, {}>() performance.clearMeasures() + const clock = mockPerformanceClock() - await container.runWithTimer('a')(async () => { - await sleep(0.01) - await container.runWithTimer('b')(async () => { - await sleep(0.01) - await container.runWithTimer('c')(async () => { - await sleep(0.01) - }) - await container.runWithTimer('d')(async () => { - await sleep(0.01) - await container.runWithTimer('e')(async () => { - await sleep(0.01) + try { + await container.runWithTimer('a')(async () => { + clock.advanceBy(10) + await container.runWithTimer('b')(async () => { + clock.advanceBy(10) + await container.runWithTimer('c')(async () => { + clock.advanceBy(10) + }) + clock.advanceBy(10) + await container.runWithTimer('d')(async () => { + clock.advanceBy(10) + await container.runWithTimer('e')(async () => { + clock.advanceBy(10) + }) + clock.advanceBy(10) }) + clock.advanceBy(10) }) + clock.advanceBy(10) }) - }) + } finally { + clock.restore() + } // eslint-disable-next-line id-length const {a, b, c, d, e} = container.getAllPublicMetadata() as any @@ -134,6 +156,7 @@ describe('runtime metadata', () => { test('can handle when a nested timer fails', async () => { const container = createRuntimeMetadataContainer<{a: number; b: number}, {}>() performance.clearMeasures() + const clock = mockPerformanceClock() let errorOccurred = false @@ -141,15 +164,17 @@ describe('runtime metadata', () => { // inside a timed section, we wouldn't want that to count as active time try { await container.runWithTimer('a')(async () => { - await sleep(0.01) + clock.advanceBy(10) await container.runWithTimer('b')(async () => { - await sleep(0.01) + clock.advanceBy(10) throw new Error('error inside a nested timed section') }) }) // eslint-disable-next-line no-catch-all/no-catch-all } catch { errorOccurred = true + } finally { + clock.restore() } expect(errorOccurred).toBe(true) diff --git a/packages/cli-kit/src/public/node/session.test.ts b/packages/cli-kit/src/public/node/session.test.ts index b54da575406..449992bb4b8 100644 --- a/packages/cli-kit/src/public/node/session.test.ts +++ b/packages/cli-kit/src/public/node/session.test.ts @@ -6,13 +6,21 @@ import { ensureAuthenticatedPartners, ensureAuthenticatedStorefront, ensureAuthenticatedThemes, + findSessionIdByAlias, + setCurrentSessionAlias, setLastSeenUserId, } from './session.js' import {nonRandomUUID} from './crypto.js' import {getAppAutomationToken} from './environment.js' import {shopifyFetch} from './http.js' -import {ensureAuthenticated, setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../../private/node/session.js' +import { + ensureAuthenticated, + setCommandSessionId, + setLastSeenAuthMethod, + setLastSeenUserIdAfterAuth, +} from '../../private/node/session.js' +import * as sessionStore from '../../private/node/session/store.js' import {ApplicationToken} from '../../private/node/session/schema.js' import { exchangeCustomPartnerToken, @@ -32,6 +40,7 @@ const partnersToken: ApplicationToken = { vi.mock('../../private/node/session.js') vi.mock('../../private/node/session/exchange.js') +vi.mock('../../private/node/session/store.js') vi.mock('./environment.js') vi.mock('./http.js') @@ -43,6 +52,50 @@ describe('store command analytics session helpers', () => { }) }) +describe('findSessionIdByAlias', () => { + test('returns the matching session ID without selecting it', async () => { + // Given + vi.mocked(sessionStore.findSessionByAlias).mockResolvedValueOnce('user-id') + + // When + const got = await findSessionIdByAlias('work') + + // Then + expect(got).toEqual('user-id') + expect(sessionStore.findSessionByAlias).toHaveBeenCalledWith('work') + }) +}) + +describe('setCurrentSessionAlias', () => { + test('selects a stored session by alias', async () => { + // Given + vi.mocked(sessionStore.findSessionByAlias).mockResolvedValueOnce('user-id') + + // When + await setCurrentSessionAlias('work') + + // Then + expect(sessionStore.findSessionByAlias).toHaveBeenCalledWith('work') + expect(setCommandSessionId).toHaveBeenCalledWith('user-id') + }) + + test('clears the selected session when no alias is provided', async () => { + // When + await setCurrentSessionAlias(undefined) + + // Then + expect(setCommandSessionId).toHaveBeenCalledWith(undefined) + }) + + test('throws when the alias is unknown', async () => { + // Given + vi.mocked(sessionStore.findSessionByAlias).mockResolvedValueOnce(undefined) + + // When/Then + await expect(setCurrentSessionAlias('missing')).rejects.toThrow('No authenticated account found for alias') + }) +}) + describe('ensureAuthenticatedStorefront', () => { test('returns only storefront token if success', async () => { // Given @@ -173,6 +226,23 @@ describe('ensureAuthenticatedTheme', () => { expect(setLastSeenUserIdAfterAuth).not.toBeCalled() }) + test('passes additional auth options through to the shared authenticator', async () => { + // Given + vi.mocked(ensureAuthenticated).mockResolvedValueOnce({ + admin: {token: 'admin_token', storeFqdn: 'mystore.myshopify.com'}, + userId: '1234-5678', + }) + + // When + const got = await ensureAuthenticatedThemes('mystore', undefined, [], {noPrompt: true}) + + // Then + expect(got).toEqual({token: 'admin_token', storeFqdn: 'mystore.myshopify.com'}) + expect(ensureAuthenticated).toHaveBeenCalledWith({adminApi: {scopes: [], storeFqdn: 'mystore'}}, process.env, { + noPrompt: true, + }) + }) + test('throws error if there is no token when no password is provided', async () => { // Given vi.mocked(ensureAuthenticated).mockResolvedValueOnce({userId: ''}) diff --git a/packages/cli-kit/src/public/node/session.ts b/packages/cli-kit/src/public/node/session.ts index 309804abf78..15be5d39cbf 100644 --- a/packages/cli-kit/src/public/node/session.ts +++ b/packages/cli-kit/src/public/node/session.ts @@ -17,6 +17,7 @@ import { PartnersAPIScope, StorefrontRendererScope, ensureAuthenticated, + setCommandSessionId, setLastSeenAuthMethod, setLastSeenUserIdAfterAuth, } from '../../private/node/session.js' @@ -51,6 +52,37 @@ export function setLastSeenUserId(userId: string): void { setLastSeenUserIdAfterAuth(userId) } +/** + * Finds a stored Shopify account session by alias without changing the current session. + * + * @param alias - The account alias to find. + * @returns The matching session ID, or undefined if no session matches. + */ +export async function findSessionIdByAlias(alias: string): Promise { + return sessionStore.findSessionByAlias(alias) +} + +/** + * Selects a stored Shopify account session by alias for the current command process. + * + * @param alias - The account alias to select. Passing undefined clears the command selection. + */ +export async function setCurrentSessionAlias(alias?: string): Promise { + if (!alias) { + setCommandSessionId(undefined) + return + } + + const sessionId = await findSessionIdByAlias(alias) + if (!sessionId) { + throw new AbortError( + outputContent`No authenticated account found for alias ${outputToken.yellow(alias)}.`, + outputContent`Run ${outputToken.genericShellCommand(`shopify auth login`)} first.`, + ) + } + setCommandSessionId(sessionId) +} + interface UserAccountInfo { type: 'UserAccount' email: string diff --git a/packages/cli-kit/src/public/node/themes/api.test.ts b/packages/cli-kit/src/public/node/themes/api.test.ts index 79f5954b6d4..c6da96b898a 100644 --- a/packages/cli-kit/src/public/node/themes/api.test.ts +++ b/packages/cli-kit/src/public/node/themes/api.test.ts @@ -354,6 +354,19 @@ describe('themeCreate', () => { preferredBehaviour: expectedApiOptions, }) }) + + test('throws a friendly error when access is denied by a missing theme write access scope', async () => { + vi.mocked(adminRequestDoc).mockRejectedValue( + themeAccessDeniedError( + 'The user needs write_themes and an exemption from Shopify to modify themes.', + 'themeCreate', + ), + ) + + await expect(themeCreate(params, session)).rejects.toThrow( + 'The authenticated account or access token is missing write_themes and an exemption from Shopify to modify themes.', + ) + }) }) describe('themeUpdate', () => { @@ -808,11 +821,11 @@ describe('parseThemeFileContent', () => { }) }) -function themeAccessDeniedError(requiredAccess?: string): ClientError { +function themeAccessDeniedError(requiredAccess?: string, field = 'themes'): ClientError { const extensions = requiredAccess ? {code: 'ACCESS_DENIED', requiredAccess} : {code: 'ACCESS_DENIED'} const message = requiredAccess - ? `Access denied for themes field. Required access: ${requiredAccess}` - : 'Access denied for themes field.' + ? `Access denied for ${field} field. Required access: ${requiredAccess}` + : `Access denied for ${field} field.` return new ClientError( { @@ -821,7 +834,7 @@ function themeAccessDeniedError(requiredAccess?: string): ClientError { { message, extensions, - path: ['themes'], + path: [field], } as any, ], }, diff --git a/packages/cli-kit/src/public/node/themes/api.ts b/packages/cli-kit/src/public/node/themes/api.ts index 5b91b7130bc..5bbd328b6aa 100644 --- a/packages/cli-kit/src/public/node/themes/api.ts +++ b/packages/cli-kit/src/public/node/themes/api.ts @@ -153,7 +153,7 @@ export async function findDevelopmentThemeByName(name: string, session: AdminSes export async function themeCreate(params: ThemeParams, session: AdminSession): Promise { const themeSource = params.src ?? SkeletonThemeCdn recordEvent('theme-api:create-theme') - const {themeCreate} = await adminRequestDoc({ + const {themeCreate} = await requestThemeAdminDoc({ query: ThemeCreate, session, variables: { @@ -684,7 +684,16 @@ function getThemeAccessRequirementForAccessDeniedError(error: ClientError): stri const requiredAccess = accessDeniedError.extensions?.requiredAccess if (typeof requiredAccess !== 'string') return DEFAULT_THEME_ACCESS_REQUIREMENT - return requiredAccess.trim().replace(/\.$/, '') || DEFAULT_THEME_ACCESS_REQUIREMENT + return formatThemeAccessRequirement(requiredAccess) +} + +function formatThemeAccessRequirement(requiredAccess: string): string { + const requirement = requiredAccess + .trim() + .replace(/\.$/, '') + .replace(/^The user needs\s+/i, '') + + return requirement || DEFAULT_THEME_ACCESS_REQUIREMENT } function themeGid(id: number): string { diff --git a/packages/cli/README.md b/packages/cli/README.md index 773806ae41c..60be6630998 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -80,12 +80,16 @@ * [`shopify plugins update`](#shopify-plugins-update) * [`shopify search [query]`](#shopify-search-query) * [`shopify store auth`](#shopify-store-auth) +* [`shopify store auth list`](#shopify-store-auth-list) * [`shopify store bulk cancel`](#shopify-store-bulk-cancel) * [`shopify store bulk execute`](#shopify-store-bulk-execute) * [`shopify store bulk status`](#shopify-store-bulk-status) +* [`shopify store create preview`](#shopify-store-create-preview) * [`shopify store execute`](#shopify-store-execute) * [`shopify store graphiql`](#shopify-store-graphiql) * [`shopify store info`](#shopify-store-info) +* [`shopify store list`](#shopify-store-list) +* [`shopify store open`](#shopify-store-open) * [`shopify theme check`](#shopify-theme-check) * [`shopify theme console`](#shopify-theme-console) * [`shopify theme delete`](#shopify-theme-delete) @@ -114,14 +118,18 @@ Build the app, including extensions. ``` USAGE - $ shopify app build [--client-id | -c ] [--no-color] [--path ] [--reset | ] - [--skip-dependencies-installation] [--verbose] + $ shopify app build [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [--skip-dependencies-installation] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -164,8 +172,8 @@ Cancel a bulk operation. ``` USAGE - $ shopify app bulk cancel --id [--client-id | -c ] [--no-color] [--path ] [--reset | - ] [-s ] [--verbose] + $ shopify app bulk cancel --id [--auth-alias ] [--client-id | -c ] [--no-color] + [--path ] [--reset | ] [-s ] [--verbose] FLAGS -c, --config= @@ -176,6 +184,10 @@ FLAGS The store domain. Must be an existing dev store. [env: SHOPIFY_FLAG_STORE] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -212,9 +224,9 @@ Execute bulk operations. ``` USAGE - $ shopify app bulk execute [--client-id | -c ] [--no-color] [--output-file --watch] [--path - ] [-q ] [--query-file ] [--reset | ] [-s ] [--variable-file | -v ...] - [--verbose] [--version ] + $ shopify app bulk execute [--auth-alias ] [--client-id | -c ] [--no-color] [--output-file + --watch] [--path ] [-q ] [--query-file ] [--reset | ] [-s ] [--variable-file + | -v ...] [--verbose] [--version ] FLAGS -c, --config= @@ -233,6 +245,10 @@ FLAGS The values for any GraphQL variables in your mutation, in JSON format. Can be specified multiple times. [env: SHOPIFY_FLAG_VARIABLES] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -295,8 +311,8 @@ Check the status of bulk operations. ``` USAGE - $ shopify app bulk status [--client-id | -c ] [--id ] [--no-color] [--path ] [--reset - | ] [-s ] [--verbose] + $ shopify app bulk status [--auth-alias ] [--client-id | -c ] [--id ] [--no-color] + [--path ] [--reset | ] [-s ] [--verbose] FLAGS -c, --config= @@ -307,6 +323,10 @@ FLAGS The store domain. Must be an existing dev store. [env: SHOPIFY_FLAG_STORE] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -351,17 +371,30 @@ Fetch your app configuration from the Developer Dashboard. ``` USAGE - $ shopify app config link [--client-id | -c ] [--no-color] [--path ] [--reset | ] [--verbose] + $ shopify app config link [--auth-alias ] [--client-id | -c ] [--force [--file-name | + ]] [--no-color] [--path ] [--reset | ] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] + --file-name= + The name of the app configuration file to create or overwrite. + [env: SHOPIFY_FLAG_APP_CONFIG_FILE_NAME] + + --force + Overwrite an existing configuration file without prompting. + [env: SHOPIFY_FLAG_FORCE] + --no-color Disable color output. [env: SHOPIFY_FLAG_NO_COLOR] @@ -394,13 +427,18 @@ Refresh an already-linked app configuration without prompts. ``` USAGE - $ shopify app config pull [--client-id | -c ] [--no-color] [--path ] [--reset | ] [--verbose] + $ shopify app config pull [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -442,6 +480,10 @@ ARGUMENTS [CONFIG] The name of the app configuration. Can be 'shopify.app.staging.toml' or simply 'staging'. FLAGS + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -475,8 +517,8 @@ Validate your app configuration and extensions. ``` USAGE - $ shopify app config validate [--client-id | -c ] [-j] [--no-color] [--path ] [--reset | ] - [--verbose] + $ shopify app config validate [--auth-alias ] [--client-id | -c ] [-j] [--no-color] [--path + ] [--reset | ] [--verbose] FLAGS -c, --config= @@ -487,6 +529,10 @@ FLAGS Output the result as JSON. Automatically disables color output. [env: SHOPIFY_FLAG_JSON] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -520,9 +566,9 @@ Deploy your Shopify app. ``` USAGE - $ shopify app deploy [--client-id | -c ] [--message ] [--no-build] [--no-color] - [--no-release | --allow-updates | --allow-deletes] [--path ] [--reset | ] [--source-control-url ] - [--verbose] [--version ] + $ shopify app deploy [--auth-alias ] [--client-id | -c ] [--message ] + [--no-build] [--no-color] [--no-release | --allow-updates | --allow-deletes] [--path ] [--reset | ] + [--source-control-url ] [--verbose] [--version ] FLAGS -c, --config= @@ -539,6 +585,10 @@ FLAGS CI/CD environments. [env: SHOPIFY_FLAG_ALLOW_UPDATES] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -602,8 +652,8 @@ Run the app. ``` USAGE - $ shopify app dev [--checkout-cart-url ] [--client-id | -c ] [--localhost-port - ] [--no-color] [--no-update] [--notify ] [--path ] [--reset | ] + $ shopify app dev [--auth-alias ] [--checkout-cart-url ] [--client-id | -c ] + [--localhost-port ] [--no-color] [--no-update] [--notify ] [--path ] [--reset | ] [--skip-dependencies-installation] [-s ] [--subscription-product-url ] [-t ] [--theme-app-extension-port ] [--use-localhost | [--tunnel-url | ]] [--verbose] @@ -620,6 +670,10 @@ FLAGS Theme ID or name of the theme app extension host theme. [env: SHOPIFY_FLAG_THEME] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --checkout-cart-url= Resource URL for checkout UI extension. Format: "/cart/{productVariantID}:{productQuantity}" [env: SHOPIFY_FLAG_CHECKOUT_CART_URL] @@ -691,8 +745,8 @@ Cleans up the dev preview from the selected store. ``` USAGE - $ shopify app dev clean [--client-id | -c ] [--no-color] [--path ] [--reset | ] [-s - ] [--verbose] + $ shopify app dev clean [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [-s ] [--verbose] FLAGS -c, --config= @@ -703,6 +757,10 @@ FLAGS Store URL. Must be an existing development store. [env: SHOPIFY_FLAG_STORE] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -737,14 +795,18 @@ Pull app and extensions environment variables. ``` USAGE - $ shopify app env pull [--client-id | -c ] [--env-file ] [--no-color] [--path ] - [--reset | ] [--verbose] + $ shopify app env pull [--auth-alias ] [--client-id | -c ] [--env-file ] + [--no-color] [--path ] [--reset | ] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -784,13 +846,18 @@ Display app and extensions environment variables. ``` USAGE - $ shopify app env show [--client-id | -c ] [--no-color] [--path ] [--reset | ] [--verbose] + $ shopify app env show [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -823,9 +890,9 @@ Execute GraphQL queries and mutations. ``` USAGE - $ shopify app execute [--client-id | -c ] [--no-color] [--output-file ] [--path ] - [-q ] [--query-file ] [--reset | ] [-s ] [--variable-file | -v ] [--verbose] - [--version ] + $ shopify app execute [--auth-alias ] [--client-id | -c ] [--no-color] [--output-file + ] [--path ] [-q ] [--query-file ] [--reset | ] [-s ] [--variable-file | + -v ] [--verbose] [--version ] FLAGS -c, --config= @@ -845,6 +912,10 @@ FLAGS The values for any GraphQL variables in your query or mutation, in JSON format. [env: SHOPIFY_FLAG_VARIABLES] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -896,13 +967,18 @@ Compile a function to wasm. ``` USAGE - $ shopify app function build [--client-id | -c ] [--no-color] [--path ] [--reset | ] [--verbose] + $ shopify app function build [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -935,8 +1011,8 @@ Print basic information about your function. ``` USAGE - $ shopify app function info [--client-id | -c ] [-j] [--no-color] [--path ] [--reset | ] - [--verbose] + $ shopify app function info [--auth-alias ] [--client-id | -c ] [-j] [--no-color] [--path + ] [--reset | ] [--verbose] FLAGS -c, --config= @@ -947,6 +1023,10 @@ FLAGS Output the result as JSON. Automatically disables color output. [env: SHOPIFY_FLAG_JSON] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -987,8 +1067,8 @@ Replays a function run from an app log. ``` USAGE - $ shopify app function replay [--client-id | -c ] [-j] [-l ] [--no-color] [--path ] - [--reset | ] [--verbose] [-w] + $ shopify app function replay [--auth-alias ] [--client-id | -c ] [-j] [-l ] [--no-color] + [--path ] [--reset | ] [--verbose] [-w] FLAGS -c, --config= @@ -1008,6 +1088,10 @@ FLAGS Re-run the function when the source code changes. [env: SHOPIFY_FLAG_WATCH] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1042,8 +1126,8 @@ Run a function locally for testing. ``` USAGE - $ shopify app function run [--client-id | -c ] [-e ] [-i ] [-j] [--no-color] [--path - ] [--reset | ] [--verbose] + $ shopify app function run [--auth-alias ] [--client-id | -c ] [-e ] [-i ] [-j] + [--no-color] [--path ] [--reset | ] [--verbose] FLAGS -c, --config= @@ -1062,6 +1146,10 @@ FLAGS Output the result as JSON. Automatically disables color output. [env: SHOPIFY_FLAG_JSON] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1096,14 +1184,18 @@ Fetch the latest GraphQL schema for a function. ``` USAGE - $ shopify app function schema [--client-id | -c ] [--no-color] [--path ] [--reset | ] [--stdout] - [--verbose] + $ shopify app function schema [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [--stdout] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1144,14 +1236,18 @@ Generate GraphQL types for a function. ``` USAGE - $ shopify app function typegen [--client-id | -c ] [--no-color] [--path ] [--reset | ] - [--verbose] + $ shopify app function typegen [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1185,7 +1281,7 @@ Generate a new app Extension. ``` USAGE - $ shopify app generate extension [--client-id | -c ] [--flavor + $ shopify app generate extension [--auth-alias ] [--client-id | -c ] [--flavor vanilla-js|react|typescript|typescript-react|wasm|rust] [-n ] [--no-color] [--path ] [--reset | ] [-t ] [--verbose] @@ -1202,6 +1298,10 @@ FLAGS Extension template [env: SHOPIFY_FLAG_EXTENSION_TEMPLATE] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1245,8 +1345,8 @@ Open a local GraphiQL UI for your app and store. ``` USAGE - $ shopify app graphiql [--client-id | -c ] [--no-color] [--path ] [--port ] - [--reset | ] [-s ] [-v ] [--verbose] [--version ] + $ shopify app graphiql [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--port ] [--reset | ] [-s ] [-v ] [--verbose] [--version ] FLAGS -c, --config= @@ -1262,6 +1362,10 @@ FLAGS The values for any GraphQL variables in your query or mutation, in JSON format. [env: SHOPIFY_FLAG_VARIABLES] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1309,8 +1413,8 @@ Import metafield and metaobject definitions. ``` USAGE - $ shopify app import-custom-data-definitions [--client-id | -c ] [--include-existing] [--no-color] [--path ] - [--reset | ] [-s ] [--verbose] + $ shopify app import-custom-data-definitions [--auth-alias ] [--client-id | -c ] [--include-existing] + [--no-color] [--path ] [--reset | ] [-s ] [--verbose] FLAGS -c, --config= @@ -1321,6 +1425,10 @@ FLAGS Store URL. Must be an existing development or Shopify Plus sandbox store. [env: SHOPIFY_FLAG_STORE] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1358,14 +1466,18 @@ Import dashboard-managed extensions into your app. ``` USAGE - $ shopify app import-extensions [--client-id | -c ] [--no-color] [--path ] [--reset | ] - [--verbose] + $ shopify app import-extensions [--auth-alias ] [--client-id | -c ] [--no-color] [--path ] + [--reset | ] [--verbose] FLAGS -c, --config= The name of the app configuration. [env: SHOPIFY_FLAG_APP_CONFIG] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1396,8 +1508,8 @@ Print basic information about your app and extensions. ``` USAGE - $ shopify app info [--client-id | -c ] [-j] [--no-color] [--path ] [--reset | ] - [--verbose] [--web-env] + $ shopify app info [--auth-alias ] [--client-id | -c ] [-j] [--no-color] [--path + ] [--reset | ] [--verbose] [--web-env] FLAGS -c, --config= @@ -1408,6 +1520,10 @@ FLAGS Output the result as JSON. Automatically disables color output. [env: SHOPIFY_FLAG_JSON] + --auth-alias= + Alias of the Shopify account to use for authentication. + [env: SHOPIFY_FLAG_AUTH_ALIAS] + --client-id= The Client ID of your app. [env: SHOPIFY_FLAG_CLIENT_ID] @@ -1451,8 +1567,8 @@ Create a new app project ``` USAGE - $ shopify app init [--flavor ] [-n ] [--no-color] [--organization-id | [--client-id - | ]] [-d npm|yarn|pnpm|bun] [-p ] [--template ] [--verbose] + $ shopify app init [--auth-alias ] [--flavor ] [-n ] [--no-color] [--organization-id + | [--client-id | ]] [-d npm|yarn|pnpm|bun] [-p ] [--template ] [--verbose] FLAGS -d, --package-manager=