Skip to content

Add command side event infrastructure - #8403

Draft
gonzaloriestra wants to merge 4 commits into
mainfrom
gonzalo/json-side-events-infrastructure
Draft

Add command side event infrastructure#8403
gonzaloriestra wants to merge 4 commits into
mainfrom
gonzalo/json-side-events-infrastructure

Conversation

@gonzaloriestra

@gonzaloriestra gonzaloriestra commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

Closes shop/issues-develop#23661

Finite commands need structured diagnostics and progress that remain separate from their final result.

Based on prototypes:

WHAT is this pull request doing?

  • Adds typed diagnostic and progress events with timestamps.
  • Adds a single-sink, execution-scoped channel.
  • Adds a stderr renderer using the existing CLI output behavior.
  • Leaves command migrations out of scope.

How to test your changes?

  1. Run pnpm vitest run packages/cli-kit/src/public/common/finite-command-events.test.ts packages/cli-kit/src/public/node/finite-command-events.test.ts.
  2. Run pnpm --filter @shopify/cli-kit type-check.
  3. Run pnpm --filter @shopify/cli-kit lint.

Checklist

  • Cross-platform impacts considered (Mac, Linux, Windows)
  • Documentation changes considered
  • Analytics changes considered
  • The change is user-facing and has a changeset

@github-actions github-actions Bot added the Area: @shopify/cli @shopify/cli package issues label Aug 26, 2026
@gonzaloriestra gonzaloriestra changed the title Add finite command side event infrastructure Add command side event infrastructure Aug 27, 2026
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/json-side-events-infrastructure branch from 0384ef4 to 405cbbd Compare August 27, 2026 12:44
@gonzaloriestra
gonzaloriestra force-pushed the gonzalo/json-side-events-infrastructure branch from 405cbbd to 7e68be2 Compare August 27, 2026 13:47
@github-actions github-actions Bot added no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. and removed Area: @shopify/cli @shopify/cli package issues labels Aug 27, 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

packages/cli-kit/dist/public/common/command-events.d.ts
import { z } from 'zod';
/** Schema for a diagnostic emitted while a command executes. */
export declare const commandDiagnosticEventSchema: z.ZodObject<{
    type: z.ZodLiteral<"diagnostic">;
    timestamp: z.ZodString;
    level: z.ZodEnum<["debug", "info", "warning"]>;
    message: z.ZodString;
    code: z.ZodOptional<z.ZodString>;
}, "strict", z.ZodTypeAny, {
    type: "diagnostic";
    message: string;
    timestamp: string;
    level: "info" | "warning" | "debug";
    code?: string | undefined;
}, {
    type: "diagnostic";
    message: string;
    timestamp: string;
    level: "info" | "warning" | "debug";
    code?: string | undefined;
}>;
/** Schema for a progress update emitted while a command executes. */
export declare const commandProgressEventSchema: z.ZodObject<{
    type: z.ZodLiteral<"progress">;
    timestamp: z.ZodString;
    message: z.ZodString;
    current: z.ZodOptional<z.ZodNumber>;
    total: z.ZodOptional<z.ZodNumber>;
}, "strict", z.ZodTypeAny, {
    type: "progress";
    message: string;
    timestamp: string;
    current?: number | undefined;
    total?: number | undefined;
}, {
    type: "progress";
    message: string;
    timestamp: string;
    current?: number | undefined;
    total?: number | undefined;
}>;
/** Schema for side events emitted while a command executes. */
export declare const commandEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
    type: z.ZodLiteral<"diagnostic">;
    timestamp: z.ZodString;
    level: z.ZodEnum<["debug", "info", "warning"]>;
    message: z.ZodString;
    code: z.ZodOptional<z.ZodString>;
}, "strict", z.ZodTypeAny, {
    type: "diagnostic";
    message: string;
    timestamp: string;
    level: "info" | "warning" | "debug";
    code?: string | undefined;
}, {
    type: "diagnostic";
    message: string;
    timestamp: string;
    level: "info" | "warning" | "debug";
    code?: string | undefined;
}>, z.ZodObject<{
    type: z.ZodLiteral<"progress">;
    timestamp: z.ZodString;
    message: z.ZodString;
    current: z.ZodOptional<z.ZodNumber>;
    total: z.ZodOptional<z.ZodNumber>;
}, "strict", z.ZodTypeAny, {
    type: "progress";
    message: string;
    timestamp: string;
    current?: number | undefined;
    total?: number | undefined;
}, {
    type: "progress";
    message: string;
    timestamp: string;
    current?: number | undefined;
    total?: number | undefined;
}>]>;
/** A diagnostic emitted while a command executes. */
export type CommandDiagnosticEvent = z.infer<typeof commandDiagnosticEventSchema>;
/** A progress update emitted while a command executes. */
export type CommandProgressEvent = z.infer<typeof commandProgressEventSchema>;
/** A side event emitted while a command executes. */
export type CommandEvent = z.infer<typeof commandEventSchema>;
/** An event before its emission timestamp is added. */
export type CommandEventInput<TEvent extends CommandEvent = CommandEvent> = TEvent extends unknown ? Omit<TEvent, 'timestamp'> : never;
/** Receives one timestamped event from a command execution. */
export type CommandEventSink<TEvent extends CommandEvent = CommandEvent> = (event: TEvent) => void;
/** Emits timestamped side events from one command execution. */
export interface CommandEventChannel<TEvent extends CommandEvent = CommandEvent> {
    emit: (event: CommandEventInput<TEvent>) => void;
}
/** Supplies the current time when an event is emitted. */
export type CommandEventClock = () => Date;
/** Options for a command event channel. */
export interface CommandEventChannelOptions<TEvent extends CommandEvent> {
    sink?: CommandEventSink<TEvent>;
    clock?: CommandEventClock;
}
/**
 * Creates a synchronous, execution-scoped channel for command side events.
 *
 * @param options - The event sink and clock used by the channel.
 * @returns A channel that adds an ISO timestamp before synchronously delivering each event.
 */
export declare function createCommandEventChannel<TEvent extends CommandEvent = CommandEvent>(options?: CommandEventChannelOptions<TEvent>): CommandEventChannel<TEvent>;
packages/cli-kit/dist/public/node/command-events.d.ts
import type { CommandEvent } from '../common/command-events.js';
/**
 * Renders a command side event to stderr using the existing CLI output behavior.
 *
 * @param event - The event to render.
 */
export declare function renderCommandEvent(event: CommandEvent): void;
/**
 * Renders a command side event as compact JSON to stderr.
 *
 * @param event - The event to render.
 */
export declare function renderCommandEventAsJson(event: CommandEvent): void;

Existing type declarations

We found no diffs with existing type declarations

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.

1 participant