Repository navigation
Conversation
grollest
marked this pull request as ready for review
November 9, 2026 23:01
This branch has not been deployed
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.
WHY are these changes introduced?
Developers and agents can discover the inputs accepted by the installed CLI without reading source or querying an app. This complements
shopify app logs-next typeswith local filter and query-control discovery.WHAT is this pull request doing?
shopify app logs-next filters, only underlogs-next.--type, returns the complete union. An explicit type selection returns only inputs applicable to every selected type; repeated names are deduplicated. This discovery intersection is distinct from retrieval's OR across selected types.{filters: [...]}JSON envelope containing names, kinds, descriptions, value formats, allowed values, literal defaults, repeatability, applicability, matching semantics, vocabulary, requirements, dependencies, and incompatibilities.app logscommand remain unchanged.How to manually test your changes?
Run these from any directory, including outside an app project. Each collapsible section contains the actual captured output of the built CLI (no omitted records or schema fields).
Actual output — stderr; exit 0
stdout: empty.
Actual output — stdout; exit 0
stderr: empty.
{ "filters": [ { "name": "json", "kind": "output", "description": "Output the result as JSON. Automatically disables color output.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Selects JSON output, independently of --no-input. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "json-schema", "kind": "output", "description": "Print the command's JSON schemas.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Prints the result, error, and event schemas without retrieving logs.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "limit", "kind": "query", "description": "Maximum number of records to return, from 1 through 1000.", "valueFormat": "Integer from 1 to 1000", "allowedValues": null, "default": 20, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Caps returned records. Without --sort, a capped result is not necessarily the oldest or newest matches.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "no-color", "kind": "output", "description": "Disable color output.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Disables color. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "no-input", "kind": "output", "description": "Disable interactive prompts and browser authentication.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Disables prompts independently of --json. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "order", "kind": "query", "description": "Sort direction: asc (oldest first, default with --sort) or desc (newest first).", "valueFormat": "Sort direction", "allowedValues": [ "asc", "desc" ], "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "With --sort, defaults to asc: selects oldest matches first. Use desc to select newest matches first.", "vocabulary": "fixed", "required": false, "dependencies": [ "sort" ], "incompatibleWith": [] }, { "name": "since", "kind": "query", "description": "Inclusive start: positive duration (s/m/h/d) or whole-second RFC 3339 timestamp.", "valueFormat": "Positive integer duration with s/m/h/d suffix, or whole-second RFC 3339 timestamp with timezone", "allowedValues": null, "default": "1h", "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Inclusive start, earlier than --until. Durations are relative to --until (current time by default). Documented API bounds: 30-day lookback and seven-day maximum window.", "vocabulary": "open", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "sort", "kind": "query", "description": "Select the oldest/newest matches using server-side sorting. Omit for faster, less-throttled retrieval.", "valueFormat": "Sort key", "allowedValues": [ "timestamp" ], "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Sorts matches on the server before applying --limit. Omit for faster retrieval; returned records are still displayed oldest first.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "status", "kind": "filter", "description": "Recorded result status; not inferred from HTTP codes or response bodies.", "valueFormat": "Recorded result status; one nonempty value, at most 1024 UTF-8 bytes", "allowedValues": [ "success", "failure" ], "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "One exact value. Different record filters combine with AND; records without the field are excluded. Uses the recorded result status, not inferred from HTTP codes or response bodies.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "status-code", "kind": "filter", "description": "Exact webhook HTTP status code (100–599).", "valueFormat": "Three-digit HTTP code from 100 to 599; one nonempty value, at most 1024 UTF-8 bytes", "allowedValues": null, "default": null, "repeatable": false, "applicableTypes": [ "webhook" ], "matching": "One exact value. Different record filters combine with AND; records without the field are excluded.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "store", "kind": "filter", "description": "Exact store handle or myshopify.com domain/URL.", "valueFormat": "Store handle or myshopify.com domain/URL; one nonempty value, at most 1024 UTF-8 bytes", "allowedValues": null, "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "One exact value. Different record filters combine with AND; records without the field are excluded. Normalized to a myshopify.com domain before matching.", "vocabulary": "open", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "topic", "kind": "filter", "description": "Exact webhook topic; excludes non-webhook records.", "valueFormat": "Slash-form webhook topic, such as orders/create; one nonempty value, at most 1024 UTF-8 bytes", "allowedValues": null, "default": null, "repeatable": false, "applicableTypes": [ "webhook" ], "matching": "One exact value. Different record filters combine with AND; records without the field are excluded.", "vocabulary": "open", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "type", "kind": "query", "description": "Log type; repeat to select multiple. Defaults to all supported types.", "valueFormat": "Log type name", "allowedValues": [ "webhook", "graphql" ], "default": [ "webhook", "graphql" ], "repeatable": true, "applicableTypes": [ "webhook", "graphql" ], "matching": "Retrieval includes records of any selected type (OR). In filters discovery, repeated --type returns inputs common to every selected type (intersection). Repeated names are deduplicated.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "until", "kind": "query", "description": "Exclusive whole-second RFC 3339 end; defaults to the current time.", "valueFormat": "Whole-second RFC 3339 timestamp with timezone", "allowedValues": null, "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Exclusive end, later than --since; defaults to the current time. Fractional seconds are not accepted.", "vocabulary": "open", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "verbose", "kind": "output", "description": "Increase the verbosity of the output. May include sensitive data.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Increases diagnostic output. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] } ] }Actual output — stdout; exit 0
stderr: empty.
{ "filters": [ { "name": "json", "kind": "output", "description": "Output the result as JSON. Automatically disables color output.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Selects JSON output, independently of --no-input. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "json-schema", "kind": "output", "description": "Print the command's JSON schemas.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Prints the result, error, and event schemas without retrieving logs.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "limit", "kind": "query", "description": "Maximum number of records to return, from 1 through 1000.", "valueFormat": "Integer from 1 to 1000", "allowedValues": null, "default": 20, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Caps returned records. Without --sort, a capped result is not necessarily the oldest or newest matches.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "no-color", "kind": "output", "description": "Disable color output.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Disables color. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "no-input", "kind": "output", "description": "Disable interactive prompts and browser authentication.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Disables prompts independently of --json. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "order", "kind": "query", "description": "Sort direction: asc (oldest first, default with --sort) or desc (newest first).", "valueFormat": "Sort direction", "allowedValues": [ "asc", "desc" ], "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "With --sort, defaults to asc: selects oldest matches first. Use desc to select newest matches first.", "vocabulary": "fixed", "required": false, "dependencies": [ "sort" ], "incompatibleWith": [] }, { "name": "since", "kind": "query", "description": "Inclusive start: positive duration (s/m/h/d) or whole-second RFC 3339 timestamp.", "valueFormat": "Positive integer duration with s/m/h/d suffix, or whole-second RFC 3339 timestamp with timezone", "allowedValues": null, "default": "1h", "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Inclusive start, earlier than --until. Durations are relative to --until (current time by default). Documented API bounds: 30-day lookback and seven-day maximum window.", "vocabulary": "open", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "sort", "kind": "query", "description": "Select the oldest/newest matches using server-side sorting. Omit for faster, less-throttled retrieval.", "valueFormat": "Sort key", "allowedValues": [ "timestamp" ], "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Sorts matches on the server before applying --limit. Omit for faster retrieval; returned records are still displayed oldest first.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "status", "kind": "filter", "description": "Recorded result status; not inferred from HTTP codes or response bodies.", "valueFormat": "Recorded result status; one nonempty value, at most 1024 UTF-8 bytes", "allowedValues": [ "success", "failure" ], "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "One exact value. Different record filters combine with AND; records without the field are excluded. Uses the recorded result status, not inferred from HTTP codes or response bodies.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "store", "kind": "filter", "description": "Exact store handle or myshopify.com domain/URL.", "valueFormat": "Store handle or myshopify.com domain/URL; one nonempty value, at most 1024 UTF-8 bytes", "allowedValues": null, "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "One exact value. Different record filters combine with AND; records without the field are excluded. Normalized to a myshopify.com domain before matching.", "vocabulary": "open", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "type", "kind": "query", "description": "Log type; repeat to select multiple. Defaults to all supported types.", "valueFormat": "Log type name", "allowedValues": [ "webhook", "graphql" ], "default": [ "webhook", "graphql" ], "repeatable": true, "applicableTypes": [ "webhook", "graphql" ], "matching": "Retrieval includes records of any selected type (OR). In filters discovery, repeated --type returns inputs common to every selected type (intersection). Repeated names are deduplicated.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "until", "kind": "query", "description": "Exclusive whole-second RFC 3339 end; defaults to the current time.", "valueFormat": "Whole-second RFC 3339 timestamp with timezone", "allowedValues": null, "default": null, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Exclusive end, later than --since; defaults to the current time. Fractional seconds are not accepted.", "vocabulary": "open", "required": false, "dependencies": [], "incompatibleWith": [] }, { "name": "verbose", "kind": "output", "description": "Increase the verbosity of the output. May include sensitive data.", "valueFormat": "Boolean switch", "allowedValues": null, "default": false, "repeatable": false, "applicableTypes": [ "webhook", "graphql" ], "matching": "Increases diagnostic output. Does not change record matching.", "vocabulary": "fixed", "required": false, "dependencies": [], "incompatibleWith": [] } ] }Actual output — stdout; exit 0
stderr: empty.
{ "anyOf": [ { "$ref": "#/definitions/Result" }, { "$ref": "#/definitions/Error" }, { "$ref": "#/definitions/Event" } ], "title": "CommandOutput", "definitions": { "Result": { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-z]+(?:-[a-z]+)*$", "description": "Long flag name without the -- prefix." }, "kind": { "type": "string", "enum": [ "filter", "query", "output" ] }, "description": { "type": "string", "minLength": 1 }, "valueFormat": { "type": "string" }, "allowedValues": { "anyOf": [ { "type": "array", "items": { "type": "string" } }, { "type": "null" } ], "description": "Exhaustive choices, or null for a format-defined value." }, "default": { "anyOf": [ { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "type": "string" } } ] }, { "type": "null" } ], "description": "The literal retrieval default, or null when unset, dynamic, or conditional; see matching for details." }, "repeatable": { "type": "boolean" }, "applicableTypes": { "type": "array", "items": { "type": "string", "enum": [ "webhook", "graphql" ] } }, "matching": { "type": "string" }, "vocabulary": { "type": "string", "enum": [ "fixed", "open" ] }, "required": { "type": "boolean" }, "dependencies": { "type": "array", "items": { "type": "string" }, "description": "Other flag names required when this input is supplied, without the -- prefix." }, "incompatibleWith": { "type": "array", "items": { "type": "string" }, "description": "Combinations rejected by retrieval, not combinations that match no records." } }, "required": [ "name", "kind", "description", "valueFormat", "allowedValues", "default", "repeatable", "applicableTypes", "matching", "vocabulary", "required", "dependencies", "incompatibleWith" ], "additionalProperties": false }, "description": "Local app logs-next record filters and query/output controls, sorted by long flag name. Without --type, lists all inputs; selected types return only common inputs. Does not check app access or log availability." } }, "required": [ "filters" ], "additionalProperties": false }, "Error": { "type": "object", "properties": { "error": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "abort" }, "message": { "type": "string" }, "code": { "type": "string", "minLength": 1, "description": "A stable error code, included only when known." }, "tryMessage": { "type": "string" }, "nextSteps": { "type": "array", "items": { "type": "string" } }, "customSections": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "body": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "array", "items": { "type": "string" } } } ] } }, "required": [ "body" ], "additionalProperties": false } }, "details": { "description": "Selected domain details, preserving native API payloads such as GraphQL errors, extensions, and data." } }, "required": [ "type", "message" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "bug" }, "message": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/message" }, "code": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/code" }, "tryMessage": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/tryMessage" }, "nextSteps": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/nextSteps" }, "customSections": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/customSections" }, "details": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/details" }, "stack": { "type": "string" } }, "required": [ "type", "message" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "external" }, "message": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/message" }, "code": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/code" }, "tryMessage": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/tryMessage" }, "nextSteps": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/nextSteps" }, "customSections": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/customSections" }, "details": { "$ref": "#/definitions/Error/properties/error/anyOf/0/properties/details" }, "command": { "type": "string" }, "args": { "type": "array", "items": { "type": "string" } } }, "required": [ "type", "message", "command", "args" ], "additionalProperties": false } ] } }, "required": [ "error" ], "additionalProperties": false }, "Event": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "diagnostic" }, "timestamp": { "type": "string", "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$", "description": "A UTC ISO 8601 instant with whole seconds and the Z timezone marker." }, "level": { "type": "string", "enum": [ "debug", "info", "warning", "error" ] }, "message": { "type": "string" }, "code": { "type": "string", "minLength": 1, "description": "A stable diagnostic code, included only when known." } }, "required": [ "type", "timestamp", "level", "message" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "progress" }, "timestamp": { "$ref": "#/definitions/Event/anyOf/0/properties/timestamp" }, "status": { "type": "string", "enum": [ "started", "updated", "retrying", "completed", "failed" ] }, "operation": { "type": "string" }, "message": { "type": "string" }, "current": { "type": "integer", "minimum": 0 }, "total": { "type": "integer", "minimum": 0 } }, "required": [ "type", "timestamp", "status", "operation" ], "additionalProperties": false } ] } }, "$schema": "http://json-schema.org/draft-07/schema#" }Actual output — stdout; exit 2
stderr: empty.
{"error":{"type":"abort","message":"Expected --type=not-a-type to be one of: webhook, graphql\nSee more help with --help"}}Validation
app:logs-next:filters.Checklist