Skip to content

Fail fast when the store auth URL is withheld - #8446

Merged
dengjeffrey merged 1 commit into
redact-store-auth-manual-urlfrom
craigmartin/store-auth-abort-without-browser
Aug 31, 2026
Merged

Fail fast when the store auth URL is withheld#8446
dengjeffrey merged 1 commit into
redact-store-auth-manual-urlfrom
craigmartin/store-auth-abort-without-browser

Conversation

@craigmichaelmartin

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

One commit for #8427, kept separate so it can be squashed in rather than pushed over an approved branch. Base is redact-store-auth-manual-url.

#8427 stops printing the manual authorization URL when it carries the signup credential, which is right. But withholding the URL leaves the browser with nothing to open, and the code still returns into waitForStoreAuthCode's onListening and waits. callback.ts:222 discards the fulfilled value, so nothing settles the promise. The command sits idle for the full timeoutMs = 5 * 60 * 1000 (callback.ts:100) and then fails with Timed out waiting for OAuth callback.

So on #8427 as it stands, shopify store stripe-auth in any environment without a browser prints "run this command again in an environment where Shopify CLI can open a browser automatically" and then hangs for five minutes before erroring. There is no escape hatch — --verbose doesn't reveal the URL either, since pkce.ts only debug-logs the store, scopes and redirect_uri.

It is unconditional wherever openURL returns false, which includes:

  • Codespaces, Gitpod, Cloud ShellopenURL returns false at system.ts:57 via isCloudEnvironment() without attempting to open anything.
  • plain SSH sessions and headless hosts, where open/xdg-open fails and openURL catches it.

--signup is required: true on this branch, so every stripe-auth invocation reaches the branch.

Before this commit the behaviour is a trade — no leak, but no authentication either. After it, the user gets an immediate error instead of a five-minute wait.

WHAT is this pull request doing?

onListening: async () => {
  const opened = await resolvedDependencies.openURL(authorizationUrl)
  if (opened) return

  const sensitive = Boolean(input.signup)
  resolvedDependencies.presenter.manualAuthUrl(authorizationUrl, {sensitive})

  if (sensitive) throw new AbortError("Authentication can't continue without a browser.")
},

Throwing from onListening is already handled: callback.ts:222 catches it and routes it through settleWithError, which closes the server and rejects with the AbortError. Follows the environment-refusal pattern at private/node/session/device-authorization.ts:74-79.

Deliberately small:

  • The presenter is untouched. It keeps explaining why the URL was withheld and what to do; the AbortError only states the outcome, so the guidance isn't repeated. Your sensitive option and its result.ts behaviour are unchanged.
  • The non-signup path is unchanged — the URL still prints and the command still waits, which is correct there because the user can act on it. Covered by the existing shows a manual auth URL when the browser does not open automatically test, still passing.
  • It composes with Read store signup JWT from stdin #8428. Once the loopback handoff lands, the URL handed to the presenter is the credential-free handoff URL and sensitive is false, so this abort doesn't fire and the headless path works again. Nothing to unwind later.

One existing test had to change: authenticateStoreWithApp marks manual auth URL as sensitive when signup JWT is present now awaits a rejection instead of a return. Its manualAuthUrl assertion is intact.

How to test your changes?

pnpm vitest run packages/store/src/cli/services/store/auth/index.test.ts

Both affected tests fail without the index.ts change (verified by reverting it in isolation) and pass with it. Full packages/store: 374 passed / 55 files. eslint and prettier --check clean on both files; nx run store:type-check 0 errors.

Expect the same inherited CI failures as #8427Check OCLIF manifests (dies on Cannot find module bin/check-commands-snapshot.js, added to main after this branch was cut) and Check graphql-codegen, plus the E2E jobs, which are not required checks. Neither is caused by this commit; both clear on rebase. This branch changes no command or flag metadata, so it needs no manifest regeneration.

Post-release steps

None.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows) — the change is control flow around an existing openURL result; if anything it helps Windows and headless Linux, where open is likelier to fail
  • I've considered possible documentation changes — none; store stripe-auth is hidden and no command or flag metadata changes
  • I've considered analytics changes to measure impact — none. The command now exits non-zero promptly instead of after a timeout, so cmd_all_exit shifts from a timeout abort to this abort for the affected runs.
  • The change is user-facing — no changeset, consistent with Avoid printing sensitive store auth URLs #8427 and Read store signup JWT from stdin #8428, which add none for this hidden command

Withholding the URL leaves the browser with nothing to open, so the callback the
local server waits for can never arrive and the command sits idle for the full
five-minute timeout before failing. Abort as soon as the URL is withheld.

This path is unconditional wherever openURL returns false, which includes
Codespaces, Gitpod and Cloud Shell, where it returns false without attempting to
open anything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Assisted-By: devx/39092f35-5041-4a88-ab8d-808c98322495
@craigmichaelmartin
craigmichaelmartin requested a review from a team as a code owner August 31, 2026 18:08
@github-actions github-actions Bot added the no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. label Aug 31, 2026
@github-actions

Copy link
Copy Markdown
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/constants.d.ts
@@ -6,6 +6,7 @@ export declare const environmentVariables: {
     doctor: string;
     enableCliRedirect: string;
     env: string;
+    firstPartyDev: string;
     noAnalytics: string;
     optOutInstrumentation: string;
     appAutomationToken: string;
@@ -30,6 +31,7 @@ export declare const environmentVariables: {
     otelURL: string;
     themeKitAccessDomain: string;
     json: string;
+    neverUsePartnersApi: string;
     skipNetworkLevelRetry: string;
     maxRequestTimeForNetworkCalls: string;
     disableImportScanning: string;
packages/cli-kit/dist/private/node/otel-metrics.d.ts
@@ -2,7 +2,7 @@ import { OtelService } from '../../public/node/vendor/otel-js/service/types.js';
 import { DefaultOtelServiceOptions } from '../../public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js';
 type MetricRecorder = 'console' | {
     type: 'otel';
-    otel: Pick<OtelService, 'getMeterProvider' | 'record'>;
+    otel: Pick<OtelService, 'record'>;
 };
 interface Timing {
     active: number;
packages/cli-kit/dist/private/node/session.d.ts
@@ -90,7 +90,6 @@ export declare function setLastSeenUserIdAfterAuth(id: string): void;
  */
 export declare function getLastSeenAuthMethod(): Promise<AuthMethod>;
 export declare function setLastSeenAuthMethod(method: AuthMethod): void;
-export declare function setCommandSessionId(sessionId: string | undefined): void;
 export interface EnsureAuthenticatedAdditionalOptions {
     noPrompt?: boolean;
     forceRefresh?: boolean;
packages/cli-kit/dist/public/common/object.d.ts
@@ -38,14 +38,6 @@ export declare function mapValues<T extends object, TResult>(source: T | null |
  * @returns True if the objects are equal, false otherwise.
  */
 export declare function deepCompare(one: object, two: object): boolean;
-/**
- * Deeply compares two values and treats arrays as order-insensitive.
- *
- * @param one - The first value to be compared.
- * @param two - The second value to be compared.
- * @returns True if the normalized values are equal, false otherwise.
- */
-export declare function deepCompareWithOrderInsensitiveArrays(one: unknown, two: unknown): boolean;
 /**
  * Return the difference between two nested objects.
  *
packages/cli-kit/dist/public/common/string.d.ts
@@ -1,4 +1,4 @@
-import type { Token, TokenItem } from '../../private/node/ui/components/token-item.js';
+import { Token, TokenItem } from '../../private/node/ui/components/TokenizedText.js';
 export type RandomNameFamily = 'business' | 'creative';
 /**
  * Generates a random name by combining an adjective and noun.
packages/cli-kit/dist/public/common/version.d.ts
@@ -1 +1 @@
-export declare const CLI_KIT_VERSION = "4.7.0";
\ No newline at end of file
+export declare const CLI_KIT_VERSION = "4.4.0";
\ No newline at end of file
packages/cli-kit/dist/public/node/abort.d.ts
+import { AbortController as NodeAbortController, AbortSignal as NodeAbortControllerSignal } from 'node-abort-controller';
 /**
  * The AbortController interface represents a controller object that allows you to abort one or more Web requests as and when desired.
  *
  * - MDN Documentation: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
  *
- * This class exists to keep the historical `@shopify/cli-kit/node/abort` import path working
- * now that Node provides AbortController natively.
+ * This class is necessary because AbortController support was added to Node 15 and the minimum
+ * version that we support is Node 14.
  */
-export declare class AbortController extends globalThis.AbortController {
+export declare class AbortController extends NodeAbortController {
 }
 /**
  * The AbortSignal interface represents a signal object that allows you to communicate with a DOM request (such as a fetch request) and abort it if required via an AbortController object.
- *
- * Note that AbortSignal cannot be constructed directly. Get one from an AbortController's
- * `signal` property or from the static helpers such as `AbortSignal.timeout()`.
  */
-export declare const AbortSignal: {
-    new (): globalThis.AbortSignal;
-    prototype: globalThis.AbortSignal;
-    abort(reason?: any): globalThis.AbortSignal;
-    any(signals: globalThis.AbortSignal[]): globalThis.AbortSignal;
-    timeout(milliseconds: number): globalThis.AbortSignal;
-};
-export type AbortSignal = globalThis.AbortSignal;
+export declare class AbortSignal extends NodeAbortControllerSignal {
+}
packages/cli-kit/dist/public/node/analytics.d.ts
 import { RuntimeData } from '../../private/node/analytics/storage.js';
 import { Interfaces } from '@oclif/core';
 export type CommandExitMode = 'ok' | 'unexpected_error' | 'expected_error';
 interface ReportAnalyticsEventOptions {
     config: Interfaces.Config;
     errorMessage?: string;
     exitMode: CommandExitMode;
 }
-export declare function sendAnalyticsEventFromStdin(): Promise<void>;
 /**
  * Report an analytics event, sending it off to Monorail -- Shopify's internal analytics service.
  *
  * The payload for an event includes both generic data, and data gathered from installed plug-ins.
  *
  */
 export declare function reportAnalyticsEvent(options: ReportAnalyticsEventOptions): Promise<void>;
 /**
  * Records timing data for performance monitoring. Call twice with the same
  * event name to start and stop timing. First call starts the timer, second
  * call stops it and records the duration.
  *
  * @example
  * ```ts
  *   recordTiming('theme-upload') // Start timing
  *   // ... do work ...
  *   recordTiming('theme-upload') // Stop timing and record duration
  * ```
  *
  * @param eventName - Unique identifier for the timing event
  */
 export declare function recordTiming(eventName: string): void;
 /**
  * Records error information for debugging and monitoring. Use this to track
  * any exceptions or error conditions that occur during theme operations.
  * Errors are automatically categorized for easier analysis.
  *
  * @example
  * ```ts
  *   try {
  *     // ... risky operation ...
  *   } catch (error) {
  *     recordError(error)
  *   }
  * ```
  *
  * @param error - Error object or message to record
  */
 export declare function recordError<T>(error: T): T;
 /**
  * Records retry attempts for network operations. Use this to track when
  * operations are retried due to transient failures. Helps identify
  * problematic endpoints or operations that frequently fail.
  *
  * @example
  * ```ts
  *   recordRetry('https://api.shopify.com/themes', 'upload')
  * ```
  *
  * @param url - The URL or endpoint being retried
  * @param operation - Description of the operation being retried
  */
 export declare function recordRetry(url: string, operation: string): void;
 /**
  * Records custom events for tracking specific user actions or system events.
  * Use this for important milestones, user interactions, or significant
  * state changes in the application.
  *
  * @example
  * ```ts
  *   recordEvent('theme-dev-started')
  *   recordEvent('file-watcher-connected')
  * ```
  *
  * @param eventName - Descriptive name for the event
  */
 export declare function recordEvent(eventName: string): void;
 /**
  * Compiles and returns all runtime analytics data collected during the session.
  * This includes timing measurements, error records, retry attempts, and custom
  * events. Use this to retrieve a complete snapshot of analytics data for
  * reporting or debugging purposes.
  *
  * @example
  * ```ts
  *   const analyticsData = compileData()
  *   console.log(`Recorded ${analyticsData.timings.length} timing events`)
  *   console.log(`Recorded ${analyticsData.errors.length} errors`)
  * ```
  *
  * @returns Object containing all collected analytics data including timings, errors, retries, and events
  */
 export declare function compileData(): RuntimeData;
 export {};
packages/cli-kit/dist/public/node/base-command.d.ts
@@ -2,16 +2,8 @@ import { Command } from '@oclif/core';
 import { OutputFlags, Input, ParserOutput, FlagInput, OutputArgs } from '@oclif/core/parser';
 export type ArgOutput = OutputArgs<any>;
 export type FlagOutput = OutputFlags<any>;
-export interface NonTTYFlagRequirement {
-    /** At least one of these flags must be present when the requirement applies. */
-    flags: string[];
-    /** Determines whether the requirement applies to the parsed flags. */
-    when?: (flags: FlagOutput) => boolean;
-}
 declare abstract class BaseCommand extends Command {
     static baseFlags: FlagInput<{}>;
-    static get requiresSyncAnalytics(): boolean;
-    static nonTTYFlagRequirements(_flags: FlagOutput): NonTTYFlagRequirement[];
     static descriptionWithoutMarkdown(): string | undefined;
     static analyticsNameOverride(): string | undefined;
     static analyticsStopCommand(): string | undefined;
@@ -24,14 +16,11 @@ declare abstract class BaseCommand extends Command {
     protected parse<TFlags extends FlagOutput & {
         path?: string;
         verbose?: boolean;
-        'auth-alias'?: string;
     }, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput>(options?: Input<TFlags, TGlobalFlags, TArgs>, argv?: string[]): Promise<ParserOutput<TFlags, TGlobalFlags, TArgs> & {
         argv: string[];
     }>;
     protected environmentsFilename(): string | undefined;
     protected failMissingNonTTYFlags(flags: FlagOutput, requiredFlags: string[]): void;
-    private failMissingNonTTYFlagRequirements;
-    private applicableNonTTYFlagRequirements;
     private resultWithEnvironment;
     /**
      * Tries to load an environment to forward to the command. If no environment
packages/cli-kit/dist/public/node/cli.d.ts
@@ -39,9 +39,6 @@ export declare const globalFlags: {
 export declare const jsonFlag: {
     json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
 };
-export declare const authAliasFlag: {
-    'auth-alias': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
-};
 /**
  * Builds a  flag that only accepts a valid port number. The flag parses its
  * value as an integer and rejects anything that isn't a whole number between 1 and
@@ -55,19 +52,6 @@ export declare const portFlag: (options?: {
     env?: string;
     hidden?: boolean;
 }) => import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
-/**
- * Marks a flag as required when the CLI cannot prompt for a value.
- *
- * The flag remains optional in interactive terminals. In non-interactive environments,
- *  validates the flag automatically and the requirement is shown in .
- * Use  for conditional or alternative requirements.
- *
- * @param flag - An oclif flag definition.
- * @returns A new flag definition annotated for non-interactive validation and help output.
- */
-export declare function requiredIfNonInteractive<TFlag extends {
-    description?: string;
-}>(flag: TFlag): TFlag;
 /**
  * Clear the CLI cache, used to store some API responses and handle notifications status
  */
packages/cli-kit/dist/public/node/environment.d.ts
@@ -45,6 +45,12 @@ export declare function getIdentityTokenInformation(): {
  * @returns True if the JSON output is enabled, false otherwise.
  */
 export declare function jsonOutputEnabled(environment?: NodeJS.ProcessEnv): boolean;
+/**
+ * If true, the CLI should not use the Partners API.
+ *
+ * @returns True when the CLI should not use the Partners API.
+ */
+export declare function blockPartnersAccess(): boolean;
 /**
  * If true, the CLI should not use the network level retry.
  *
packages/cli-kit/dist/public/node/error.d.ts
@@ -1,6 +1,7 @@
 import { OutputMessage } from './output.js';
-import { type InlineToken, type TokenItem } from '../../private/node/ui/components/token-item.js';
+import { InlineToken, TokenItem } from '../../private/node/ui/components/TokenizedText.js';
 import type { AlertCustomSection } from './ui.js';
+export { ExtendableError } from 'ts-error';
 export declare enum FatalErrorType {
     Abort = 0,
     AbortSilent = 1,
@@ -37,6 +38,8 @@ export declare abstract class FatalError extends Error {
  * Those usually represent unexpected scenarios that we can't handle and that usually require some action from the developer.
  */
 export declare class AbortError extends FatalError {
+    nextSteps?: TokenItem<InlineToken>[];
+    customSections?: AlertCustomSection[];
     constructor(message: TokenItem | OutputMessage, tryMessage?: TokenItem | OutputMessage | null, nextSteps?: TokenItem<InlineToken>[], customSections?: AlertCustomSection[]);
 }
 /**
packages/cli-kit/dist/public/node/metadata.d.ts
@@ -42,7 +42,6 @@ declare const coreData: RuntimeMetadataManager<CmdFieldsFromMonorail, {
         startCommand: string;
         startTopic?: string;
         startArgs: string[];
-        requiresSyncAnalytics?: boolean;
     };
 } & {
     environmentFlags: string;
@@ -64,7 +63,6 @@ export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>,
         startCommand: string;
         startTopic?: string;
         startArgs: string[];
-        requiresSyncAnalytics?: boolean;
     };
 } & {
     environmentFlags: string;
@@ -85,7 +83,6 @@ export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>,
         startCommand: string;
         startTopic?: string;
         startArgs: string[];
-        requiresSyncAnalytics?: boolean;
     };
 } & {
     environmentFlags: string;
packages/cli-kit/dist/public/node/session.d.ts
@@ -22,19 +22,6 @@ export type AccountInfo = UserAccountInfo | ServiceAccountInfo | UnknownAccountI
  * @param userId - User identifier to report on the command analytics event.
  */
 export declare function setLastSeenUserId(userId: string): void;
-/**
- * Finds a stored Shopify account session by alias without changing the current session.
- *
- * @param alias - The account alias to find.
- * @returns The matching session ID, or undefined if no session matches.
- */
-export declare function findSessionIdByAlias(alias: string): Promise<string | undefined>;
-/**
- * Selects a stored Shopify account session by alias for the current command process.
- *
- * @param alias - The account alias to select. Passing undefined clears the command selection.
- */
-export declare function setCurrentSessionAlias(alias?: string): Promise<void>;
 interface UserAccountInfo {
     type: 'UserAccount';
     email: string;
packages/cli-kit/dist/public/node/system.d.ts
@@ -105,25 +105,12 @@ export declare function terminalSupportsPrompting(): boolean;
  * @returns True if the current environment is a CI environment.
  */
 export declare function isCI(): boolean;
-interface WslDetectionOverrides {
-    platform?: NodeJS.Platform;
-    kernelRelease?: string;
-    procVersion?: string;
-    insideContainer?: boolean;
-}
 /**
  * Check if the current environment is a WSL environment.
  *
- * @param overrides - Detection inputs, read from the system when not provided. Intended for tests.
  * @returns True if the current environment is a WSL environment.
  */
-export declare function isWsl(overrides?: WslDetectionOverrides): Promise<boolean>;
-/**
- * Check if the current process is running inside a container.
- *
- * @returns True if the current process is running inside a container.
- */
-export declare function isInsideContainer(): boolean;
+export declare function isWsl(): Promise<boolean>;
 /**
  * Check if stdin has piped data available.
  * This distinguishes between actual piped input (e.g., )
@@ -142,5 +129,4 @@ export declare function isStdinPiped(): boolean;
  *
  * @returns A promise that resolves with the stdin content, or undefined if stdin is a TTY.
  */
-export declare function readStdinString(): Promise<string | undefined>;
-export {};
\ No newline at end of file
+export declare function readStdinString(): Promise<string | undefined>;
\ No newline at end of file
packages/cli-kit/dist/public/node/ui.d.ts
@@ -6,7 +6,7 @@ import { AlertOptions } from '../../private/node/ui/alert.js';
 import { CustomSection } from '../../private/node/ui/components/Alert.js';
 import ScalarDict from '../../private/node/ui/components/Table/ScalarDict.js';
 import { TableColumn, TableProps } from '../../private/node/ui/components/Table/Table.js';
-import { type InlineToken, type LinkToken, type ListToken, type Token, type TokenItem } from '../../private/node/ui/components/token-item.js';
+import { Token, InlineToken, LinkToken, ListToken, TokenItem } from '../../private/node/ui/components/TokenizedText.js';
 import { DangerousConfirmationPromptProps } from '../../private/node/ui/components/DangerousConfirmationPrompt.js';
 import { SelectPromptProps } from '../../private/node/ui/components/SelectPrompt.js';
 import { Task } from '../../private/node/ui/components/Tasks.js';
packages/cli-kit/dist/private/node/analytics/graphql-error-codes.d.ts
@@ -21,8 +21,8 @@ export declare function graphQLErrorCodes(errors: unknown): string[];
 /**
  * Whether a single code is a rate-limit signal ( or ).
  *
- * Shared with the retry path ( in ), where these codes signal
- * rate limiting even at HTTP 200.
+ * Mirrors the established shape detected by  in ,
+ * where  signals rate limiting even at HTTP 200.
  */
 export declare function isRateLimitCode(code: string | undefined): boolean;
 /**
packages/cli-kit/dist/private/node/session/exchange.d.ts
@@ -1,9 +1,10 @@
 import { ApplicationToken, IdentityToken } from './schema.js';
 import { API } from '../api.js';
 import { Result } from '../../../public/node/result.js';
-export declare class InvalidGrantError extends Error {
+import { ExtendableError } from '../../../public/node/error.js';
+export declare class InvalidGrantError extends ExtendableError {
 }
-export declare class InvalidRequestError extends Error {
+export declare class InvalidRequestError extends ExtendableError {
 }
 export interface ExchangeScopes {
     admin: string[];
@@ -51,8 +52,7 @@ export declare function exchangeAppAutomationTokenForBusinessPlatformAccessToken
     accessToken: string;
     userId: string;
 }>;
-declare const identityDeviceErrors: readonly ["authorization_pending", "access_denied", "expired_token", "slow_down", "unknown_failure"];
-type IdentityDeviceError = (typeof identityDeviceErrors)[number];
+type IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure';
 /**
  * Given a deviceCode obtained after starting a device identity flow, request an identity token.
  * @param deviceCode - The device code obtained after starting a device identity flow
packages/cli-kit/dist/private/node/ui/utilities.d.ts
@@ -1,16 +1,16 @@
-import { type TokenItem } from './components/token-item.js';
-export declare function messageWithPunctuation(message: TokenItem): string | import("./components/token-item.js").LinkToken | import("./components/token-item.js").UserInputToken | import("./components/token-item.js").ListToken | {
+import { TokenItem } from './components/TokenizedText.js';
+export declare function messageWithPunctuation(message: TokenItem): string | {
     command: string;
-} | {
+} | import("./components/TokenizedText.js").LinkToken | {
     char: string;
-} | {
+} | import("./components/TokenizedText.js").UserInputToken | {
     subdued: string;
 } | {
     filePath: string;
-} | import("./components/token-item.js").BoldToken | {
+} | import("./components/TokenizedText.js").ListToken | import("./components/TokenizedText.js").BoldToken | {
     info: string;
 } | {
     warn: string;
 } | {
     error: string;
-} | import("./components/token-item.js").Token[];
\ No newline at end of file
+} | import("./components/TokenizedText.js").Token[];
\ No newline at end of file
packages/cli-kit/dist/public/node/api/partners.d.ts
@@ -1,5 +1,7 @@
 import { GraphQLVariables, GraphQLResponse, CacheOptions, UnauthorizedHandler } from './graphql.js';
 import { RequestModeInput } from '../http.js';
+import { Variables } from 'graphql-request';
+import { TypedDocumentNode } from '@graphql-typed-document-node/core';
 /**
  * Executes a GraphQL query against the Partners API.
  *
@@ -12,6 +14,21 @@ import { RequestModeInput } from '../http.js';
  * @returns The response of the query of generic type <T>.
  */
 export declare function partnersRequest<T>(query: string, token: string, variables?: GraphQLVariables, cacheOptions?: CacheOptions, preferredBehaviour?: RequestModeInput, unauthorizedHandler?: UnauthorizedHandler): Promise<T>;
+export declare const generateFetchAppLogUrl: (cursor?: string, filters?: {
+    status?: string;
+    source?: string;
+}) => Promise<string>;
+/**
+ * Executes a GraphQL query against the Partners API. Uses typed documents.
+ *
+ * @param query - GraphQL query to execute.
+ * @param token - Partners token.
+ * @param variables - GraphQL variables to pass to the query.
+ * @param preferredBehaviour - Preferred behaviour for the request.
+ * @param unauthorizedHandler - Optional handler for unauthorized requests.
+ * @returns The response of the query of generic type <TResult>.
+ */
+export declare function partnersRequestDoc<TResult, TVariables extends Variables>(query: TypedDocumentNode<TResult, TVariables>, token: string, variables?: TVariables, preferredBehaviour?: RequestModeInput, unauthorizedHandler?: UnauthorizedHandler): Promise<TResult>;
 /**
  * Sets the next deprecation date from [GraphQL response extensions](https://www.apollographql.com/docs/resources/graphql-glossary/#extensions)
  * if  objects contain a  (ISO 8601-formatted string).
packages/cli-kit/dist/public/node/context/local.d.ts
@@ -63,6 +63,13 @@ export declare function alwaysLogAnalytics(env?: NodeJS.ProcessEnv): boolean;
  * @returns True if SHOPIFY_CLI_ALWAYS_LOG_METRICS is truthy.
  */
 export declare function alwaysLogMetrics(env?: NodeJS.ProcessEnv): boolean;
+/**
+ * Returns true if the CLI User is 1P.
+ *
+ * @param env - The environment variables from the environment of the current process.
+ * @returns True if SHOPIFY_CLI_1P is truthy.
+ */
+export declare function firstPartyDev(env?: NodeJS.ProcessEnv): boolean;
 /**
  * Returns true if the CLI can run the "doctor-release" command.
  *
@@ -141,9 +148,7 @@ export declare function ciPlatform(env?: NodeJS.ProcessEnv): {
     metadata?: undefined;
 };
 /**
- * Returns the first mac address found, preferring external interfaces. Returns a random
- * value when no interface has a MAC, so callers hashing it as a device id don't group
- * unrelated devices together.
+ * Returns the first mac address found.
  *
  * @returns Mac address.
  */
packages/cli-kit/dist/public/node/plugins/tunnel.d.ts
@@ -1,3 +1,4 @@
+import { ExtendableError } from '../error.js';
 import { OutputMessage } from '../output.js';
 import { FanoutHookFunction, PluginReturnsForHook } from '../plugins.js';
 import { Result } from '../result.js';
@@ -21,7 +22,7 @@ export type TunnelStatusType = {
     message: TokenItem | OutputMessage;
     tryMessage?: TokenItem | OutputMessage | null;
 };
-export declare class TunnelError extends Error {
+export declare class TunnelError extends ExtendableError {
     type: TunnelErrorType;
     constructor(type: TunnelErrorType, message?: string);
 }
packages/cli-kit/dist/private/node/ui/components/Alert.d.ts
@@ -1,7 +1,7 @@
 import { BannerType } from './Banner.js';
+import { BoldToken, InlineToken, LinkToken, TokenItem } from './TokenizedText.js';
 import { TabularDataProps } from './TabularData.js';
 import { FunctionComponent } from 'react';
-import type { BoldToken, InlineToken, LinkToken, TokenItem } from './token-item.js';
 export interface CustomSection {
     title?: string;
     body: TabularDataProps | TokenItem;
packages/cli-kit/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts
@@ -1,7 +1,7 @@
+import { InlineToken, TokenItem } from './TokenizedText.js';
 import { InfoTableProps } from './Prompts/InfoTable.js';
 import { AbortSignal } from '../../../../public/node/abort.js';
 import { FunctionComponent } from 'react';
-import type { InlineToken, TokenItem } from './token-item.js';
 export interface DangerousConfirmationPromptProps {
     message: string;
     confirmation: string;
packages/cli-kit/dist/private/node/ui/components/List.d.ts
@@ -1,6 +1,6 @@
+import { InlineToken, TokenItem } from './TokenizedText.js';
 import { TextProps } from 'ink';
 import { FunctionComponent } from 'react';
-import type { InlineToken, TokenItem } from './token-item.js';
 export interface CustomListItem {
     type?: string;
     item: TokenItem<InlineToken>;
packages/cli-kit/dist/private/node/ui/components/TabularData.d.ts
@@ -1,4 +1,4 @@
-import { type InlineToken } from './token-item.js';
+import { InlineToken } from './TokenizedText.js';
 import { FunctionComponent } from 'react';
 export interface TabularDataProps {
     tabularData: InlineToken[][];
packages/cli-kit/dist/private/node/ui/components/TextPrompt.d.ts
@@ -1,6 +1,6 @@
+import { InlineToken, TokenItem } from './TokenizedText.js';
 import { AbortSignal } from '../../../../public/node/abort.js';
 import { FunctionComponent } from 'react';
-import type { InlineToken, TokenItem } from './token-item.js';
 export interface TextPromptProps {
     message: TokenItem;
     onSubmit: (value: string) => void;
packages/cli-kit/dist/private/node/ui/components/TokenizedText.d.ts
@@ -1,5 +1,42 @@
 import { FunctionComponent } from 'react';
-import type { TokenItem } from './token-item.js';
+export interface LinkToken {
+    link: {
+        label?: string;
+        url: string;
+    };
+}
+export interface UserInputToken {
+    userInput: string;
+}
+export interface ListToken {
+    list: {
+        title?: TokenItem<InlineToken>;
+        items: TokenItem<InlineToken>[];
+        ordered?: boolean;
+    };
+}
+export interface BoldToken {
+    bold: string;
+}
+export type Token = string | {
+    command: string;
+} | LinkToken | {
+    char: string;
+} | UserInputToken | {
+    subdued: string;
+} | {
+    filePath: string;
+} | ListToken | BoldToken | {
+    info: string;
+} | {
+    warn: string;
+} | {
+    error: string;
+};
+export type InlineToken = Exclude<Token, ListToken>;
+export type TokenItem<T extends Token = Token> = T | T[];
+export declare function tokenItemToString(token: TokenItem): string;
+export declare function appendToTokenItem(token: TokenItem, suffix: string): TokenItem;
 interface TokenizedTextProps {
     item: TokenItem;
 }
packages/cli-kit/dist/private/node/ui/components/Prompts/InfoMessage.d.ts
@@ -1,6 +1,6 @@
+import { InlineToken, LinkToken, TokenItem, UserInputToken } from '../TokenizedText.js';
 import { TextProps } from 'ink';
 import { FunctionComponent } from 'react';
-import type { InlineToken, LinkToken, TokenItem, UserInputToken } from '../token-item.js';
 export interface InfoMessageProps {
     message: {
         title: {
packages/cli-kit/dist/private/node/ui/components/Prompts/InfoTable.d.ts
@@ -1,7 +1,7 @@
 import { CustomListItem } from '../List.js';
+import { InlineToken, TokenItem } from '../TokenizedText.js';
 import { TextProps } from 'ink';
 import { FunctionComponent } from 'react';
-import type { InlineToken, TokenItem } from '../token-item.js';
 type Items = (TokenItem<InlineToken> | CustomListItem)[];
 export interface InfoTableSection {
     color?: TextProps['color'];
packages/cli-kit/dist/private/node/ui/components/Prompts/PromptLayout.d.ts
@@ -1,9 +1,9 @@
 import { InfoTableProps } from './InfoTable.js';
 import { InfoMessageProps } from './InfoMessage.js';
+import { InlineToken, LinkToken, TokenItem } from '../TokenizedText.js';
 import { AbortSignal } from '../../../../../public/node/abort.js';
 import { PromptState } from '../../hooks/use-prompt.js';
 import { ReactElement } from 'react';
-import type { InlineToken, LinkToken, TokenItem } from '../token-item.js';
 export type Message = TokenItem<Exclude<InlineToken, LinkToken>>;
 interface PromptLayoutProps {
     message: Message;
packages/cli-kit/dist/public/node/vendor/otel-js/service/types.d.ts
@@ -1,5 +1,5 @@
-import type { Counter, Histogram, MetricAttributes, MetricOptions, UpDownCounter } from '@opentelemetry/api';
-import type { MeterProvider, ViewOptions } from '@opentelemetry/sdk-metrics';
+import type { Counter, Histogram, MeterProvider, MetricAttributes, MetricOptions, UpDownCounter } from '@opentelemetry/api';
+import type { ViewOptions } from '@opentelemetry/sdk-metrics';
 export type CustomMetricLabels<TLabels extends Record<TKeys, MetricAttributes>, TKeys extends string = keyof TLabels & string> = {
     [P in TKeys]: TLabels[P] extends MetricAttributes ? TLabels[P] : never;
 };

@dengjeffrey
dengjeffrey merged commit ad4b791 into redact-store-auth-manual-url Aug 31, 2026
24 of 28 checks passed
@dengjeffrey
dengjeffrey deleted the craigmartin/store-auth-abort-without-browser branch August 31, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants