Skip to content

Add filter discovery under app logs-next - #9112

Open
grollest wants to merge 1 commit into
grollest/app-logs-types-localfrom
grollest/app-logs-filters
Open

grollest wants to merge 1 commit into
grollest/app-logs-types-localfrom
grollest/app-logs-filters

Conversation

@grollest

@grollest grollest commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Scope: This PR only describes webhook and GraphQL log types. The remaining log types in this stack will be added once those PRs have merged.

Dependency: Stacked on #9111 (grollest/app-logs-types-local), reusing its local type/filter applicability metadata.

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 types with local filter and query-control discovery.

WHAT is this pull request doing?

  • Adds hidden shopify app logs-next filters, only under logs-next.
  • Lists 18 inputs: seven record predicates, six query controls, and five output controls.
  • With no --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.
  • Returns a sorted, strict {filters: [...]} JSON envelope containing names, kinds, descriptions, value formats, allowed values, literal defaults, repeatability, applicability, matching semantics, vocabulary, requirements, dependencies, and incompatibilities.
  • Reuses existing flags/catalog definitions and Add type discovery under app logs-next #9111's applicability mapping. Conditional/dynamic defaults are null with explanatory text; documented API time bounds are not queried live.
  • Uses standard parsing, JSON/error/schema infrastructure, and UI Kit informational sections that preserve full flag names at 80 columns.
  • Performs no app lookup, authentication, or App Logs request. Describes installed CLI support, not an app's access or available logs. Retrieval and the existing app logs command 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).

shopify app logs-next filters
Actual output — stderr; exit 0

stdout: empty.

╭─ info ───────────────────────────────────────────────────────────────────────╮
│                                                                              │
│  App log filters.                                                            │
│                                                                              │
│  --json                                                                      │
│  Output the result as JSON. Automatically disables color output.             │
│  Applies to: webhook, graphql.                                               │
│  Value: Boolean switch.                                                      │
│  Default: false. Repeatable: no.                                             │
│  Selects JSON output, independently of --no-input. Does not change record    │
│  matching.                                                                   │
│                                                                              │
│  --json-schema                                                               │
│  Print the command's JSON schemas.                                           │
│  Applies to: webhook, graphql.                                               │
│  Value: Boolean switch.                                                      │
│  Default: false. Repeatable: no.                                             │
│  Prints the result, error, and event schemas without retrieving logs.        │
│                                                                              │
│  --limit                                                                     │
│  Maximum number of records to return, from 1 through 1000.                   │
│  Applies to: webhook, graphql.                                               │
│  Value: Integer from 1 to 1000.                                              │
│  Default: 20. Repeatable: no.                                                │
│  Caps returned records. Without --sort, a capped result is not necessarily   │
│  the oldest or newest matches.                                               │
│                                                                              │
│  --no-color                                                                  │
│  Disable color output.                                                       │
│  Applies to: webhook, graphql.                                               │
│  Value: Boolean switch.                                                      │
│  Default: false. Repeatable: no.                                             │
│  Disables color. Does not change record matching.                            │
│                                                                              │
│  --no-input                                                                  │
│  Disable interactive prompts and browser authentication.                     │
│  Applies to: webhook, graphql.                                               │
│  Value: Boolean switch.                                                      │
│  Default: false. Repeatable: no.                                             │
│  Disables prompts independently of --json. Does not change record matching.  │
│                                                                              │
│  --operation-name                                                            │
│  Exact GraphQL operation name; excludes non-GraphQL records.                 │
│  Applies to: graphql.                                                        │
│  Value: Nonempty client-supplied GraphQL operation name; one nonempty        │
│  value, at most 1024 UTF-8 bytes.                                            │
│  Default: unset or described below. Repeatable: no.                          │
│  One exact value. Different record filters combine with AND; records         │
│  without the field are excluded. Matches the operation name, not a root API  │
│   field.                                                                     │
│                                                                              │
│  --operation-type                                                            │
│  Exact GraphQL operation type; excludes non-GraphQL records.                 │
│  Applies to: graphql.                                                        │
│  Value: Nonempty recorded GraphQL operation kind; one nonempty value, at     │
│  most 1024 UTF-8 bytes.                                                      │
│  Default: unset or described below. Repeatable: no.                          │
│  One exact value. Different record filters combine with AND; records         │
│  without the field are excluded.                                             │
│                                                                              │
│  --order                                                                     │
│  Sort direction: asc (oldest first, default with --sort) or desc (newest     │
│  first).                                                                     │
│  Applies to: webhook, graphql.                                               │
│  Value: asc | desc.                                                          │
│  Default: unset or described below. Repeatable: no.                          │
│  Requires: --sort.                                                           │
│  With --sort, defaults to asc: selects oldest matches first. Use desc to     │
│  select newest matches first.                                                │
│                                                                              │
│  --request-id                                                                │
│  Exact GraphQL request ID; excludes non-GraphQL records.                     │
│  Applies to: graphql.                                                        │
│  Value: Nonempty GraphQL request identifier; one nonempty value, at most     │
│  1024 UTF-8 bytes.                                                           │
│  Default: unset or described below. Repeatable: no.                          │
│  One exact value. Different record filters combine with AND; records         │
│  without the field are excluded.                                             │
│                                                                              │
│  --since                                                                     │
│  Inclusive start: positive duration (s/m/h/d) or whole-second RFC 3339       │
│  timestamp.                                                                  │
│  Applies to: webhook, graphql.                                               │
│  Value: Positive integer duration with s/m/h/d suffix, or whole-second RFC   │
│  3339 timestamp with timezone.                                               │
│  Default: 1h. Repeatable: no.                                                │
│  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.                                                   │
│                                                                              │
│  --sort                                                                      │
│  Select the oldest/newest matches using server-side sorting. Omit for        │
│  faster, less-throttled retrieval.                                           │
│  Applies to: webhook, graphql.                                               │
│  Value: timestamp.                                                           │
│  Default: unset or described below. Repeatable: no.                          │
│  Sorts matches on the server before applying --limit. Omit for faster        │
│  retrieval; returned records are still displayed oldest first.               │
│                                                                              │
│  --status                                                                    │
│  Recorded result status; not inferred from HTTP codes or response bodies.    │
│  Applies to: webhook, graphql.                                               │
│  Value: success | failure.                                                   │
│  Default: unset or described below. Repeatable: no.                          │
│  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.                                │
│                                                                              │
│  --status-code                                                               │
│  Exact webhook HTTP status code (100–599).                                   │
│  Applies to: webhook.                                                        │
│  Value: Three-digit HTTP code from 100 to 599; one nonempty value, at most   │
│  1024 UTF-8 bytes.                                                           │
│  Default: unset or described below. Repeatable: no.                          │
│  One exact value. Different record filters combine with AND; records         │
│  without the field are excluded.                                             │
│                                                                              │
│  --store                                                                     │
│  Exact store handle or myshopify.com domain/URL.                             │
│  Applies to: webhook, graphql.                                               │
│  Value: Store handle or myshopify.com domain/URL; one nonempty value, at     │
│  most 1024 UTF-8 bytes.                                                      │
│  Default: unset or described below. Repeatable: no.                          │
│  One exact value. Different record filters combine with AND; records         │
│  without the field are excluded. Normalized to a myshopify.com domain        │
│  before matching.                                                            │
│                                                                              │
│  --topic                                                                     │
│  Exact webhook topic; excludes non-webhook records.                          │
│  Applies to: webhook.                                                        │
│  Value: Slash-form webhook topic, such as orders/create; one nonempty        │
│  value, at most 1024 UTF-8 bytes.                                            │
│  Default: unset or described below. Repeatable: no.                          │
│  One exact value. Different record filters combine with AND; records         │
│  without the field are excluded.                                             │
│                                                                              │
│  --type                                                                      │
│  Log type; repeat to select multiple. Defaults to all supported types.       │
│  Applies to: webhook, graphql.                                               │
│  Value: webhook | graphql.                                                   │
│  Default: webhook,graphql. Repeatable: yes.                                  │
│  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.                            │
│                                                                              │
│  --until                                                                     │
│  Exclusive whole-second RFC 3339 end; defaults to the current time.          │
│  Applies to: webhook, graphql.                                               │
│  Value: Whole-second RFC 3339 timestamp with timezone.                       │
│  Default: unset or described below. Repeatable: no.                          │
│  Exclusive end, later than --since; defaults to the current time.            │
│  Fractional seconds are not accepted.                                        │
│                                                                              │
│  --verbose                                                                   │
│  Increase the verbosity of the output. May include sensitive data.           │
│  Applies to: webhook, graphql.                                               │
│  Value: Boolean switch.                                                      │
│  Default: false. Repeatable: no.                                             │
│  Increases diagnostic output. Does not change record matching.               │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
shopify app logs-next filters --type webhook --json --no-input
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": []
    }
  ]
}
shopify app logs-next filters --type graphql --type webhook --json --no-input
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": []
    }
  ]
}
shopify app logs-next filters --json-schema
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#"
}
shopify app logs-next filters --type not-a-type --json --no-input
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

  • 275 tests passed across ten files: new filters command/service/help, parent types command/service/help, and existing retrieval/input/service/help regressions.
  • App and CLI type-checks, targeted ESLint, bundle, manifest/readme/code-documentation generation, command snapshot, and diff checks passed.
  • The manifest delta adds only app:logs-next:filters.
  • A temporary intersection-to-union mutation failed two regression tests; source was restored and the complete suite passed.
  • Built CLI tested with an empty private HOME and project directory and network access blocked: complete union (18 inputs), webhook (15), GraphQL (16), both types (13), repeated selections, environment precedence, invalid selections, full schema, human output, and unchanged types/legacy behavior.
  • Shared CLI startup attempted its normal npm/CDN checks, which were blocked and tolerated. No App Logs or authentication requests occurred. These are local checks, not a claim that GitHub CI has passed.
  • Human output was checked at 80 columns; the multiline table was replaced with shared informational sections to avoid wrapping/corrupting long flag names.

Checklist

  • Considered cross-platform impacts; implementation uses shared CLI parsing and UI infrastructure. Executable smoke was run on macOS.
  • Considered documentation changes; command help/examples and manifest regenerated.
  • Considered analytics changes; no custom analytics added.
  • No changeset: command remains hidden and pre-release.

@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 Nov 9, 2026
@grollest
grollest marked this pull request as ready for review November 9, 2026 23:01
@grollest
grollest requested review from a team as code owners November 9, 2026 23:01

This branch has not been deployed

No deployments
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