@shopify/cli-kit 4.9.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.d.ts +5 -0
- package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.js +22 -0
- package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.js.map +1 -1
- package/dist/private/node/api/graphql.d.ts +2 -1
- package/dist/private/node/api/graphql.js +12 -1
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api.d.ts +2 -0
- package/dist/private/node/api.js +49 -22
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/command-json-schema.js +1 -0
- package/dist/private/node/command-json-schema.js.map +1 -1
- package/dist/private/node/constants.d.ts +1 -0
- package/dist/private/node/constants.js +1 -0
- package/dist/private/node/constants.js.map +1 -1
- package/dist/private/node/dev-instance-output.d.ts +47 -0
- package/dist/private/node/dev-instance-output.js +143 -0
- package/dist/private/node/dev-instance-output.js.map +1 -0
- package/dist/private/node/json-error.d.ts +1 -15
- package/dist/private/node/json-error.js +4 -98
- package/dist/private/node/json-error.js.map +1 -1
- package/dist/private/node/output-context.d.ts +8 -0
- package/dist/private/node/output-context.js +10 -0
- package/dist/private/node/output-context.js.map +1 -0
- package/dist/private/node/output.test.js +4 -4
- package/dist/private/node/output.test.js.map +1 -1
- package/dist/private/node/session/automation-token.d.ts +50 -0
- package/dist/private/node/session/automation-token.js +77 -0
- package/dist/private/node/session/automation-token.js.map +1 -0
- package/dist/private/node/session/exchange.d.ts +2 -1
- package/dist/private/node/session/exchange.js +5 -3
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/session/permanent-store-domain.d.ts +21 -0
- package/dist/private/node/session/permanent-store-domain.js +72 -0
- package/dist/private/node/session/permanent-store-domain.js.map +1 -0
- package/dist/private/node/session.d.ts +3 -2
- package/dist/private/node/session.js +12 -3
- package/dist/private/node/session.js.map +1 -1
- package/dist/private/node/themes/trust-challenge.d.ts +31 -0
- package/dist/private/node/themes/trust-challenge.js +143 -0
- package/dist/private/node/themes/trust-challenge.js.map +1 -0
- package/dist/private/node/ui/alert.js +1 -1
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +2 -7
- package/dist/private/node/ui/components/ConcurrentOutput.js +4 -8
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.js +9 -15
- package/dist/private/node/ui/components/LoadingBar.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.test.js +45 -107
- package/dist/private/node/ui/components/LoadingBar.test.js.map +1 -1
- package/dist/private/node/ui/components/LoadingIndicator.d.ts +7 -0
- package/dist/private/node/ui/components/LoadingIndicator.js +22 -0
- package/dist/private/node/ui/components/LoadingIndicator.js.map +1 -0
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/api/admin.js +13 -0
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/graphql.js +38 -7
- package/dist/public/node/api/graphql.js.map +1 -1
- package/dist/public/node/archiver.js +13 -6
- package/dist/public/node/archiver.js.map +1 -1
- package/dist/public/node/base-command.d.ts +6 -0
- package/dist/public/node/base-command.js +97 -16
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/dev-instance.d.ts +138 -0
- package/dist/public/node/dev-instance.js +365 -0
- package/dist/public/node/dev-instance.js.map +1 -0
- package/dist/public/node/environment.d.ts +6 -3
- package/dist/public/node/environment.js +11 -4
- package/dist/public/node/environment.js.map +1 -1
- package/dist/public/node/error/index.js +2 -1
- package/dist/public/node/error/index.js.map +1 -1
- package/dist/public/node/error/schema.d.ts +24 -24
- package/dist/public/node/error/serialization.d.ts +8 -0
- package/dist/public/node/error/serialization.js +103 -0
- package/dist/public/node/error/serialization.js.map +1 -0
- package/dist/public/node/graphiql/server.js +18 -2
- package/dist/public/node/graphiql/server.js.map +1 -1
- package/dist/public/node/is-global.js +2 -1
- package/dist/public/node/is-global.js.map +1 -1
- package/dist/public/node/notifications-system.d.ts +6 -6
- package/dist/public/node/path.d.ts +19 -3
- package/dist/public/node/path.js +21 -3
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/session.d.ts +36 -2
- package/dist/public/node/session.js +48 -4
- package/dist/public/node/session.js.map +1 -1
- package/dist/public/node/system.d.ts +4 -0
- package/dist/public/node/system.js +39 -9
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/themes/api.d.ts +9 -0
- package/dist/public/node/themes/api.js +50 -22
- package/dist/public/node/themes/api.js.map +1 -1
- package/dist/public/node/themes/theme-manager.d.ts +8 -1
- package/dist/public/node/themes/theme-manager.js +1 -1
- package/dist/public/node/themes/theme-manager.js.map +1 -1
- package/dist/public/node/tree-kill.js +12 -2
- package/dist/public/node/tree-kill.js.map +1 -1
- package/dist/public/node/ui/components.d.ts +1 -0
- package/dist/public/node/ui/components.js +1 -0
- package/dist/public/node/ui/components.js.map +1 -1
- package/dist/public/node/ui.d.ts +24 -4
- package/dist/public/node/ui.js +41 -18
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/upgrade/output.d.ts +17 -0
- package/dist/public/node/upgrade/output.js +51 -0
- package/dist/public/node/upgrade/output.js.map +1 -0
- package/dist/public/node/upgrade/result.d.ts +8 -0
- package/dist/public/node/upgrade/result.js +21 -0
- package/dist/public/node/upgrade/result.js.map +1 -0
- package/dist/public/node/upgrade/types.d.ts +61 -0
- package/dist/public/node/upgrade/types.js +46 -0
- package/dist/public/node/upgrade/types.js.map +1 -0
- package/dist/public/node/upgrade.d.ts +8 -0
- package/dist/public/node/upgrade.js +57 -22
- package/dist/public/node/upgrade.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/private/node/ui/components/TextAnimation.d.ts +0 -10
- package/dist/private/node/ui/components/TextAnimation.js +0 -56
- package/dist/private/node/ui/components/TextAnimation.js.map +0 -1
- package/dist/private/node/ui/components/TextAnimation.test.d.ts +0 -1
- package/dist/private/node/ui/components/TextAnimation.test.js +0 -73
- package/dist/private/node/ui/components/TextAnimation.test.js.map +0 -1
|
@@ -4,9 +4,12 @@ import { getAppAutomationToken } from './environment.js';
|
|
|
4
4
|
import { AbortError, BugError } from './error.js';
|
|
5
5
|
import { outputContent, outputToken, outputDebug } from './output.js';
|
|
6
6
|
import * as sessionStore from '../../private/node/session/store.js';
|
|
7
|
+
import { automationTokenVariable } from '../../private/node/session/automation-token.js';
|
|
8
|
+
import { environmentVariables } from '../../private/node/constants.js';
|
|
7
9
|
import { exchangeCustomPartnerToken, exchangeAppAutomationTokenForAppManagementAccessToken, exchangeAppAutomationTokenForBusinessPlatformAccessToken, } from '../../private/node/session/exchange.js';
|
|
8
10
|
import { ensureAuthenticated, setCommandSessionId, setLastSeenAuthMethod, setLastSeenUserIdAfterAuth, } from '../../private/node/session.js';
|
|
9
11
|
import { isThemeAccessSession } from '../../private/node/api/rest.js';
|
|
12
|
+
import { resolvePermanentStoreFqdn } from '../../private/node/session/permanent-store-domain.js';
|
|
10
13
|
/**
|
|
11
14
|
* Records the user ID that should be attached to command analytics for this process.
|
|
12
15
|
*
|
|
@@ -178,6 +181,10 @@ ${outputToken.json(scopes)}
|
|
|
178
181
|
* If a password is provided, that token will be used against Theme Access API.
|
|
179
182
|
* Otherwise, it will ensure that the user is authenticated with the Admin API.
|
|
180
183
|
*
|
|
184
|
+
* Theme Access passwords only work with the store's permanent `.myshopify.com` domain, so when the password is a
|
|
185
|
+
* Theme Access password the returned session uses the permanent domain of `store`, even if `store` is another of the
|
|
186
|
+
* store's domains.
|
|
187
|
+
*
|
|
181
188
|
* @param store - Store fqdn to request auth for.
|
|
182
189
|
* @param password - Password generated from Theme Access app.
|
|
183
190
|
* @param scopes - Optional array of extra scopes to authenticate with.
|
|
@@ -190,9 +197,11 @@ ${outputToken.json(scopes)}
|
|
|
190
197
|
`);
|
|
191
198
|
if (password) {
|
|
192
199
|
const session = { token: password, storeFqdn: store };
|
|
193
|
-
const
|
|
194
|
-
setLastSeenAuthMethod(
|
|
200
|
+
const themeAccess = isThemeAccessSession(session);
|
|
201
|
+
setLastSeenAuthMethod(themeAccess ? 'theme_access_token' : 'custom_app_token');
|
|
195
202
|
setLastSeenUserIdAfterAuth(nonRandomUUID(password));
|
|
203
|
+
if (themeAccess)
|
|
204
|
+
session.storeFqdn = await resolvePermanentStoreFqdn(store);
|
|
196
205
|
return session;
|
|
197
206
|
}
|
|
198
207
|
return ensureAuthenticatedAdmin(store, scopes, options);
|
|
@@ -200,7 +209,7 @@ ${outputToken.json(scopes)}
|
|
|
200
209
|
/**
|
|
201
210
|
* Ensure that we have a valid session to access the Business Platform API.
|
|
202
211
|
*
|
|
203
|
-
* @param scopes - Optional array of extra scopes to authenticate with.
|
|
212
|
+
* @param scopes - Optional array of extra scopes to authenticate with. Ignored when an automation token is used.
|
|
204
213
|
* @param options - Optional extra options to use.
|
|
205
214
|
* @returns The access token for the Business Platform API.
|
|
206
215
|
*/
|
|
@@ -208,12 +217,47 @@ export async function ensureAuthenticatedBusinessPlatform(scopes = [], options =
|
|
|
208
217
|
outputDebug(outputContent `Ensuring that the user is authenticated with the Business Platform API with the following scopes:
|
|
209
218
|
${outputToken.json(scopes)}
|
|
210
219
|
`);
|
|
211
|
-
const
|
|
220
|
+
const { allowAutomationToken = false, ...authenticationOptions } = options;
|
|
221
|
+
const automationToken = allowAutomationToken ? getAppAutomationToken() : undefined;
|
|
222
|
+
if (automationToken) {
|
|
223
|
+
// Request no explicit scopes, so Identity issues every Business Platform scope the token holds. The organizations
|
|
224
|
+
// API admits a CLI token only with a scope such as organization.store-management, and naming that scope would
|
|
225
|
+
// fail the exchange for app and Partner tokens, which don't hold it.
|
|
226
|
+
const result = await exchangeAppAutomationTokenForBusinessPlatformAccessToken(automationToken, []);
|
|
227
|
+
return result.accessToken;
|
|
228
|
+
}
|
|
229
|
+
const tokens = await ensureAuthenticated({ businessPlatformApi: { scopes } }, process.env, authenticationOptions);
|
|
212
230
|
if (!tokens.businessPlatform) {
|
|
213
231
|
throw new BugError('No business-platform token found after ensuring authenticated');
|
|
214
232
|
}
|
|
215
233
|
return tokens.businessPlatform;
|
|
216
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Whether SHOPIFY_SERVICE_ACCOUNT_TOKEN is set, which makes it the automation token the CLI authenticates with.
|
|
237
|
+
*
|
|
238
|
+
* True even when it's empty or set together with another automation token variable. Commands use this to skip logins
|
|
239
|
+
* saved on this machine, and authentication then reports any problem with the variables.
|
|
240
|
+
*
|
|
241
|
+
* @returns True when SHOPIFY_SERVICE_ACCOUNT_TOKEN is set.
|
|
242
|
+
*/
|
|
243
|
+
export function isServiceAccountTokenSet() {
|
|
244
|
+
return automationTokenVariable() === environmentVariables.serviceAccountToken;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Fails when SHOPIFY_SERVICE_ACCOUNT_TOKEN is set, for commands that can't run with that token.
|
|
248
|
+
*
|
|
249
|
+
* Service account tokens can't log in as a user or call a store's Admin API, so commands that need either
|
|
250
|
+
* refuse to run instead of quietly using the person's own login. `ensureAuthenticated` runs this check before any
|
|
251
|
+
* login. Commands that run on a login saved by `shopify store auth` call it before loading that login.
|
|
252
|
+
*
|
|
253
|
+
* @throws AbortError when SHOPIFY_SERVICE_ACCOUNT_TOKEN is set.
|
|
254
|
+
*/
|
|
255
|
+
export function ensureNoServiceAccountToken() {
|
|
256
|
+
if (!isServiceAccountTokenSet())
|
|
257
|
+
return;
|
|
258
|
+
const variable = environmentVariables.serviceAccountToken;
|
|
259
|
+
throw new AbortError(`This command can't use ${variable}.`, `Unset ${variable} to run it with your Shopify account.`);
|
|
260
|
+
}
|
|
217
261
|
/**
|
|
218
262
|
* Logout from Shopify.
|
|
219
263
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/public/node/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {shopifyFetch} from './http.js'\nimport {nonRandomUUID} from './crypto.js'\nimport {getAppAutomationToken} from './environment.js'\nimport {AbortError, BugError} from './error.js'\nimport {outputContent, outputToken, outputDebug} from './output.js'\nimport * as sessionStore from '../../private/node/session/store.js'\nimport {\n exchangeCustomPartnerToken,\n exchangeAppAutomationTokenForAppManagementAccessToken,\n exchangeAppAutomationTokenForBusinessPlatformAccessToken,\n} from '../../private/node/session/exchange.js'\nimport {\n AdminAPIScope,\n AppManagementAPIScope,\n BusinessPlatformScope,\n EnsureAuthenticatedAdditionalOptions,\n PartnersAPIScope,\n StorefrontRendererScope,\n ensureAuthenticated,\n setCommandSessionId,\n setLastSeenAuthMethod,\n setLastSeenUserIdAfterAuth,\n} from '../../private/node/session.js'\nimport {isThemeAccessSession} from '../../private/node/api/rest.js'\n\n/**\n * Session Object to access the Admin API, includes the token and the store FQDN.\n */\nexport interface AdminSession {\n token: string\n storeFqdn: string\n}\n\n/**\n * Session Object for Partners API and App Management API access.\n */\nexport interface Session {\n token: string\n businessPlatformToken: string\n accountInfo: AccountInfo\n userId: string\n}\n\nexport type AccountInfo = UserAccountInfo | ServiceAccountInfo | UnknownAccountInfo\n\n/**\n * Records the user ID that should be attached to command analytics for this process.\n *\n * @param userId - User identifier to report on the command analytics event.\n */\nexport function setLastSeenUserId(userId: string): void {\n setLastSeenUserIdAfterAuth(userId)\n}\n\n/**\n * Finds a stored Shopify account session by alias without changing the current session.\n *\n * @param alias - The account alias to find.\n * @returns The matching session ID, or undefined if no session matches.\n */\nexport async function findSessionIdByAlias(alias: string): Promise<string | undefined> {\n return sessionStore.findSessionByAlias(alias)\n}\n\n/**\n * Selects a stored Shopify account session by alias for the current command process.\n *\n * @param alias - The account alias to select. Passing undefined clears the command selection.\n */\nexport async function setCurrentSessionAlias(alias?: string): Promise<void> {\n if (!alias) {\n setCommandSessionId(undefined)\n return\n }\n\n const sessionId = await findSessionIdByAlias(alias)\n if (!sessionId) {\n throw new AbortError(\n outputContent`No authenticated account found for alias ${outputToken.yellow(alias)}.`,\n outputContent`Run ${outputToken.genericShellCommand(`shopify auth login`)} first.`,\n )\n }\n setCommandSessionId(sessionId)\n}\n\ninterface UserAccountInfo {\n type: 'UserAccount'\n email: string\n}\n\ninterface ServiceAccountInfo {\n type: 'ServiceAccount'\n orgName: string\n}\n\ninterface UnknownAccountInfo {\n type: 'UnknownAccount'\n}\n\n/**\n * Type guard to check if an account is a UserAccount.\n *\n * @param account - The account to check.\n * @returns True if the account is a UserAccount.\n */\nexport function isUserAccount(account: AccountInfo): account is UserAccountInfo {\n return account.type === 'UserAccount'\n}\n\n/**\n * Type guard to check if an account is a ServiceAccount.\n *\n * @param account - The account to check.\n * @returns True if the account is a ServiceAccount.\n */\nexport function isServiceAccount(account: AccountInfo): account is ServiceAccountInfo {\n return account.type === 'ServiceAccount'\n}\n\n/**\n * Ensure that we have a valid session with no particular scopes.\n *\n * @param env - Optional environment variables to use.\n * @param options - Optional extra options to use.\n * @returns The user ID.\n */\nexport async function ensureAuthenticatedUser(\n env = process.env,\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<{userId: string}> {\n outputDebug(outputContent`Ensuring that the user is authenticated with no particular scopes`)\n const tokens = await ensureAuthenticated({}, env, options)\n return {userId: tokens.userId}\n}\n\n/**\n * Ensure that we have a valid session to access the Partners API.\n * If SHOPIFY_CLI_PARTNERS_TOKEN exists, that token will be used to obtain a valid Partners Token\n * If SHOPIFY_CLI_PARTNERS_TOKEN exists, scopes will be ignored.\n *\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param env - Optional environment variables to use.\n * @param options - Optional extra options to use.\n * @returns The access token for the Partners API.\n */\nexport async function ensureAuthenticatedPartners(\n scopes: PartnersAPIScope[] = [],\n env = process.env,\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<{token: string; userId: string}> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Partners API with the following scopes:\n${outputToken.json(scopes)}\n`)\n const envToken = getAppAutomationToken()\n if (envToken) {\n const result = await exchangeCustomPartnerToken(envToken)\n return {token: result.accessToken, userId: result.userId}\n }\n const tokens = await ensureAuthenticated({partnersApi: {scopes}}, env, options)\n if (!tokens.partners) {\n throw new BugError('No partners token found after ensuring authenticated')\n }\n return {token: tokens.partners, userId: tokens.userId}\n}\n\n/**\n * Ensure that we have a valid session to access the App Management API.\n *\n * @param options - Optional extra options to use.\n * @param appManagementScopes - Optional array of extra scopes to authenticate with.\n * @param businessPlatformScopes - Optional array of extra scopes to authenticate with.\n * @param env - Optional environment variables to use.\n * @returns The access token for the App Management API.\n */\nexport async function ensureAuthenticatedAppManagementAndBusinessPlatform(\n options: EnsureAuthenticatedAdditionalOptions = {},\n appManagementScopes: AppManagementAPIScope[] = [],\n businessPlatformScopes: BusinessPlatformScope[] = [],\n env = process.env,\n): Promise<{appManagementToken: string; userId: string; businessPlatformToken: string}> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the App Management API with the following scopes:\n${outputToken.json(appManagementScopes)}\n`)\n\n const envToken = getAppAutomationToken()\n if (envToken) {\n const appManagmentToken = await exchangeAppAutomationTokenForAppManagementAccessToken(envToken)\n const businessPlatformToken = await exchangeAppAutomationTokenForBusinessPlatformAccessToken(envToken)\n\n return {\n appManagementToken: appManagmentToken.accessToken,\n userId: appManagmentToken.userId,\n businessPlatformToken: businessPlatformToken.accessToken,\n }\n }\n\n const tokens = await ensureAuthenticated(\n {appManagementApi: {scopes: appManagementScopes}, businessPlatformApi: {scopes: businessPlatformScopes}},\n env,\n options,\n )\n if (!tokens.appManagement || !tokens.businessPlatform) {\n throw new BugError('No App Management or Business Platform token found after ensuring authenticated')\n }\n\n return {\n appManagementToken: tokens.appManagement,\n userId: tokens.userId,\n businessPlatformToken: tokens.businessPlatform,\n }\n}\n\n/**\n * Ensure that we have a valid session to access the Storefront API.\n *\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param password - Optional password to use.\n * @param options - Optional extra options to use.\n * @returns The access token for the Storefront API.\n */\nexport async function ensureAuthenticatedStorefront(\n scopes: StorefrontRendererScope[] = [],\n password: string | undefined = undefined,\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<string> {\n if (password) {\n const session = {token: password, storeFqdn: ''}\n const authMethod = isThemeAccessSession(session) ? 'theme_access_token' : 'custom_app_token'\n setLastSeenAuthMethod(authMethod)\n setLastSeenUserIdAfterAuth(nonRandomUUID(password))\n return password\n }\n\n outputDebug(outputContent`Ensuring that the user is authenticated with the Storefront API with the following scopes:\n${outputToken.json(scopes)}\n`)\n const tokens = await ensureAuthenticated({storefrontRendererApi: {scopes}}, process.env, options)\n if (!tokens.storefront) {\n throw new BugError('No storefront token found after ensuring authenticated')\n }\n return tokens.storefront\n}\n\n/**\n * Ensure that we have a valid Admin session for the given store.\n *\n * @param store - Store fqdn to request auth for.\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param options - Optional extra options to use.\n * @returns The access token for the Admin API.\n */\nexport async function ensureAuthenticatedAdmin(\n store: string,\n scopes: AdminAPIScope[] = [],\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<AdminSession> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Admin API with the following scopes for the store ${outputToken.raw(\n store,\n )}:\n${outputToken.json(scopes)}\n`)\n const tokens = await ensureAuthenticated({adminApi: {scopes, storeFqdn: store}}, process.env, {\n ...options,\n })\n if (!tokens.admin) {\n throw new BugError('No admin token found after ensuring authenticated')\n }\n return tokens.admin\n}\n\n/**\n * Ensure that we have a valid session to access the Theme API.\n * If a password is provided, that token will be used against Theme Access API.\n * Otherwise, it will ensure that the user is authenticated with the Admin API.\n *\n * @param store - Store fqdn to request auth for.\n * @param password - Password generated from Theme Access app.\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param options - Optional extra options to use.\n * @returns The access token and store.\n */\nexport async function ensureAuthenticatedThemes(\n store: string,\n password: string | undefined,\n scopes: AdminAPIScope[] = [],\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<AdminSession> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Theme API with the following scopes:\n${outputToken.json(scopes)}\n`)\n if (password) {\n const session = {token: password, storeFqdn: store}\n const authMethod = isThemeAccessSession(session) ? 'theme_access_token' : 'custom_app_token'\n setLastSeenAuthMethod(authMethod)\n setLastSeenUserIdAfterAuth(nonRandomUUID(password))\n return session\n }\n return ensureAuthenticatedAdmin(store, scopes, options)\n}\n\n/**\n * Ensure that we have a valid session to access the Business Platform API.\n *\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param options - Optional extra options to use.\n * @returns The access token for the Business Platform API.\n */\nexport async function ensureAuthenticatedBusinessPlatform(\n scopes: BusinessPlatformScope[] = [],\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<string> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Business Platform API with the following scopes:\n${outputToken.json(scopes)}\n`)\n const tokens = await ensureAuthenticated({businessPlatformApi: {scopes}}, process.env, options)\n if (!tokens.businessPlatform) {\n throw new BugError('No business-platform token found after ensuring authenticated')\n }\n return tokens.businessPlatform\n}\n\n/**\n * Logout from Shopify.\n *\n * @returns A promise that resolves when the logout is complete.\n */\nexport function logout(): Promise<void> {\n return sessionStore.remove()\n}\n\n/**\n * Ensure that we have a valid Admin session for the given store, with access on behalf of the app.\n *\n * See `ensureAuthenticatedAdmin` for access on behalf of a user.\n *\n * @param storeFqdn - Store fqdn to request auth for.\n * @param clientId - Client ID of the app.\n * @param clientSecret - Client secret of the app.\n * @returns The access token for the Admin API.\n */\nexport async function ensureAuthenticatedAdminAsApp(\n storeFqdn: string,\n clientId: string,\n clientSecret: string,\n): Promise<AdminSession> {\n const bodyData = {\n client_id: clientId,\n client_secret: clientSecret,\n grant_type: 'client_credentials',\n }\n const tokenResponse = await shopifyFetch(\n `https://${storeFqdn}/admin/oauth/access_token`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(bodyData),\n },\n 'slow-request',\n )\n\n const body = await tokenResponse.text()\n\n if (tokenResponse.status === 400) {\n if (body.includes('app_not_installed')) {\n throw new AbortError(\n outputContent`App is not installed on ${outputToken.green(\n storeFqdn,\n )}. Try running ${outputToken.genericShellCommand(`shopify app dev`)} to connect your app to the shop.`,\n )\n }\n throw new AbortError(\n `Failed to get access token for app ${clientId} on store ${storeFqdn}: ${tokenResponse.statusText}`,\n )\n }\n try {\n const tokenJson = JSON.parse(body) as {access_token: string}\n return {token: tokenJson.access_token, storeFqdn}\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new AbortError(\n `Received invalid response from admin authentication service (HTTP ${tokenResponse.status}).`,\n 'The response could not be parsed as JSON. The service may be temporarily unavailable. Please try again.',\n )\n }\n throw error\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/public/node/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {shopifyFetch} from './http.js'\nimport {nonRandomUUID} from './crypto.js'\nimport {getAppAutomationToken} from './environment.js'\nimport {AbortError, BugError} from './error.js'\nimport {outputContent, outputToken, outputDebug} from './output.js'\nimport * as sessionStore from '../../private/node/session/store.js'\nimport {automationTokenVariable} from '../../private/node/session/automation-token.js'\nimport {environmentVariables} from '../../private/node/constants.js'\nimport {\n exchangeCustomPartnerToken,\n exchangeAppAutomationTokenForAppManagementAccessToken,\n exchangeAppAutomationTokenForBusinessPlatformAccessToken,\n} from '../../private/node/session/exchange.js'\nimport {\n AdminAPIScope,\n AppManagementAPIScope,\n BusinessPlatformScope,\n EnsureAuthenticatedAdditionalOptions,\n PartnersAPIScope,\n StorefrontRendererScope,\n ensureAuthenticated,\n setCommandSessionId,\n setLastSeenAuthMethod,\n setLastSeenUserIdAfterAuth,\n} from '../../private/node/session.js'\nimport {isThemeAccessSession} from '../../private/node/api/rest.js'\nimport {resolvePermanentStoreFqdn} from '../../private/node/session/permanent-store-domain.js'\n\n/**\n * Session Object to access the Admin API, includes the token and the store FQDN.\n */\nexport interface AdminSession {\n token: string\n storeFqdn: string\n}\n\n/**\n * Session Object for Partners API and App Management API access.\n */\nexport interface Session {\n token: string\n businessPlatformToken: string\n accountInfo: AccountInfo\n userId: string\n}\n\nexport type AccountInfo = UserAccountInfo | ServiceAccountInfo | UnknownAccountInfo\n\n/**\n * Records the user ID that should be attached to command analytics for this process.\n *\n * @param userId - User identifier to report on the command analytics event.\n */\nexport function setLastSeenUserId(userId: string): void {\n setLastSeenUserIdAfterAuth(userId)\n}\n\n/**\n * Finds a stored Shopify account session by alias without changing the current session.\n *\n * @param alias - The account alias to find.\n * @returns The matching session ID, or undefined if no session matches.\n */\nexport async function findSessionIdByAlias(alias: string): Promise<string | undefined> {\n return sessionStore.findSessionByAlias(alias)\n}\n\n/**\n * Selects a stored Shopify account session by alias for the current command process.\n *\n * @param alias - The account alias to select. Passing undefined clears the command selection.\n */\nexport async function setCurrentSessionAlias(alias?: string): Promise<void> {\n if (!alias) {\n setCommandSessionId(undefined)\n return\n }\n\n const sessionId = await findSessionIdByAlias(alias)\n if (!sessionId) {\n throw new AbortError(\n outputContent`No authenticated account found for alias ${outputToken.yellow(alias)}.`,\n outputContent`Run ${outputToken.genericShellCommand(`shopify auth login`)} first.`,\n )\n }\n setCommandSessionId(sessionId)\n}\n\ninterface UserAccountInfo {\n type: 'UserAccount'\n email: string\n}\n\ninterface ServiceAccountInfo {\n type: 'ServiceAccount'\n orgName: string\n}\n\ninterface UnknownAccountInfo {\n type: 'UnknownAccount'\n}\n\n/**\n * Type guard to check if an account is a UserAccount.\n *\n * @param account - The account to check.\n * @returns True if the account is a UserAccount.\n */\nexport function isUserAccount(account: AccountInfo): account is UserAccountInfo {\n return account.type === 'UserAccount'\n}\n\n/**\n * Type guard to check if an account is a ServiceAccount.\n *\n * @param account - The account to check.\n * @returns True if the account is a ServiceAccount.\n */\nexport function isServiceAccount(account: AccountInfo): account is ServiceAccountInfo {\n return account.type === 'ServiceAccount'\n}\n\n/**\n * Ensure that we have a valid session with no particular scopes.\n *\n * @param env - Optional environment variables to use.\n * @param options - Optional extra options to use.\n * @returns The user ID.\n */\nexport async function ensureAuthenticatedUser(\n env = process.env,\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<{userId: string}> {\n outputDebug(outputContent`Ensuring that the user is authenticated with no particular scopes`)\n const tokens = await ensureAuthenticated({}, env, options)\n return {userId: tokens.userId}\n}\n\n/**\n * Ensure that we have a valid session to access the Partners API.\n * If SHOPIFY_CLI_PARTNERS_TOKEN exists, that token will be used to obtain a valid Partners Token\n * If SHOPIFY_CLI_PARTNERS_TOKEN exists, scopes will be ignored.\n *\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param env - Optional environment variables to use.\n * @param options - Optional extra options to use.\n * @returns The access token for the Partners API.\n */\nexport async function ensureAuthenticatedPartners(\n scopes: PartnersAPIScope[] = [],\n env = process.env,\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<{token: string; userId: string}> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Partners API with the following scopes:\n${outputToken.json(scopes)}\n`)\n const envToken = getAppAutomationToken()\n if (envToken) {\n const result = await exchangeCustomPartnerToken(envToken)\n return {token: result.accessToken, userId: result.userId}\n }\n const tokens = await ensureAuthenticated({partnersApi: {scopes}}, env, options)\n if (!tokens.partners) {\n throw new BugError('No partners token found after ensuring authenticated')\n }\n return {token: tokens.partners, userId: tokens.userId}\n}\n\n/**\n * Ensure that we have a valid session to access the App Management API.\n *\n * @param options - Optional extra options to use.\n * @param appManagementScopes - Optional array of extra scopes to authenticate with.\n * @param businessPlatformScopes - Optional array of extra scopes to authenticate with.\n * @param env - Optional environment variables to use.\n * @returns The access token for the App Management API.\n */\nexport async function ensureAuthenticatedAppManagementAndBusinessPlatform(\n options: EnsureAuthenticatedAdditionalOptions = {},\n appManagementScopes: AppManagementAPIScope[] = [],\n businessPlatformScopes: BusinessPlatformScope[] = [],\n env = process.env,\n): Promise<{appManagementToken: string; userId: string; businessPlatformToken: string}> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the App Management API with the following scopes:\n${outputToken.json(appManagementScopes)}\n`)\n\n const envToken = getAppAutomationToken()\n if (envToken) {\n const appManagmentToken = await exchangeAppAutomationTokenForAppManagementAccessToken(envToken)\n const businessPlatformToken = await exchangeAppAutomationTokenForBusinessPlatformAccessToken(envToken)\n\n return {\n appManagementToken: appManagmentToken.accessToken,\n userId: appManagmentToken.userId,\n businessPlatformToken: businessPlatformToken.accessToken,\n }\n }\n\n const tokens = await ensureAuthenticated(\n {appManagementApi: {scopes: appManagementScopes}, businessPlatformApi: {scopes: businessPlatformScopes}},\n env,\n options,\n )\n if (!tokens.appManagement || !tokens.businessPlatform) {\n throw new BugError('No App Management or Business Platform token found after ensuring authenticated')\n }\n\n return {\n appManagementToken: tokens.appManagement,\n userId: tokens.userId,\n businessPlatformToken: tokens.businessPlatform,\n }\n}\n\n/**\n * Ensure that we have a valid session to access the Storefront API.\n *\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param password - Optional password to use.\n * @param options - Optional extra options to use.\n * @returns The access token for the Storefront API.\n */\nexport async function ensureAuthenticatedStorefront(\n scopes: StorefrontRendererScope[] = [],\n password: string | undefined = undefined,\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<string> {\n if (password) {\n const session = {token: password, storeFqdn: ''}\n const authMethod = isThemeAccessSession(session) ? 'theme_access_token' : 'custom_app_token'\n setLastSeenAuthMethod(authMethod)\n setLastSeenUserIdAfterAuth(nonRandomUUID(password))\n return password\n }\n\n outputDebug(outputContent`Ensuring that the user is authenticated with the Storefront API with the following scopes:\n${outputToken.json(scopes)}\n`)\n const tokens = await ensureAuthenticated({storefrontRendererApi: {scopes}}, process.env, options)\n if (!tokens.storefront) {\n throw new BugError('No storefront token found after ensuring authenticated')\n }\n return tokens.storefront\n}\n\n/**\n * Ensure that we have a valid Admin session for the given store.\n *\n * @param store - Store fqdn to request auth for.\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param options - Optional extra options to use.\n * @returns The access token for the Admin API.\n */\nexport async function ensureAuthenticatedAdmin(\n store: string,\n scopes: AdminAPIScope[] = [],\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<AdminSession> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Admin API with the following scopes for the store ${outputToken.raw(\n store,\n )}:\n${outputToken.json(scopes)}\n`)\n const tokens = await ensureAuthenticated({adminApi: {scopes, storeFqdn: store}}, process.env, {\n ...options,\n })\n if (!tokens.admin) {\n throw new BugError('No admin token found after ensuring authenticated')\n }\n return tokens.admin\n}\n\n/**\n * Ensure that we have a valid session to access the Theme API.\n * If a password is provided, that token will be used against Theme Access API.\n * Otherwise, it will ensure that the user is authenticated with the Admin API.\n *\n * Theme Access passwords only work with the store's permanent `.myshopify.com` domain, so when the password is a\n * Theme Access password the returned session uses the permanent domain of `store`, even if `store` is another of the\n * store's domains.\n *\n * @param store - Store fqdn to request auth for.\n * @param password - Password generated from Theme Access app.\n * @param scopes - Optional array of extra scopes to authenticate with.\n * @param options - Optional extra options to use.\n * @returns The access token and store.\n */\nexport async function ensureAuthenticatedThemes(\n store: string,\n password: string | undefined,\n scopes: AdminAPIScope[] = [],\n options: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<AdminSession> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Theme API with the following scopes:\n${outputToken.json(scopes)}\n`)\n if (password) {\n const session = {token: password, storeFqdn: store}\n const themeAccess = isThemeAccessSession(session)\n setLastSeenAuthMethod(themeAccess ? 'theme_access_token' : 'custom_app_token')\n setLastSeenUserIdAfterAuth(nonRandomUUID(password))\n if (themeAccess) session.storeFqdn = await resolvePermanentStoreFqdn(store)\n return session\n }\n return ensureAuthenticatedAdmin(store, scopes, options)\n}\n\n/**\n * Options for `ensureAuthenticatedBusinessPlatform`.\n */\nexport interface EnsureAuthenticatedBusinessPlatformOptions extends EnsureAuthenticatedAdditionalOptions {\n /**\n * Authenticate with the automation token set in the environment, when there is one, instead of the\n * logged-in user. Only commands that support automation tokens opt in; other callers, such as\n * Hydrogen's login, keep using the user's session.\n */\n allowAutomationToken?: boolean\n}\n\n/**\n * Ensure that we have a valid session to access the Business Platform API.\n *\n * @param scopes - Optional array of extra scopes to authenticate with. Ignored when an automation token is used.\n * @param options - Optional extra options to use.\n * @returns The access token for the Business Platform API.\n */\nexport async function ensureAuthenticatedBusinessPlatform(\n scopes: BusinessPlatformScope[] = [],\n options: EnsureAuthenticatedBusinessPlatformOptions = {},\n): Promise<string> {\n outputDebug(outputContent`Ensuring that the user is authenticated with the Business Platform API with the following scopes:\n${outputToken.json(scopes)}\n`)\n const {allowAutomationToken = false, ...authenticationOptions} = options\n const automationToken = allowAutomationToken ? getAppAutomationToken() : undefined\n if (automationToken) {\n // Request no explicit scopes, so Identity issues every Business Platform scope the token holds. The organizations\n // API admits a CLI token only with a scope such as organization.store-management, and naming that scope would\n // fail the exchange for app and Partner tokens, which don't hold it.\n const result = await exchangeAppAutomationTokenForBusinessPlatformAccessToken(automationToken, [])\n return result.accessToken\n }\n\n const tokens = await ensureAuthenticated({businessPlatformApi: {scopes}}, process.env, authenticationOptions)\n if (!tokens.businessPlatform) {\n throw new BugError('No business-platform token found after ensuring authenticated')\n }\n return tokens.businessPlatform\n}\n\n/**\n * Whether SHOPIFY_SERVICE_ACCOUNT_TOKEN is set, which makes it the automation token the CLI authenticates with.\n *\n * True even when it's empty or set together with another automation token variable. Commands use this to skip logins\n * saved on this machine, and authentication then reports any problem with the variables.\n *\n * @returns True when SHOPIFY_SERVICE_ACCOUNT_TOKEN is set.\n */\nexport function isServiceAccountTokenSet(): boolean {\n return automationTokenVariable() === environmentVariables.serviceAccountToken\n}\n\n/**\n * Fails when SHOPIFY_SERVICE_ACCOUNT_TOKEN is set, for commands that can't run with that token.\n *\n * Service account tokens can't log in as a user or call a store's Admin API, so commands that need either\n * refuse to run instead of quietly using the person's own login. `ensureAuthenticated` runs this check before any\n * login. Commands that run on a login saved by `shopify store auth` call it before loading that login.\n *\n * @throws AbortError when SHOPIFY_SERVICE_ACCOUNT_TOKEN is set.\n */\nexport function ensureNoServiceAccountToken(): void {\n if (!isServiceAccountTokenSet()) return\n const variable = environmentVariables.serviceAccountToken\n\n throw new AbortError(`This command can't use ${variable}.`, `Unset ${variable} to run it with your Shopify account.`)\n}\n\n/**\n * Logout from Shopify.\n *\n * @returns A promise that resolves when the logout is complete.\n */\nexport function logout(): Promise<void> {\n return sessionStore.remove()\n}\n\n/**\n * Ensure that we have a valid Admin session for the given store, with access on behalf of the app.\n *\n * See `ensureAuthenticatedAdmin` for access on behalf of a user.\n *\n * @param storeFqdn - Store fqdn to request auth for.\n * @param clientId - Client ID of the app.\n * @param clientSecret - Client secret of the app.\n * @returns The access token for the Admin API.\n */\nexport async function ensureAuthenticatedAdminAsApp(\n storeFqdn: string,\n clientId: string,\n clientSecret: string,\n): Promise<AdminSession> {\n const bodyData = {\n client_id: clientId,\n client_secret: clientSecret,\n grant_type: 'client_credentials',\n }\n const tokenResponse = await shopifyFetch(\n `https://${storeFqdn}/admin/oauth/access_token`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(bodyData),\n },\n 'slow-request',\n )\n\n const body = await tokenResponse.text()\n\n if (tokenResponse.status === 400) {\n if (body.includes('app_not_installed')) {\n throw new AbortError(\n outputContent`App is not installed on ${outputToken.green(\n storeFqdn,\n )}. Try running ${outputToken.genericShellCommand(`shopify app dev`)} to connect your app to the shop.`,\n )\n }\n throw new AbortError(\n `Failed to get access token for app ${clientId} on store ${storeFqdn}: ${tokenResponse.statusText}`,\n )\n }\n try {\n const tokenJson = JSON.parse(body) as {access_token: string}\n return {token: tokenJson.access_token, storeFqdn}\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new AbortError(\n `Received invalid response from admin authentication service (HTTP ${tokenResponse.status}).`,\n 'The response could not be parsed as JSON. The service may be temporarily unavailable. Please try again.',\n )\n }\n throw error\n }\n}\n"]}
|
|
@@ -8,6 +8,8 @@ export interface ExecOptions {
|
|
|
8
8
|
stderr?: Writable | 'inherit';
|
|
9
9
|
stdio?: 'inherit';
|
|
10
10
|
input?: string;
|
|
11
|
+
/** Whether to remove the final newline from captured stdout/stderr (default: true). */
|
|
12
|
+
stripFinalNewline?: boolean;
|
|
11
13
|
signal?: AbortSignal;
|
|
12
14
|
externalErrorHandler?: (error: unknown) => Promise<void>;
|
|
13
15
|
background?: boolean;
|
|
@@ -42,6 +44,7 @@ export interface CaptureOutputResult {
|
|
|
42
44
|
/**
|
|
43
45
|
* Runs a command asynchronously and returns stdout, stderr, and exit code.
|
|
44
46
|
* Unlike captureOutput, this function does NOT throw on non-zero exit codes.
|
|
47
|
+
* Startup failures and signal termination still throw an ExternalError.
|
|
45
48
|
*
|
|
46
49
|
* @param command - Command to be executed.
|
|
47
50
|
* @param args - Arguments to pass to the command.
|
|
@@ -61,6 +64,7 @@ export declare function captureOutputWithExitCode(command: string, args: string[
|
|
|
61
64
|
* Runs a command string asynchronously and returns stdout, stderr, and exit code.
|
|
62
65
|
* Parses the command string into command and arguments (handles quoted strings).
|
|
63
66
|
* Unlike captureOutput, this function does NOT throw on non-zero exit codes.
|
|
67
|
+
* Startup failures and signal termination still throw an ExternalError.
|
|
64
68
|
*
|
|
65
69
|
* @param command - Full command string to be executed (e.g., 'ls -la "my folder"').
|
|
66
70
|
* @param options - Optional settings for how to run the command.
|
|
@@ -33,14 +33,38 @@ export async function openURL(url) {
|
|
|
33
33
|
return false;
|
|
34
34
|
const externalOpen = await import('open');
|
|
35
35
|
try {
|
|
36
|
-
await externalOpen.default(url);
|
|
37
|
-
return
|
|
36
|
+
const subprocess = await externalOpen.default(url);
|
|
37
|
+
return await browserLaunchSucceeded(subprocess);
|
|
38
38
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
39
39
|
}
|
|
40
40
|
catch (error) {
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Waits for the process spawned to open a browser to either start or fail.
|
|
46
|
+
*
|
|
47
|
+
* `open` resolves as soon as it has called `spawn`, before the OS reports whether the
|
|
48
|
+
* launcher exists. A missing launcher (e.g. `xdg-open` in a headless container) is
|
|
49
|
+
* reported later as an `error` event on the child process. Without a listener that
|
|
50
|
+
* event is thrown as an uncaught exception and terminates the CLI, which kills flows
|
|
51
|
+
* such as device-code login that could otherwise carry on with the printed link.
|
|
52
|
+
*
|
|
53
|
+
* @param subprocess - The child process returned by `open`.
|
|
54
|
+
* @returns A promise that resolves true if the process started, false if it failed to start.
|
|
55
|
+
*/
|
|
56
|
+
async function browserLaunchSucceeded(subprocess) {
|
|
57
|
+
if (!subprocess || typeof subprocess.once !== 'function')
|
|
58
|
+
return true;
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
// Keep a permanent listener so a late error can never become an uncaught exception.
|
|
61
|
+
subprocess.on('error', (error) => {
|
|
62
|
+
outputDebug(`Failed to open the browser: ${error.message}`);
|
|
63
|
+
resolve(false);
|
|
64
|
+
});
|
|
65
|
+
subprocess.once('spawn', () => resolve(true));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
44
68
|
/**
|
|
45
69
|
* Runs a command asynchronously, aggregates the stdout data, and returns it.
|
|
46
70
|
*
|
|
@@ -56,6 +80,7 @@ export async function captureOutput(command, args, options) {
|
|
|
56
80
|
/**
|
|
57
81
|
* Runs a command asynchronously and returns stdout, stderr, and exit code.
|
|
58
82
|
* Unlike captureOutput, this function does NOT throw on non-zero exit codes.
|
|
83
|
+
* Startup failures and signal termination still throw an ExternalError.
|
|
59
84
|
*
|
|
60
85
|
* @param command - Command to be executed.
|
|
61
86
|
* @param args - Arguments to pass to the command.
|
|
@@ -72,10 +97,13 @@ export async function captureOutput(command, args, options) {
|
|
|
72
97
|
*/
|
|
73
98
|
export async function captureOutputWithExitCode(command, args, options) {
|
|
74
99
|
const result = await buildExec(command, args, options, { reject: false });
|
|
100
|
+
if (result.exitCode === undefined) {
|
|
101
|
+
throw new ExternalError(result instanceof Error ? result.message : 'Command terminated without an exit code.', command, args);
|
|
102
|
+
}
|
|
75
103
|
return {
|
|
76
104
|
stdout: result.stdout,
|
|
77
105
|
stderr: result.stderr,
|
|
78
|
-
exitCode: result.exitCode
|
|
106
|
+
exitCode: result.exitCode,
|
|
79
107
|
};
|
|
80
108
|
}
|
|
81
109
|
/**
|
|
@@ -127,6 +155,7 @@ function parseCommand(command) {
|
|
|
127
155
|
* Runs a command string asynchronously and returns stdout, stderr, and exit code.
|
|
128
156
|
* Parses the command string into command and arguments (handles quoted strings).
|
|
129
157
|
* Unlike captureOutput, this function does NOT throw on non-zero exit codes.
|
|
158
|
+
* Startup failures and signal termination still throw an ExternalError.
|
|
130
159
|
*
|
|
131
160
|
* @param command - Full command string to be executed (e.g., 'ls -la "my folder"').
|
|
132
161
|
* @param options - Optional settings for how to run the command.
|
|
@@ -177,12 +206,6 @@ export async function exec(command, args, options) {
|
|
|
177
206
|
if (options?.background) {
|
|
178
207
|
commandProcess.unref();
|
|
179
208
|
}
|
|
180
|
-
if (options?.stderr && options.stderr !== 'inherit') {
|
|
181
|
-
commandProcess.stderr?.pipe(options.stderr, { end: false });
|
|
182
|
-
}
|
|
183
|
-
if (options?.stdout && options.stdout !== 'inherit') {
|
|
184
|
-
commandProcess.stdout?.pipe(options.stdout, { end: false });
|
|
185
|
-
}
|
|
186
209
|
let aborted = false;
|
|
187
210
|
options?.signal?.addEventListener('abort', () => {
|
|
188
211
|
const pid = commandProcess.pid;
|
|
@@ -232,6 +255,7 @@ function buildExec(command, args, options, execaOptions) {
|
|
|
232
255
|
env,
|
|
233
256
|
cwd: executionCwd,
|
|
234
257
|
input: options?.input,
|
|
258
|
+
stripFinalNewline: options?.stripFinalNewline ?? true,
|
|
235
259
|
stdio: options?.background ? backgroundStdio : options?.stdio,
|
|
236
260
|
stdin: options?.stdin,
|
|
237
261
|
stdout: options?.stdout === 'inherit' ? 'inherit' : undefined,
|
|
@@ -243,6 +267,12 @@ function buildExec(command, args, options, execaOptions) {
|
|
|
243
267
|
cleanup: !options?.background,
|
|
244
268
|
...execaOptions,
|
|
245
269
|
});
|
|
270
|
+
if (options?.stderr && options.stderr !== 'inherit') {
|
|
271
|
+
commandProcess.stderr?.pipe(options.stderr, { end: false });
|
|
272
|
+
}
|
|
273
|
+
if (options?.stdout && options.stdout !== 'inherit') {
|
|
274
|
+
commandProcess.stdout?.pipe(options.stdout, { end: false });
|
|
275
|
+
}
|
|
246
276
|
outputDebug(`Running system process${options?.background ? ' in background' : ''}:
|
|
247
277
|
· Command: ${command} ${args.join(' ')}
|
|
248
278
|
· Working directory: ${executionCwd}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/public/node/system.ts"],"names":[],"mappings":"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","sourcesContent":["import {AbortSignal} from './abort.js'\nimport {AbortError, ExternalError} from './error.js'\nimport {cwd, resolvePath} from './path.js'\nimport {treeKill} from './tree-kill.js'\nimport {isTruthy} from './context/utilities.js'\nimport {renderWarning} from './ui.js'\nimport {platformAndArch} from './os.js'\nimport {shouldDisplayColors, outputDebug} from './output.js'\nimport {isCloudEnvironment} from './context/local.js'\nimport {isInputDisabled} from './no-input.js'\nimport {execa, ExecaChildProcess} from 'execa'\nimport supportsHyperlinks from 'supports-hyperlinks'\nimport which from 'which'\n\nimport {fstatSync, existsSync, readFileSync} from 'fs'\nimport {release} from 'os'\nimport {setTimeout} from 'timers/promises'\nimport type {Writable, Readable} from 'stream'\n\n/**\n * The maximum size of data that can be read from stdin in bytes.\n * This is to prevent memory exhaustion when reading from stdin.\n * 10MB.\n */\nconst MAX_STDIN_SIZE = 10 * 1024 * 1024\n\nexport interface ExecOptions {\n cwd?: string\n env?: Record<string, string | undefined>\n stdin?: Readable | 'inherit'\n stdout?: Writable | 'inherit'\n stderr?: Writable | 'inherit'\n stdio?: 'inherit'\n input?: string\n signal?: AbortSignal\n // Custom handler if process exits with a non-zero code\n externalErrorHandler?: (error: unknown) => Promise<void>\n // Ignored on Windows\n background?: boolean\n}\n\n/**\n * Options passed directly to execa.\n */\ninterface BuildExecOptions {\n /** Whether to throw on non-zero exit codes (default: true). */\n reject?: boolean\n}\n\n/**\n * Opens a URL in the user's default browser.\n *\n * @param url - URL to open.\n * @returns A promise that resolves true if the URL was opened successfully, false otherwise.\n */\nexport async function openURL(url: string): Promise<boolean> {\n if (isInputDisabled()) {\n throw new AbortError(\n 'Opening a browser is unavailable when user input is disabled.',\n 'Remove `--no-input` and run the command in an interactive terminal.',\n )\n }\n if (isCloudEnvironment()) return false\n\n const externalOpen = await import('open')\n try {\n await externalOpen.default(url)\n return true\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n return false\n }\n}\n\n/**\n * Runs a command asynchronously, aggregates the stdout data, and returns it.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n * @returns A promise that resolves with the aggregatted stdout of the command.\n */\nexport async function captureOutput(command: string, args: string[], options?: ExecOptions): Promise<string> {\n const result = await buildExec(command, args, options)\n return result.stdout\n}\n\n/**\n * Result from running a command with captureOutputWithExitCode.\n */\nexport interface CaptureOutputResult {\n /** Standard output. */\n stdout: string\n /** Standard error. */\n stderr: string\n /** Exit code (0 = success). */\n exitCode: number\n}\n\n/**\n * Runs a command asynchronously and returns stdout, stderr, and exit code.\n * Unlike captureOutput, this function does NOT throw on non-zero exit codes.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n * @returns A promise that resolves with stdout, stderr, and exitCode.\n *\n * @example\n * ```typescript\n * const result = await captureOutputWithExitCode('ls', ['-la'])\n * if (result.exitCode !== 0) \\{\n * console.error('Command failed:', result.stderr)\n * \\}\n * ```\n */\nexport async function captureOutputWithExitCode(\n command: string,\n args: string[],\n options?: ExecOptions,\n): Promise<CaptureOutputResult> {\n const result = await buildExec(command, args, options, {reject: false})\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode ?? 0,\n }\n}\n\n/**\n * Parse a command string into an array of arguments, respecting quoted strings.\n * Handles both single and double quotes, preserving spaces within quoted sections.\n *\n * @param command - The command string to parse (e.g., 'ls -la \"my folder\"').\n * @returns An array of command parts with quotes removed.\n *\n * @example\n * parseCommand('shopify theme push --theme \"My Theme Name\"') // ['shopify', 'theme', 'push', '--theme', 'My Theme Name']\n */\nfunction parseCommand(command: string): string[] {\n const result: string[] = []\n let current = ''\n let inQuote: string | null = null\n\n for (const char of command) {\n if (inQuote) {\n if (char === inQuote) {\n // End of quoted section\n inQuote = null\n } else {\n current += char\n }\n } else if (char === '\"' || char === \"'\") {\n // Start of quoted section\n inQuote = char\n } else if (char === ' ' || char === '\\t') {\n // Whitespace outside quotes - end current token\n if (current) {\n result.push(current)\n current = ''\n }\n } else {\n current += char\n }\n }\n\n // Don't forget the last token\n if (current) {\n result.push(current)\n }\n\n return result\n}\n\n/**\n * Runs a command string asynchronously and returns stdout, stderr, and exit code.\n * Parses the command string into command and arguments (handles quoted strings).\n * Unlike captureOutput, this function does NOT throw on non-zero exit codes.\n *\n * @param command - Full command string to be executed (e.g., 'ls -la \"my folder\"').\n * @param options - Optional settings for how to run the command.\n * @returns A promise that resolves with stdout, stderr, and exitCode.\n *\n * @example\n * ```typescript\n * const result = await captureCommandWithExitCode('shopify theme push --theme \"My Theme\"')\n * if (result.exitCode !== 0) {\n * console.error('Command failed:', result.stderr)\n * }\n * ```\n */\nexport async function captureCommandWithExitCode(command: string, options?: ExecOptions): Promise<CaptureOutputResult> {\n const [cmd, ...args] = parseCommand(command)\n if (!cmd) {\n return {stdout: '', stderr: 'Empty command', exitCode: 1}\n }\n return captureOutputWithExitCode(cmd, args, options)\n}\n\n/**\n * Runs a command string asynchronously (parses command and arguments from the string).\n *\n * @param command - Full command string to be executed (e.g., 'ls -la \"my folder\"').\n * @param options - Optional settings for how to run the command.\n */\nexport async function execCommand(command: string, options?: ExecOptions): Promise<void> {\n const [cmd, ...args] = parseCommand(command)\n if (!cmd) {\n throw new AbortError('Empty command')\n }\n await exec(cmd, args, options)\n}\n\n/**\n * Runs a command asynchronously.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n */\nexport async function exec(command: string, args: string[], options?: ExecOptions): Promise<void> {\n if (options) {\n // Windows opens a new console window when running a command in the background, so we disable it.\n const runningOnWindows = platformAndArch().platform === 'windows'\n options.background = runningOnWindows ? false : options.background\n }\n\n const commandProcess = buildExec(command, args, options)\n\n if (options?.background) {\n commandProcess.unref()\n }\n\n if (options?.stderr && options.stderr !== 'inherit') {\n commandProcess.stderr?.pipe(options.stderr, {end: false})\n }\n if (options?.stdout && options.stdout !== 'inherit') {\n commandProcess.stdout?.pipe(options.stdout, {end: false})\n }\n let aborted = false\n options?.signal?.addEventListener('abort', () => {\n const pid = commandProcess.pid\n if (pid) {\n outputDebug(`Killing process ${pid}: ${command} ${args.join(' ')}`)\n aborted = true\n treeKill(pid, 'SIGTERM')\n }\n })\n try {\n await commandProcess\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (processError: any) {\n // Windows will throw an error whenever the process is killed, no matter the reason.\n // The aborted flag tell use that we killed it, so we can ignore the error.\n if (aborted) return\n if (options?.externalErrorHandler) {\n await options.externalErrorHandler(processError)\n } else {\n const abortError = new ExternalError(processError.message, command, args)\n abortError.stack = processError.stack\n throw abortError\n }\n }\n}\n\n/**\n * Runs a command asynchronously.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n * @param execaOptions - Options passed directly to execa.\n * @returns A promise for a result with stdout and stderr properties.\n */\nfunction buildExec(\n command: string,\n args: string[],\n options?: ExecOptions,\n execaOptions?: BuildExecOptions,\n): ExecaChildProcess {\n const env = options?.env ?? process.env\n if (shouldDisplayColors()) {\n env.FORCE_COLOR = '1'\n }\n const executionCwd = options?.cwd ?? cwd()\n checkCommandSafety(command, executionCwd)\n const backgroundStdio = options?.input === undefined ? 'ignore' : (['pipe', 'ignore', 'ignore'] as const)\n const commandProcess = execa(command, args, {\n env,\n cwd: executionCwd,\n input: options?.input,\n stdio: options?.background ? backgroundStdio : options?.stdio,\n stdin: options?.stdin,\n stdout: options?.stdout === 'inherit' ? 'inherit' : undefined,\n stderr: options?.stderr === 'inherit' ? 'inherit' : undefined,\n // Setting this to false makes it possible to kill the main process\n // and all its sub-processes with Ctrl+C on Windows\n windowsHide: false,\n detached: options?.background,\n cleanup: !options?.background,\n ...execaOptions,\n })\n outputDebug(`Running system process${options?.background ? ' in background' : ''}:\n · Command: ${command} ${args.join(' ')}\n · Working directory: ${executionCwd}\n`)\n return commandProcess\n}\n\n/**\n * Refuses a bare command name that matches an executable in the working directory, because that directory may be\n * untrusted and Windows looks there before PATH. The name is looked up as a file in the working directory, with\n * Windows executable extensions, instead of through a search path, which would split a directory whose name contains\n * the path delimiter. Resolving to an absolute path keeps a relative working directory such as `.` from reducing the\n * file to the bare name, which `which` would search for in PATH. A command given as a path runs the file the caller\n * named, so it isn't checked.\n *\n * @param command - The command to run.\n * @param workingDirectory - The directory the command runs in.\n * @throws AbortError when the command matches an executable in the working directory.\n */\nfunction checkCommandSafety(command: string, workingDirectory: string): void {\n if (/[\\\\/]/.test(command)) return\n if (which.sync(resolvePath(workingDirectory, command), {nothrow: true})) {\n const headline = ['Skipped run of unsecure binary', {command}, 'found in the current directory.']\n const body = 'Please remove that file or review your current PATH.'\n renderWarning({headline, body})\n throw new AbortError(headline, body)\n }\n}\n\n/**\n * Waits for a given number of seconds.\n *\n * @param seconds - Number of seconds to wait.\n * @returns A Promise resolving after the number of seconds.\n */\nexport async function sleep(seconds: number): Promise<void> {\n await setTimeout(1000 * seconds)\n}\n\n/**\n * Check if the terminal supports OSC 8 hyperlinks.\n *\n * @returns True if the terminal supports hyperlinks.\n */\nexport function terminalSupportsHyperlinks(): boolean {\n return supportsHyperlinks.stdout\n}\n\n/**\n * Check if standard input and standard error are terminals that support prompting.\n *\n * @returns True if standard input and standard error support prompting.\n */\nexport function terminalSupportsPrompting(): boolean {\n if (isInputDisabled() || isTruthy(process.env.CI)) {\n return false\n }\n return Boolean(process.stdin.isTTY && process.stderr.isTTY)\n}\n\n/**\n * Check if the current environment is a CI environment.\n *\n * @returns True if the current environment is a CI environment.\n */\nexport function isCI(): boolean {\n return isTruthy(process.env.CI)\n}\n\ninterface WslDetectionOverrides {\n platform?: NodeJS.Platform\n kernelRelease?: string\n procVersion?: string\n insideContainer?: boolean\n}\n\n/**\n * Check if the current environment is a WSL environment.\n *\n * @param overrides - Detection inputs, read from the system when not provided. Intended for tests.\n * @returns True if the current environment is a WSL environment.\n */\n// Mirrors https://github.com/sindresorhus/is-wsl: WSL reports \"microsoft\" in the kernel\n// release, but containers running inside WSL shouldn't count.\nexport async function isWsl(overrides: WslDetectionOverrides = {}): Promise<boolean> {\n const platform = overrides.platform ?? process.platform\n if (platform !== 'linux') return false\n const insideContainer = () => overrides.insideContainer ?? isInsideContainer()\n if ((overrides.kernelRelease ?? release()).toLowerCase().includes('microsoft')) {\n return !insideContainer()\n }\n try {\n const procVersion = overrides.procVersion ?? readFileSync('/proc/version', 'utf8')\n return procVersion.toLowerCase().includes('microsoft') ? !insideContainer() : false\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n// Mirrors the is-inside-container and is-docker packages: Podman creates /run/.containerenv,\n// Docker creates /.dockerenv or mentions \"docker\" in the process cgroup.\n/**\n * Check if the current process is running inside a container.\n *\n * @returns True if the current process is running inside a container.\n */\nexport function isInsideContainer(): boolean {\n if (existsSync('/run/.containerenv') || existsSync('/.dockerenv')) return true\n try {\n return readFileSync('/proc/self/cgroup', 'utf8').includes('docker')\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * Check if stdin has piped data available.\n * This distinguishes between actual piped input (e.g., `echo \"query\" | cmd`)\n * and non-TTY environments without input (e.g., CI).\n *\n * @returns True if stdin is receiving piped data or file redirect, false otherwise.\n */\nexport function isStdinPiped(): boolean {\n try {\n const stats = fstatSync(0)\n return stats.isFIFO() || stats.isFile() || stats.isSocket()\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * Reads all data from stdin and returns it as a string.\n * This is useful for commands that accept input via piping.\n *\n * @example\n * // Usage: echo \"your query\" | shopify app execute\n * const query = await readStdin()\n *\n * @returns A promise that resolves with the stdin content, or undefined if stdin is a TTY.\n */\nexport async function readStdinString(): Promise<string | undefined> {\n if (!isStdinPiped()) {\n return undefined\n }\n\n let data = ''\n let totalSize = 0\n process.stdin.setEncoding('utf8')\n for await (const chunk of process.stdin) {\n const chunkString = String(chunk)\n totalSize += Buffer.byteLength(chunkString, 'utf8')\n if (totalSize > MAX_STDIN_SIZE) {\n throw new AbortError('Stdin input exceeded the maximum allowed size.')\n }\n data += chunkString\n }\n return data.trim()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/public/node/system.ts"],"names":[],"mappings":"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","sourcesContent":["import {AbortSignal} from './abort.js'\nimport {AbortError, ExternalError} from './error.js'\nimport {cwd, resolvePath} from './path.js'\nimport {treeKill} from './tree-kill.js'\nimport {isTruthy} from './context/utilities.js'\nimport {renderWarning} from './ui.js'\nimport {platformAndArch} from './os.js'\nimport {shouldDisplayColors, outputDebug} from './output.js'\nimport {isCloudEnvironment} from './context/local.js'\nimport {isInputDisabled} from './no-input.js'\nimport {execa, ExecaChildProcess} from 'execa'\nimport supportsHyperlinks from 'supports-hyperlinks'\nimport which from 'which'\n\nimport {fstatSync, existsSync, readFileSync} from 'fs'\nimport {release} from 'os'\nimport {setTimeout} from 'timers/promises'\nimport type {Writable, Readable} from 'stream'\n\n/**\n * The maximum size of data that can be read from stdin in bytes.\n * This is to prevent memory exhaustion when reading from stdin.\n * 10MB.\n */\nconst MAX_STDIN_SIZE = 10 * 1024 * 1024\n\nexport interface ExecOptions {\n cwd?: string\n env?: Record<string, string | undefined>\n stdin?: Readable | 'inherit'\n stdout?: Writable | 'inherit'\n stderr?: Writable | 'inherit'\n stdio?: 'inherit'\n input?: string\n /** Whether to remove the final newline from captured stdout/stderr (default: true). */\n stripFinalNewline?: boolean\n signal?: AbortSignal\n // Custom handler if process exits with a non-zero code\n externalErrorHandler?: (error: unknown) => Promise<void>\n // Ignored on Windows\n background?: boolean\n}\n\n/**\n * Options passed directly to execa.\n */\ninterface BuildExecOptions {\n /** Whether to throw on non-zero exit codes (default: true). */\n reject?: boolean\n}\n\n/**\n * Opens a URL in the user's default browser.\n *\n * @param url - URL to open.\n * @returns A promise that resolves true if the URL was opened successfully, false otherwise.\n */\nexport async function openURL(url: string): Promise<boolean> {\n if (isInputDisabled()) {\n throw new AbortError(\n 'Opening a browser is unavailable when user input is disabled.',\n 'Remove `--no-input` and run the command in an interactive terminal.',\n )\n }\n if (isCloudEnvironment()) return false\n\n const externalOpen = await import('open')\n try {\n const subprocess = await externalOpen.default(url)\n return await browserLaunchSucceeded(subprocess)\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n return false\n }\n}\n\n/**\n * Waits for the process spawned to open a browser to either start or fail.\n *\n * `open` resolves as soon as it has called `spawn`, before the OS reports whether the\n * launcher exists. A missing launcher (e.g. `xdg-open` in a headless container) is\n * reported later as an `error` event on the child process. Without a listener that\n * event is thrown as an uncaught exception and terminates the CLI, which kills flows\n * such as device-code login that could otherwise carry on with the printed link.\n *\n * @param subprocess - The child process returned by `open`.\n * @returns A promise that resolves true if the process started, false if it failed to start.\n */\nasync function browserLaunchSucceeded(subprocess: NodeJS.EventEmitter | undefined): Promise<boolean> {\n if (!subprocess || typeof subprocess.once !== 'function') return true\n return new Promise<boolean>((resolve) => {\n // Keep a permanent listener so a late error can never become an uncaught exception.\n subprocess.on('error', (error: Error) => {\n outputDebug(`Failed to open the browser: ${error.message}`)\n resolve(false)\n })\n subprocess.once('spawn', () => resolve(true))\n })\n}\n\n/**\n * Runs a command asynchronously, aggregates the stdout data, and returns it.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n * @returns A promise that resolves with the aggregatted stdout of the command.\n */\nexport async function captureOutput(command: string, args: string[], options?: ExecOptions): Promise<string> {\n const result = await buildExec(command, args, options)\n return result.stdout\n}\n\n/**\n * Result from running a command with captureOutputWithExitCode.\n */\nexport interface CaptureOutputResult {\n /** Standard output. */\n stdout: string\n /** Standard error. */\n stderr: string\n /** Exit code (0 = success). */\n exitCode: number\n}\n\n/**\n * Runs a command asynchronously and returns stdout, stderr, and exit code.\n * Unlike captureOutput, this function does NOT throw on non-zero exit codes.\n * Startup failures and signal termination still throw an ExternalError.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n * @returns A promise that resolves with stdout, stderr, and exitCode.\n *\n * @example\n * ```typescript\n * const result = await captureOutputWithExitCode('ls', ['-la'])\n * if (result.exitCode !== 0) \\{\n * console.error('Command failed:', result.stderr)\n * \\}\n * ```\n */\nexport async function captureOutputWithExitCode(\n command: string,\n args: string[],\n options?: ExecOptions,\n): Promise<CaptureOutputResult> {\n const result = await buildExec(command, args, options, {reject: false})\n if (result.exitCode === undefined) {\n throw new ExternalError(\n result instanceof Error ? result.message : 'Command terminated without an exit code.',\n command,\n args,\n )\n }\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n }\n}\n\n/**\n * Parse a command string into an array of arguments, respecting quoted strings.\n * Handles both single and double quotes, preserving spaces within quoted sections.\n *\n * @param command - The command string to parse (e.g., 'ls -la \"my folder\"').\n * @returns An array of command parts with quotes removed.\n *\n * @example\n * parseCommand('shopify theme push --theme \"My Theme Name\"') // ['shopify', 'theme', 'push', '--theme', 'My Theme Name']\n */\nfunction parseCommand(command: string): string[] {\n const result: string[] = []\n let current = ''\n let inQuote: string | null = null\n\n for (const char of command) {\n if (inQuote) {\n if (char === inQuote) {\n // End of quoted section\n inQuote = null\n } else {\n current += char\n }\n } else if (char === '\"' || char === \"'\") {\n // Start of quoted section\n inQuote = char\n } else if (char === ' ' || char === '\\t') {\n // Whitespace outside quotes - end current token\n if (current) {\n result.push(current)\n current = ''\n }\n } else {\n current += char\n }\n }\n\n // Don't forget the last token\n if (current) {\n result.push(current)\n }\n\n return result\n}\n\n/**\n * Runs a command string asynchronously and returns stdout, stderr, and exit code.\n * Parses the command string into command and arguments (handles quoted strings).\n * Unlike captureOutput, this function does NOT throw on non-zero exit codes.\n * Startup failures and signal termination still throw an ExternalError.\n *\n * @param command - Full command string to be executed (e.g., 'ls -la \"my folder\"').\n * @param options - Optional settings for how to run the command.\n * @returns A promise that resolves with stdout, stderr, and exitCode.\n *\n * @example\n * ```typescript\n * const result = await captureCommandWithExitCode('shopify theme push --theme \"My Theme\"')\n * if (result.exitCode !== 0) {\n * console.error('Command failed:', result.stderr)\n * }\n * ```\n */\nexport async function captureCommandWithExitCode(command: string, options?: ExecOptions): Promise<CaptureOutputResult> {\n const [cmd, ...args] = parseCommand(command)\n if (!cmd) {\n return {stdout: '', stderr: 'Empty command', exitCode: 1}\n }\n return captureOutputWithExitCode(cmd, args, options)\n}\n\n/**\n * Runs a command string asynchronously (parses command and arguments from the string).\n *\n * @param command - Full command string to be executed (e.g., 'ls -la \"my folder\"').\n * @param options - Optional settings for how to run the command.\n */\nexport async function execCommand(command: string, options?: ExecOptions): Promise<void> {\n const [cmd, ...args] = parseCommand(command)\n if (!cmd) {\n throw new AbortError('Empty command')\n }\n await exec(cmd, args, options)\n}\n\n/**\n * Runs a command asynchronously.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n */\nexport async function exec(command: string, args: string[], options?: ExecOptions): Promise<void> {\n if (options) {\n // Windows opens a new console window when running a command in the background, so we disable it.\n const runningOnWindows = platformAndArch().platform === 'windows'\n options.background = runningOnWindows ? false : options.background\n }\n\n const commandProcess = buildExec(command, args, options)\n\n if (options?.background) {\n commandProcess.unref()\n }\n\n let aborted = false\n options?.signal?.addEventListener('abort', () => {\n const pid = commandProcess.pid\n if (pid) {\n outputDebug(`Killing process ${pid}: ${command} ${args.join(' ')}`)\n aborted = true\n treeKill(pid, 'SIGTERM')\n }\n })\n try {\n await commandProcess\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (processError: any) {\n // Windows will throw an error whenever the process is killed, no matter the reason.\n // The aborted flag tell use that we killed it, so we can ignore the error.\n if (aborted) return\n if (options?.externalErrorHandler) {\n await options.externalErrorHandler(processError)\n } else {\n const abortError = new ExternalError(processError.message, command, args)\n abortError.stack = processError.stack\n throw abortError\n }\n }\n}\n\n/**\n * Runs a command asynchronously.\n *\n * @param command - Command to be executed.\n * @param args - Arguments to pass to the command.\n * @param options - Optional settings for how to run the command.\n * @param execaOptions - Options passed directly to execa.\n * @returns A promise for a result with stdout and stderr properties.\n */\nfunction buildExec(\n command: string,\n args: string[],\n options?: ExecOptions,\n execaOptions?: BuildExecOptions,\n): ExecaChildProcess {\n const env = options?.env ?? process.env\n if (shouldDisplayColors()) {\n env.FORCE_COLOR = '1'\n }\n const executionCwd = options?.cwd ?? cwd()\n checkCommandSafety(command, executionCwd)\n const backgroundStdio = options?.input === undefined ? 'ignore' : (['pipe', 'ignore', 'ignore'] as const)\n const commandProcess = execa(command, args, {\n env,\n cwd: executionCwd,\n input: options?.input,\n stripFinalNewline: options?.stripFinalNewline ?? true,\n stdio: options?.background ? backgroundStdio : options?.stdio,\n stdin: options?.stdin,\n stdout: options?.stdout === 'inherit' ? 'inherit' : undefined,\n stderr: options?.stderr === 'inherit' ? 'inherit' : undefined,\n // Setting this to false makes it possible to kill the main process\n // and all its sub-processes with Ctrl+C on Windows\n windowsHide: false,\n detached: options?.background,\n cleanup: !options?.background,\n ...execaOptions,\n })\n if (options?.stderr && options.stderr !== 'inherit') {\n commandProcess.stderr?.pipe(options.stderr, {end: false})\n }\n if (options?.stdout && options.stdout !== 'inherit') {\n commandProcess.stdout?.pipe(options.stdout, {end: false})\n }\n outputDebug(`Running system process${options?.background ? ' in background' : ''}:\n · Command: ${command} ${args.join(' ')}\n · Working directory: ${executionCwd}\n`)\n return commandProcess\n}\n\n/**\n * Refuses a bare command name that matches an executable in the working directory, because that directory may be\n * untrusted and Windows looks there before PATH. The name is looked up as a file in the working directory, with\n * Windows executable extensions, instead of through a search path, which would split a directory whose name contains\n * the path delimiter. Resolving to an absolute path keeps a relative working directory such as `.` from reducing the\n * file to the bare name, which `which` would search for in PATH. A command given as a path runs the file the caller\n * named, so it isn't checked.\n *\n * @param command - The command to run.\n * @param workingDirectory - The directory the command runs in.\n * @throws AbortError when the command matches an executable in the working directory.\n */\nfunction checkCommandSafety(command: string, workingDirectory: string): void {\n if (/[\\\\/]/.test(command)) return\n if (which.sync(resolvePath(workingDirectory, command), {nothrow: true})) {\n const headline = ['Skipped run of unsecure binary', {command}, 'found in the current directory.']\n const body = 'Please remove that file or review your current PATH.'\n renderWarning({headline, body})\n throw new AbortError(headline, body)\n }\n}\n\n/**\n * Waits for a given number of seconds.\n *\n * @param seconds - Number of seconds to wait.\n * @returns A Promise resolving after the number of seconds.\n */\nexport async function sleep(seconds: number): Promise<void> {\n await setTimeout(1000 * seconds)\n}\n\n/**\n * Check if the terminal supports OSC 8 hyperlinks.\n *\n * @returns True if the terminal supports hyperlinks.\n */\nexport function terminalSupportsHyperlinks(): boolean {\n return supportsHyperlinks.stdout\n}\n\n/**\n * Check if standard input and standard error are terminals that support prompting.\n *\n * @returns True if standard input and standard error support prompting.\n */\nexport function terminalSupportsPrompting(): boolean {\n if (isInputDisabled() || isTruthy(process.env.CI)) {\n return false\n }\n return Boolean(process.stdin.isTTY && process.stderr.isTTY)\n}\n\n/**\n * Check if the current environment is a CI environment.\n *\n * @returns True if the current environment is a CI environment.\n */\nexport function isCI(): boolean {\n return isTruthy(process.env.CI)\n}\n\ninterface WslDetectionOverrides {\n platform?: NodeJS.Platform\n kernelRelease?: string\n procVersion?: string\n insideContainer?: boolean\n}\n\n/**\n * Check if the current environment is a WSL environment.\n *\n * @param overrides - Detection inputs, read from the system when not provided. Intended for tests.\n * @returns True if the current environment is a WSL environment.\n */\n// Mirrors https://github.com/sindresorhus/is-wsl: WSL reports \"microsoft\" in the kernel\n// release, but containers running inside WSL shouldn't count.\nexport async function isWsl(overrides: WslDetectionOverrides = {}): Promise<boolean> {\n const platform = overrides.platform ?? process.platform\n if (platform !== 'linux') return false\n const insideContainer = () => overrides.insideContainer ?? isInsideContainer()\n if ((overrides.kernelRelease ?? release()).toLowerCase().includes('microsoft')) {\n return !insideContainer()\n }\n try {\n const procVersion = overrides.procVersion ?? readFileSync('/proc/version', 'utf8')\n return procVersion.toLowerCase().includes('microsoft') ? !insideContainer() : false\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n// Mirrors the is-inside-container and is-docker packages: Podman creates /run/.containerenv,\n// Docker creates /.dockerenv or mentions \"docker\" in the process cgroup.\n/**\n * Check if the current process is running inside a container.\n *\n * @returns True if the current process is running inside a container.\n */\nexport function isInsideContainer(): boolean {\n if (existsSync('/run/.containerenv') || existsSync('/.dockerenv')) return true\n try {\n return readFileSync('/proc/self/cgroup', 'utf8').includes('docker')\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * Check if stdin has piped data available.\n * This distinguishes between actual piped input (e.g., `echo \"query\" | cmd`)\n * and non-TTY environments without input (e.g., CI).\n *\n * @returns True if stdin is receiving piped data or file redirect, false otherwise.\n */\nexport function isStdinPiped(): boolean {\n try {\n const stats = fstatSync(0)\n return stats.isFIFO() || stats.isFile() || stats.isSocket()\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * Reads all data from stdin and returns it as a string.\n * This is useful for commands that accept input via piping.\n *\n * @example\n * // Usage: echo \"your query\" | shopify app execute\n * const query = await readStdin()\n *\n * @returns A promise that resolves with the stdin content, or undefined if stdin is a TTY.\n */\nexport async function readStdinString(): Promise<string | undefined> {\n if (!isStdinPiped()) {\n return undefined\n }\n\n let data = ''\n let totalSize = 0\n process.stdin.setEncoding('utf8')\n for await (const chunk of process.stdin) {\n const chunkString = String(chunk)\n totalSize += Buffer.byteLength(chunkString, 'utf8')\n if (totalSize > MAX_STDIN_SIZE) {\n throw new AbortError('Stdin input exceeded the maximum allowed size.')\n }\n data += chunkString\n }\n return data.trim()\n}\n"]}
|
|
@@ -34,6 +34,15 @@ export declare function metafieldDefinitionsByOwnerType(type: MetafieldOwnerType
|
|
|
34
34
|
};
|
|
35
35
|
}[]>;
|
|
36
36
|
export declare function passwordProtected(session: AdminSession): Promise<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* Whether the error ends a Trust Battery challenge on a theme request. A caller that
|
|
39
|
+
* retries theme requests must rethrow it, or the user is asked to verify again for
|
|
40
|
+
* each attempt.
|
|
41
|
+
*
|
|
42
|
+
* @param error - The error to check.
|
|
43
|
+
* @returns True when the error ends a Trust Battery challenge.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isTrustChallengeError(error: unknown): boolean;
|
|
37
46
|
type OnlineStoreThemeFileBody = {
|
|
38
47
|
__typename: 'OnlineStoreThemeFileBodyBase64';
|
|
39
48
|
contentBase64: string;
|