Skip to content

Add shopify store execute command#7064

Draft
nickwesselman wants to merge 3 commits intonw/refactor-execute-shared-logicfrom
nw/add-store-execute-command
Draft

Add shopify store execute command#7064
nickwesselman wants to merge 3 commits intonw/refactor-execute-shared-logicfrom
nw/add-store-execute-command

Conversation

@nickwesselman
Copy link
Contributor

@nickwesselman nickwesselman commented Mar 20, 2026

Summary

  • Add shopify store execute command that runs Admin API GraphQL operations authenticated as the current user (via ensureAuthenticatedAdmin) instead of as an app
  • No app linking or installation required — only a required --store flag
  • Add storeOperationFlags (same as operationFlags but with store required)
  • Register store:execute command and store oclif topic

Test plan

  • store-execute-operation service tests verify user-token auth, version resolution, and delegation to runGraphQLExecution
  • store/execute command tests verify required --store flag, correct service calls, and flag passthrough
  • shopify store execute --help shows required --store flag and all operation flags
  • Build succeeds, oclif manifest and README regenerated

🤖 Generated with Claude Code

Copy link
Contributor Author

nickwesselman commented Mar 20, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@nickwesselman
Copy link
Contributor Author

/snapit

@github-actions
Copy link
Contributor

🫰✨ Thanks @nickwesselman! Your snapshot has been published to npm.

Test the snapshot by installing your package globally:

npm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20260320170615

Caution

After installing, validate the version by running shopify version in your terminal.
If the versions don't match, you might have multiple global instances installed.
Use which shopify to find out which one you are running and uninstall it.

Copy link
Contributor Author

/snapit

@github-actions
Copy link
Contributor

🫰✨ Thanks @nickwesselman! Your snapshot has been published to npm.

Test the snapshot by installing your package globally:

npm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20260320194206

Caution

After installing, validate the version by running shopify version in your terminal.
If the versions don't match, you might have multiple global instances installed.
Use which shopify to find out which one you are running and uninstall it.

nickwesselman and others added 3 commits March 20, 2026 17:13
Adds a new `store execute` command that executes Admin API GraphQL
operations authenticated as the current user (via `ensureAuthenticatedAdmin`)
rather than as an app. This doesn't require an app to be linked or
installed — only a `--store` flag (required).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nickwesselman nickwesselman force-pushed the nw/add-store-execute-command branch from fc479a4 to ab8c4f6 Compare March 20, 2026 21:25
@nickwesselman nickwesselman force-pushed the nw/refactor-execute-shared-logic branch from aed01f6 to 12077ed Compare March 20, 2026 21:25
@github-actions
Copy link
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/private/node/conf-store.d.ts
@@ -18,12 +18,20 @@ interface Cache {
     [mostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>;
     [rateLimitKey: RateLimitKey]: CacheValue<number[]>;
 }
+export interface PendingDeviceAuth {
+    deviceCode: string;
+    interval: number;
+    expiresAt: number;
+    verificationUriComplete: string;
+    scopes: string[];
+}
 export interface ConfSchema {
     sessionStore: string;
     currentSessionId?: string;
     devSessionStore?: string;
     currentDevSessionId?: string;
     cache?: Cache;
+    pendingDeviceAuth?: PendingDeviceAuth;
 }
 /**
  * Get session.
@@ -57,6 +65,18 @@ export declare function setCurrentSessionId(sessionId: string, config?: LocalSto
  * Remove current session ID.
  */
 export declare function removeCurrentSessionId(config?: LocalStorage<ConfSchema>): void;
+/**
+ * Get pending device auth state (used for non-interactive login flow).
+ */
+export declare function getPendingDeviceAuth(config?: LocalStorage<ConfSchema>): PendingDeviceAuth | undefined;
+/**
+ * Stash pending device auth state for later resumption.
+ */
+export declare function setPendingDeviceAuth(auth: PendingDeviceAuth, config?: LocalStorage<ConfSchema>): void;
+/**
+ * Clear pending device auth state.
+ */
+export declare function clearPendingDeviceAuth(config?: LocalStorage<ConfSchema>): void;
 type CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['value'];
 /**
  * Fetch from cache, or run the provided function to get the value, and cache it
packages/cli-kit/dist/private/node/session.d.ts
@@ -1,3 +1,4 @@
+import { IdentityToken, Session } from './session/schema.js';
 import { AdminSession } from '../../public/node/session.js';
 /**
  * A scope supported by the Shopify Admin API.
@@ -104,4 +105,9 @@ export interface EnsureAuthenticatedAdditionalOptions {
  * @returns An instance with the access tokens organized by application.
  */
 export declare function ensureAuthenticated(applications: OAuthApplications, _env?: NodeJS.ProcessEnv, { forceRefresh, noPrompt, forceNewSession }?: EnsureAuthenticatedAdditionalOptions): Promise<OAuthSession>;
+/**
+ * Given an identity token, exchange it for application tokens and build a complete session.
+ * Shared between the interactive login flow and the --resume non-interactive flow.
+ */
+export declare function completeAuthFlow(identityToken: IdentityToken, applications: OAuthApplications): Promise<Session>;
 export {};
\ No newline at end of file
packages/cli-kit/dist/public/node/session.d.ts
@@ -116,12 +116,53 @@ export declare function ensureAuthenticatedThemes(store: string, password: strin
  * @returns The access token for the Business Platform API.
  */
 export declare function ensureAuthenticatedBusinessPlatform(scopes?: BusinessPlatformScope[]): Promise<string>;
+/**
+ * Returns info about the currently logged-in user, or undefined if not logged in.
+ * Does not trigger any authentication flow.
+ *
+ * @returns The current user's alias, or undefined if not logged in.
+ */
+export declare function getCurrentUserInfo(): Promise<{
+    alias: string;
+} | undefined>;
 /**
  * Logout from Shopify.
  *
  * @returns A promise that resolves when the logout is complete.
  */
 export declare function logout(): Promise<void>;
+/**
+ * Start the device authorization flow without polling.
+ * Stashes the device code for later resumption via .
+ *
+ * @returns The verification URL the user must visit to authorize.
+ */
+export declare function startDeviceAuthNoPolling(): Promise<{
+    verificationUriComplete: string;
+}>;
+export type ResumeDeviceAuthResult = {
+    status: 'success';
+    alias: string;
+} | {
+    status: 'pending';
+    verificationUriComplete: string;
+} | {
+    status: 'expired';
+    message: string;
+} | {
+    status: 'denied';
+    message: string;
+} | {
+    status: 'no_pending';
+    message: string;
+};
+/**
+ * Resume a previously started device authorization flow.
+ * Exchanges the stashed device code for tokens and stores the session.
+ *
+ * @returns The result of the resume attempt.
+ */
+export declare function resumeDeviceAuth(): Promise<ResumeDeviceAuthResult>;
 /**
  * Ensure that we have a valid Admin session for the given store, with access on behalf of the app.
  *
packages/cli-kit/dist/private/node/session/device-authorization.d.ts
@@ -15,9 +15,12 @@ export interface DeviceAuthorizationResponse {
  * Also returns a  used for polling the token endpoint in the next step.
  *
  * @param scopes - The scopes to request
+ * @param options - Optional settings. Pass  to print the URL without waiting for keypress or opening a browser.
  * @returns An object with the device authorization response.
  */
-export declare function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse>;
+export declare function requestDeviceAuthorization(scopes: string[], { noPrompt }?: {
+    noPrompt?: boolean;
+}): Promise<DeviceAuthorizationResponse>;
 /**
  * Poll the Oauth token endpoint with the device code obtained from a DeviceAuthorizationResponse.
  * The endpoint will return  until the user completes the auth flow in the browser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant