Repository navigation
Add typed JSON output to app bulk execute - #8783
isaacroldan wants to merge 4 commits into
Conversation
|
/snapit |
|
🫰✨ Thanks @isaacroldan! Your snapshot has been published to npm. Built from Test the snapshot by installing your package globally: pnpm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20261006083344Caution After installing, validate the version by running |
d7aaae1 to
2a27ac7
Compare
|
/snapit |
|
🫰✨ Thanks @isaacroldan! Your snapshot has been published to npm. Built from Test the snapshot by installing your package globally: pnpm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20261006100618Caution After installing, validate the version by running |
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/json-error.d.ts@@ -9,7 +9,6 @@ interface FatalErrorLike {
command?: unknown;
args?: unknown;
details?: unknown;
- code?: unknown;
}
/**
* Writes the public JSON representation of a fatal error to stdout.
packages/cli-kit/dist/public/common/command-events.d.ts@@ -120,6 +120,6 @@ export interface CommandEventChannelOptions<TEvent extends CommandEvent> {
* Adapters validate events at their output boundary; the channel preserves domain-specific event fields.
*
* @param options - The event sink and clock used by the channel.
- * @returns A channel that adds a whole-second UTC timestamp before synchronously delivering each event.
+ * @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>;
\ No newline at end of file
packages/cli-kit/dist/public/node/json-output-schema.d.ts@@ -1,6 +1,8 @@
+import { zod } from './schema.js';
import { zodToJsonSchema } from 'zod-to-json-schema';
import type { ZodTypeAny, z } from 'zod';
-export { formatJsonOutputTimestamp, jsonOutputTimestampSchema } from '../common/json-output-schema.js';
+/** UTC instants in CLI-owned results use whole seconds and the Z timezone marker. */
+export declare const jsonOutputTimestampSchema: zod.ZodString;
interface JsonOutputSchemaDefinition<TSchema extends ZodTypeAny = ZodTypeAny> {
readonly name: string;
readonly schema: TSchema;
@@ -23,4 +25,5 @@ interface DefineJsonOutputSchemaOptions<TSchema extends ZodTypeAny> {
* @param options - The root schema name, its Zod schema, and any named nested schemas.
* @returns The complete JSON output contract.
*/
-export declare function defineJsonOutputSchema<TSchema extends ZodTypeAny>(options: DefineJsonOutputSchemaOptions<TSchema>): JsonOutputSchema<TSchema>;
\ No newline at end of file
+export declare function defineJsonOutputSchema<TSchema extends ZodTypeAny>(options: DefineJsonOutputSchemaOptions<TSchema>): JsonOutputSchema<TSchema>;
+export {};
\ No newline at end of file
packages/cli-kit/dist/public/node/error/index.d.ts@@ -18,8 +18,6 @@ export declare abstract class FatalError extends Error {
nextSteps?: TokenItem<InlineToken>[];
formattedMessage?: TokenItem;
customSections?: AlertCustomSection[];
- /** A stable code for JSON consumers to identify this error, included only when known. */
- code?: string;
/** Selected JSON-serializable data to include in JSON errors. Never attach the raw error or request. */
details?: unknown;
skipOclifErrorHandling: boolean;
packages/cli-kit/dist/public/node/error/schema.d.ts@@ -11,7 +11,6 @@ export declare const JsonErrorCustomSectionSchema: zod.ZodObject<{
}>;
export declare const JsonAbortErrorSchema: zod.ZodObject<{
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -29,7 +28,6 @@ export declare const JsonAbortErrorSchema: zod.ZodObject<{
}, "strict", zod.ZodTypeAny, {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -40,7 +38,6 @@ export declare const JsonAbortErrorSchema: zod.ZodObject<{
}, {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -52,7 +49,6 @@ export declare const JsonAbortErrorSchema: zod.ZodObject<{
export declare const JsonBugErrorSchema: zod.ZodObject<{
stack: zod.ZodOptional<zod.ZodString>;
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -70,7 +66,6 @@ export declare const JsonBugErrorSchema: zod.ZodObject<{
}, "strict", zod.ZodTypeAny, {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -82,7 +77,6 @@ export declare const JsonBugErrorSchema: zod.ZodObject<{
}, {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -96,7 +90,6 @@ export declare const JsonExternalErrorSchema: zod.ZodObject<{
command: zod.ZodString;
args: zod.ZodArray<zod.ZodString, "many">;
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -116,7 +109,6 @@ export declare const JsonExternalErrorSchema: zod.ZodObject<{
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -129,7 +121,6 @@ export declare const JsonExternalErrorSchema: zod.ZodObject<{
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -140,7 +131,6 @@ export declare const JsonExternalErrorSchema: zod.ZodObject<{
}>;
export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -158,7 +148,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
}, "strict", zod.ZodTypeAny, {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -169,7 +158,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
}, {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -180,7 +168,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
}>, zod.ZodObject<{
stack: zod.ZodOptional<zod.ZodString>;
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -198,7 +185,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
}, "strict", zod.ZodTypeAny, {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -210,7 +196,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
}, {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -223,7 +208,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
command: zod.ZodString;
args: zod.ZodArray<zod.ZodString, "many">;
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -243,7 +227,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -256,7 +239,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -268,7 +250,6 @@ export declare const JsonErrorSchema: zod.ZodUnion<[zod.ZodObject<{
export declare const jsonErrorOutputSchema: import("../json-output-schema.js").JsonOutputSchema<zod.ZodObject<{
error: zod.ZodUnion<[zod.ZodObject<{
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -286,7 +267,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
}, "strict", zod.ZodTypeAny, {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -297,7 +277,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
}, {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -308,7 +287,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
}>, zod.ZodObject<{
stack: zod.ZodOptional<zod.ZodString>;
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -326,7 +304,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
}, "strict", zod.ZodTypeAny, {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -338,7 +315,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
}, {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -351,7 +327,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
command: zod.ZodString;
args: zod.ZodArray<zod.ZodString, "many">;
message: zod.ZodString;
- code: zod.ZodOptional<zod.ZodString>;
tryMessage: zod.ZodOptional<zod.ZodString>;
nextSteps: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
customSections: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
@@ -371,7 +346,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -384,7 +358,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -397,7 +370,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
error: {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -408,7 +380,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
} | {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -422,7 +393,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -435,7 +405,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
error: {
type: "abort";
message: string;
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
@@ -446,7 +415,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
} | {
type: "bug";
message: string;
- code?: string | undefined;
stack?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
@@ -460,7 +428,6 @@ export declare const jsonErrorOutputSchema: import("../json-output-schema.js").J
message: string;
command: string;
args: string[];
- code?: string | undefined;
nextSteps?: string[] | undefined;
customSections?: {
body: string | string[][];
|
bdb9e33 to
2816253
Compare
WHY are these changes introduced?
Expose a finite, typed JSON result for bulk execution while keeping the existing raw JSONL and file formats available.
WHAT is this pull request doing?
Add JSON output for
app bulk executeon top of the earlier stack layers. Separate preparation, execution, and final presentation. Reuse the shared operation projection and diagnostic events.Unwatched execution returns operation metadata. Watched JSON output includes native data in
resultsJsonl; file output emits an absolutepath/formatreceipt. Preserve the existing text-mode output and exact JSONL file contents. Treat query records as data and completed zero-match queries as successful empty exports.Representative text output:
Matching JSON output:
{ "storeDomain": "shop.myshopify.com", "apiVersion": "2026-01", "status": "success", "operation": { "gid": "gid://shopify/BulkOperation/123", "type": "QUERY", "status": "RUNNING", "errorCode": null, "createdAt": "2026-09-01T00:00:00Z", "completedAt": null, "objectCount": "2", "url": null, "partialDataUrl": null } }How to manually test your changes?
Use a linked app installed on a development store.
pnpm shopify app bulk execute --store <store.myshopify.com> --query 'query { products { edges { node { id } } } }', then repeat with--json.--watch. Without JSON mode, confirm stdout still contains raw JSONL. With JSON mode, confirm one result object containsresultsJsonl.--output-file ./results.jsonlto the watched JSON command. Confirm stdout contains only an absolute JSONL file receipt and the file contains native JSONL.query { products(query: "id:0") { edges { node { id } } } }. Confirm exit 0, an empty file, and a file receipt.id errors: tagsfor products with tags. Confirm watched JSON output reports success rather than treating tags as errors.pnpm shopify app bulk execute --json-schema.Checklist