Skip to content

PoC: typed result contract for app:function:info - #8288

Draft
gonzaloriestra wants to merge 1 commit into
donald/store-execute-result-contract-pocfrom
gonzalo/function-info-result-contract-poc
Draft

PoC: typed result contract for app:function:info#8288
gonzaloriestra wants to merge 1 commit into
donald/store-execute-result-contract-pocfrom
gonzalo/function-info-result-contract-poc

Conversation

@gonzaloriestra

Copy link
Copy Markdown
Contributor

Why

Extend the result/formatting split prototype to a finite single-object command with optional fields and dynamic targeting keys.

What changed

  • return a typed FunctionInfoResult independently from presentation
  • validate JSON output against the Zod schema used to infer the result type
  • automatically include FunctionInfoResult and FunctionTargeting in command help
  • preserve the existing human-readable output

Testing

  • pnpm --filter @shopify/app vitest run src/cli/services/function/info.test.ts src/cli/services/function/info-result.test.ts src/cli/services/function/info-types.test.ts src/cli/commands/app/function/info.test.ts
  • pnpm --filter @shopify/app type-check
  • ESLint on changed TypeScript files
  • pnpm refresh-manifests
  • node packages/cli/bin/run.js app function info --help

Stacked on #8243.

Copy link
Copy Markdown
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.
Learn more

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

@gonzaloriestra gonzaloriestra changed the title Add app function info result contract PoC: Add app function info result contract Aug 10, 2026
@gonzaloriestra gonzaloriestra changed the title PoC: Add app function info result contract PoC: typed result contract for app function info Aug 10, 2026
@gonzaloriestra gonzaloriestra changed the title PoC: typed result contract for app function info PoC: typed result contract for app:function:info Aug 10, 2026
@gonzaloriestra
gonzaloriestra force-pushed the donald/store-execute-result-contract-poc branch from 58006ef to 25b099a Compare August 10, 2026 12:21
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/function-info-result-contract-poc branch from 8d154c3 to b7582e7 Compare August 10, 2026 12:21

Copy link
Copy Markdown
Contributor Author

/snapit

@github-actions

Copy link
Copy Markdown
Contributor

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

Test the snapshot by installing your package globally:

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

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.

@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

packages/cli-kit/dist/public/node/json-output-schema.d.ts
import { ZodTypeAny, type z } from 'zod';
export interface JsonOutputSchema<TSchema extends ZodTypeAny = ZodTypeAny> {
    readonly name: string;
    readonly schema: TSchema;
    readonly definitions: Readonly<Record<string, ZodTypeAny>>;
}
export type InferJsonOutputSchema<TOutputSchema extends JsonOutputSchema> = z.infer<TOutputSchema['schema']>;
interface DefineJsonOutputSchemaOptions<TSchema extends ZodTypeAny> {
    name: string;
    schema: TSchema;
    definitions?: Readonly<Record<string, ZodTypeAny>>;
}
/**
 * Defines the runtime schema and named types for a command's JSON output.
 *
 * @param options - The root schema name, schema, and any named nested schemas.
 * @returns Command metadata that can also be used to infer and validate the output type.
 */
export declare function defineJsonOutputSchema<TSchema extends ZodTypeAny>(options: DefineJsonOutputSchemaOptions<TSchema>): JsonOutputSchema<TSchema>;
/**
 * Renders a command JSON output schema as TypeScript interfaces for help text.
 *
 * @param outputSchema - The command's JSON output schema metadata.
 * @returns TypeScript interfaces describing the command's JSON output.
 */
export declare function renderJsonOutputSchema(outputSchema: JsonOutputSchema): string;
export {};

Existing type declarations

packages/cli-kit/dist/public/node/abort.d.ts
@@ -1,24 +1,16 @@
+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;
\ No newline at end of file
+export declare class AbortSignal extends NodeAbortControllerSignal {
+}
\ No newline at end of file
packages/cli-kit/dist/public/node/base-command.d.ts
@@ -1,3 +1,4 @@
+import { type JsonOutputSchema } from './json-output-schema.js';
 import { Command } from '@oclif/core';
 import { OutputFlags, Input, ParserOutput, FlagInput, OutputArgs } from '@oclif/core/parser';
 export type ArgOutput = OutputArgs<any>;
@@ -10,6 +11,8 @@ export interface NonTTYFlagRequirement {
 }
 declare abstract class BaseCommand extends Command {
     static baseFlags: FlagInput<{}>;
+    static descriptionWithMarkdown?: string;
+    static get jsonOutputSchema(): JsonOutputSchema | undefined;
     static nonTTYFlagRequirements(_flags: FlagOutput): NonTTYFlagRequirement[];
     static descriptionWithoutMarkdown(): string | undefined;
     static analyticsNameOverride(): string | undefined;
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 type { AlertCustomSection } from './ui.js';
+export { ExtendableError } from 'ts-error';
 export declare enum FatalErrorType {
     Abort = 0,
     AbortSilent = 1,
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[];
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);
 }

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

Labels

Area: @shopify/app @shopify/app package issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant