diff --git a/packages/app/src/cli/constants.ts b/packages/app/src/cli/constants.ts index 36afe8a097..1f9a91d131 100644 --- a/packages/app/src/cli/constants.ts +++ b/packages/app/src/cli/constants.ts @@ -3,6 +3,7 @@ export const environmentVariableNames = { disableGraphiQLExplorer: 'SHOPIFY_CLI_DISABLE_GRAPHIQL', useDynamicConfigSpecifications: 'SHOPIFY_CLI_DYNAMIC_CONFIG', enableAppLogPolling: 'SHOPIFY_CLI_ENABLE_APP_LOG_POLLING', + templatesJsonPath: 'SHOPIFY_CLI_APP_TEMPLATES_JSON_PATH', } export const configurationFileNames = { 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 a4c0d52fa5..d3d782ba30 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 @@ -4,6 +4,7 @@ import { OrganizationBetaFlagsQueryVariables, organizationBetaFlagsQuery, } from './app-management-client/graphql/organization_beta_flags.js' +import {environmentVariableNames} from '../../constants.js' import {RemoteSpecification} from '../../api/graphql/extension_specifications.js' import { DeveloperPlatformClient, @@ -133,6 +134,7 @@ import {outputDebug} from '@shopify/cli-kit/node/output' import {developerDashboardFqdn} from '@shopify/cli-kit/node/context/fqdn' import {webhooksRequest} from '@shopify/cli-kit/node/api/webhooks' import {functionsRequestDoc} from '@shopify/cli-kit/node/api/functions' +import {fileExists, readFile} from '@shopify/cli-kit/node/fs' const TEMPLATE_JSON_URL = 'https://cdn.shopify.com/static/cli/extensions/templates.json' @@ -325,24 +327,27 @@ export class AppManagementClient implements DeveloperPlatformClient { } async templateSpecifications({organizationId}: MinimalAppIdentifiers): Promise { - let response let templates: GatedExtensionTemplate[] - try { - response = await fetch(TEMPLATE_JSON_URL) - templates = await (response.json() as Promise) - } catch (_e) { - throw new AbortError( - [ + const {templatesJsonPath} = environmentVariableNames + const overrideFile = process.env[templatesJsonPath] + if (overrideFile) { + if (!(await fileExists(overrideFile))) { + throw new AbortError('There is no file at the path specified for template specifications') + } + const templatesJson = await readFile(overrideFile) + templates = JSON.parse(templatesJson) + } else { + try { + const response = await fetch(TEMPLATE_JSON_URL) + templates = await (response.json() as Promise) + } catch (_e) { + throw new AbortError([ 'Failed to fetch extension templates from', {link: {url: TEMPLATE_JSON_URL}}, {char: '.'}, 'This likely means a problem with your internet connection.', - ], - [ - {link: {url: 'https://www.githubstatus.com', label: 'Check if GitHub is experiencing downtime'}}, - 'or try again later.', - ], - ) + ]) + } } // Fake the sortPriority as ascending, since the templates are already sorted // in the static JSON file. This can be removed once PartnersClient, which