Refactor: extract shared GraphQL execution logic#7063
Draft
nickwesselman wants to merge 2 commits intonw/agent-compatible-device-authfrom
Draft
Refactor: extract shared GraphQL execution logic#7063nickwesselman wants to merge 2 commits intonw/agent-compatible-device-authfrom
nickwesselman wants to merge 2 commits intonw/agent-compatible-device-authfrom
Conversation
Contributor
Author
|
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.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
This was referenced Mar 20, 2026
088b8e3 to
aed01f6
Compare
6 tasks
aed01f6 to
12077ed
Compare
Extract `runGraphQLExecution` from `executeOperation` to enable reuse by both app-authenticated and user-authenticated execution paths. Extract `loadQuery` from `prepareExecuteContext` for standalone query loading without app context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove export from parseVariables and RunGraphQLExecutionInput since they are only used internally. Fix prettier multiline formatting in tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
12077ed to
884667a
Compare
ae3f293 to
d0f409a
Compare
Contributor
Differences in type declarationsWe 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:
New type declarationsWe found no new type declarations in this PR Existing type declarationspackages/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.
packages/cli-kit/dist/private/node/ui/components/SingleTask.d.ts@@ -4,8 +4,9 @@ interface SingleTaskProps<T> {
title: TokenizedString;
task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
onComplete?: (result: T) => void;
+ onError?: (error: Error) => void;
onAbort?: () => void;
noColor?: boolean;
}
-declare const SingleTask: <T>({ task, title, onComplete, onAbort, noColor }: SingleTaskProps<T>) => React.JSX.Element | null;
+declare const SingleTask: <T>({ task, title, onComplete, onError, onAbort, noColor }: SingleTaskProps<T>) => React.JSX.Element | null;
export { SingleTask };
\ No newline at end of file
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
runGraphQLExecutionfromexecuteOperationso the GraphQL execution core (variable parsing, single-operation validation, request, output handling) can be reused by different auth pathsloadQueryfromprepareExecuteContextfor standalone query loading without app contextexecuteOperationnow authenticates, validates mutation store type, then delegates torunGraphQLExecutionTest plan
executeOperationtests pass unchanged (behavior preserved)runGraphQLExecutionunit tests cover execution, variable parsing, output file writing, and error handlingloadQueryunit tests cover flag/file loading, empty validation, and GraphQL syntax validation🤖 Generated with Claude Code