From 0c990bce3803c8d262d1bef14d8fa17eb74fd0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaac=20Rold=C3=A1n?= Date: Thu, 26 Mar 2026 12:38:47 +0100 Subject: [PATCH 01/11] Refactor RemoteSpecification --- .../api/graphql/extension_specifications.ts | 17 +- .../app/src/cli/models/app/app.test-data.ts | 238 ++++++------------ .../cli/models/extensions/specification.ts | 2 +- .../fetch-extension-specifications.test.ts | 4 - .../fetch-extension-specifications.ts | 37 +-- .../app-management-client.test.ts | 4 +- .../app-management-client.ts | 13 +- .../partners-client.ts | 7 +- 8 files changed, 108 insertions(+), 214 deletions(-) diff --git a/packages/app/src/cli/api/graphql/extension_specifications.ts b/packages/app/src/cli/api/graphql/extension_specifications.ts index c4270727961..ab3fe4b4ad2 100644 --- a/packages/app/src/cli/api/graphql/extension_specifications.ts +++ b/packages/app/src/cli/api/graphql/extension_specifications.ts @@ -31,6 +31,21 @@ export interface ExtensionSpecificationsQueryVariables { } export interface RemoteSpecification { + name: string + externalName: string + identifier: string + gated: boolean + externalIdentifier: string + experience: 'extension' | 'configuration' | 'deprecated' + managementExperience: 'cli' | 'custom' | 'dashboard' + registrationLimit: number + uidStrategy: 'single' | 'dynamic' | 'uuid' + validationSchema?: { + jsonSchema: string + } | null +} + +export interface PartnersRemoteSpecification { name: string externalName: string identifier: string @@ -59,5 +74,5 @@ export interface FlattenedRemoteSpecification extends RemoteSpecification { } export interface ExtensionSpecificationsQuerySchema { - extensionSpecifications: RemoteSpecification[] + extensionSpecifications: PartnersRemoteSpecification[] } diff --git a/packages/app/src/cli/models/app/app.test-data.ts b/packages/app/src/cli/models/app/app.test-data.ts index 578c83bd170..838f8b12d20 100644 --- a/packages/app/src/cli/models/app/app.test-data.ts +++ b/packages/app/src/cli/models/app/app.test-data.ts @@ -694,16 +694,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'checkout_post_purchase_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, - features: { - argo: { - surface: 'checkout', - }, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', }, { name: 'Online Store - App Theme Extension', @@ -712,11 +705,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'theme_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', }, { name: 'Product Subscription', @@ -725,16 +716,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'product_subscription_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, - features: { - argo: { - surface: 'admin', - }, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', }, { name: 'UI Extension', @@ -743,16 +727,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'ui_extension_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 50, - uidIsClientProvided: true, - }, - features: { - argo: { - surface: 'all', - }, - }, + managementExperience: 'cli', + registrationLimit: 50, + uidStrategy: 'uuid', }, { name: 'Checkout Extension', @@ -761,16 +738,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'checkout_ui_extension_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 5, - uidIsClientProvided: true, - }, - features: { - argo: { - surface: 'checkout', - }, - }, + managementExperience: 'cli', + registrationLimit: 5, + uidStrategy: 'uuid', }, { name: 'Product Subscription', @@ -781,16 +751,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'product_subscription_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, - features: { - argo: { - surface: 'admin', - }, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', }, { name: 'Marketing Activity', @@ -799,11 +762,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'marketing_activity_extension_external', gated: false, experience: 'extension', - options: { - managementExperience: 'dashboard', - registrationLimit: 100, - uidIsClientProvided: true, - }, + managementExperience: 'dashboard', + registrationLimit: 100, + uidStrategy: 'uuid', }, { name: 'function', @@ -812,16 +773,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'function', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, - features: { - argo: { - surface: 'checkout', - }, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', }, { name: 'Editor extension collection', @@ -830,11 +784,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'editor_extension_collection_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 100, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 100, + uidStrategy: 'uuid', }, { name: 'Flow Action', @@ -843,11 +795,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'flow_action', gated: true, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 100, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 100, + uidStrategy: 'uuid', }, { name: 'Flow Template', @@ -856,11 +806,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'flow_template', gated: true, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 300, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 300, + uidStrategy: 'uuid', }, { name: 'Flow Trigger', @@ -869,11 +817,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'flow_trigger', gated: true, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 100, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 100, + uidStrategy: 'uuid', }, { name: 'POS UI Extension', @@ -882,11 +828,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'pos_ui_extension', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 50, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 50, + uidStrategy: 'uuid', }, { name: 'Web Pixel Extension', @@ -895,11 +839,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'web_pixel_extension', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', }, { name: 'Branding', @@ -908,11 +850,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'branding', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'App access', @@ -921,11 +861,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'app_access', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'Webhooks', @@ -934,11 +872,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'webhooks', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'Privacy Compliance Webhooks', @@ -947,11 +883,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'privacy_compliance_webhooks', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'Webhook Subscription', @@ -960,11 +894,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'webhook_subscription', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'App Proxy', @@ -973,11 +905,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'app_proxy', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'Point Of Sale Configuration', @@ -986,11 +916,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'point_of_sale', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'App Home', @@ -999,11 +927,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ identifier: 'app_home', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', }, { name: 'Remote Extension Without Schema and Without local spec', @@ -1012,11 +938,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'remote_only_extension_without_schema_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', }, { name: 'Remote Extension With Schema, Without local spec, without localization', @@ -1025,11 +949,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'remote_only_extension_schema_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', validationSchema: { jsonSchema: '{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","additionalProperties":false,"properties":{"pattern":{"type":"string"},"name":{"type":"string"}},"required":["pattern"]}', @@ -1042,11 +964,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'remote_only_extension_schema_with_localization_external', gated: false, experience: 'extension', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: true, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'uuid', validationSchema: { jsonSchema: '{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","additionalProperties":false,"properties":{"pattern":{"type":"string"},"name":{"type":"string"},"localization":{"type":"object","properties":{"marketing_channel":{"type":"string"}},"required":["marketing_channel"]}},"required":["pattern","localization"]}', @@ -1059,11 +979,9 @@ const testRemoteSpecifications: RemoteSpecification[] = [ externalIdentifier: 'remote_only_extension_schema_config_style_external', gated: false, experience: 'configuration', - options: { - managementExperience: 'cli', - registrationLimit: 1, - uidIsClientProvided: false, - }, + managementExperience: 'cli', + registrationLimit: 1, + uidStrategy: 'single', validationSchema: { jsonSchema: '{"$schema":"http://json-schema.org/draft-07/schema#","type":"object","additionalProperties":false,"properties":{"pattern":{"type":"string"},"name":{"type":"string"}},"required":["pattern"]}', diff --git a/packages/app/src/cli/models/extensions/specification.ts b/packages/app/src/cli/models/extensions/specification.ts index a4564c6889f..9ebe567ee64 100644 --- a/packages/app/src/cli/models/extensions/specification.ts +++ b/packages/app/src/cli/models/extensions/specification.ts @@ -32,7 +32,7 @@ export interface CustomTransformationConfig { reverse?: (obj: object, options?: {flags?: Flag[]}) => object } -type ExtensionExperience = 'extension' | 'configuration' +export type ExtensionExperience = 'extension' | 'configuration' export function isAppConfigSpecification(spec: {experience: string}): boolean { return spec.experience === 'configuration' diff --git a/packages/app/src/cli/services/generate/fetch-extension-specifications.test.ts b/packages/app/src/cli/services/generate/fetch-extension-specifications.test.ts index 8b29bc0417c..da6026e9aae 100644 --- a/packages/app/src/cli/services/generate/fetch-extension-specifications.test.ts +++ b/packages/app/src/cli/services/generate/fetch-extension-specifications.test.ts @@ -43,7 +43,6 @@ describe('fetchExtensionSpecifications', () => { identifier: 'product_subscription', externalIdentifier: 'product_subscription_external', registrationLimit: 1, - surface: 'admin', }), ]), ) @@ -55,7 +54,6 @@ describe('fetchExtensionSpecifications', () => { identifier: 'ui_extension', externalIdentifier: 'ui_extension_external', registrationLimit: 50, - surface: 'all', }), ]), ) @@ -68,7 +66,6 @@ describe('fetchExtensionSpecifications', () => { identifier: 'product_subscription', externalIdentifier: 'product_subscription_external', registrationLimit: 1, - surface: 'admin', }), ]), ) @@ -81,7 +78,6 @@ describe('fetchExtensionSpecifications', () => { identifier: 'theme', externalIdentifier: 'theme_external', registrationLimit: 1, - surface: undefined, }), ]), ) diff --git a/packages/app/src/cli/services/generate/fetch-extension-specifications.ts b/packages/app/src/cli/services/generate/fetch-extension-specifications.ts index ea09719743b..08802a46915 100644 --- a/packages/app/src/cli/services/generate/fetch-extension-specifications.ts +++ b/packages/app/src/cli/services/generate/fetch-extension-specifications.ts @@ -44,9 +44,6 @@ export async function fetchSpecifications({ if (spec.identifier === 'theme_app_extension') spec.identifier = 'theme' if (spec.identifier === 'subscription_management') spec.identifier = 'product_subscription' - newSpec.registrationLimit = spec.options.registrationLimit - newSpec.surface = spec.features?.argo?.surface - // Hardcoded value for the post purchase extension because the value is wrong in the API if (spec.identifier === 'checkout_post_purchase') newSpec.surface = 'post_purchase' @@ -74,45 +71,17 @@ async function mergeLocalAndRemoteSpecs( const hasLocalization = normalisedSchema.properties?.localization !== undefined localSpec = createContractBasedModuleSpecification({ identifier: remoteSpec.identifier, - uidStrategy: remoteSpec.options.uidStrategy, + uidStrategy: remoteSpec.uidStrategy, appModuleFeatures: () => (hasLocalization ? ['localization'] : []), }) - // Seed uidStrategy for contract specs using uidIsClientProvided as fallback (Partners API path). - // This will be overridden below if the backend provides a typename-derived value. - localSpec.uidStrategy = - remoteSpec.options.uidStrategy ?? (remoteSpec.options.uidIsClientProvided ? 'uuid' : 'single') } if (!localSpec) return undefined const merged = {...localSpec, ...remoteSpec, loadedRemoteSpecs: true} as RemoteAwareExtensionSpecification & FlattenedRemoteSpecification - // Always prefer the backend-derived uidStrategy (from __typename) when available. - // This correctly overrides the local spec's default (e.g. channel_config defaults to 'uuid' - // locally but the backend defines it as 'single'). - // Falls back to the local spec value for the Partners API path (no __typename available). - merged.uidStrategy = merged.options.uidStrategy ?? localSpec.uidStrategy ?? 'single' - - // If configuration is inside an app.toml -- i.e. single UID mode -- we must be able to parse a partial slice. - // DEPRECATED: not all single specs are config specs. - // Should be removed once we can get the experience from the API. - let handleInvalidAdditionalProperties: HandleInvalidAdditionalProperties - switch (merged.uidStrategy) { - case 'uuid': - handleInvalidAdditionalProperties = 'fail' - break - case 'single': - handleInvalidAdditionalProperties = 'strip' - break - case 'dynamic': - handleInvalidAdditionalProperties = 'fail' - break - } - - // If the experience is 'configuration', force strip. - if (merged.experience === 'configuration') { - handleInvalidAdditionalProperties = 'strip' - } + let handleInvalidAdditionalProperties: HandleInvalidAdditionalProperties = 'strip' + if (merged.experience === 'extension') handleInvalidAdditionalProperties = 'fail' const parseConfigurationObject = await unifiedConfigurationParserFactory(merged, handleInvalidAdditionalProperties) diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts index 5936d55ab2b..5e530f3c72f 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.test.ts @@ -1856,7 +1856,7 @@ describe('uidStrategyFromTypename', () => { expect(uidStrategyFromTypename('UidStrategiesClientProvided')).toBe('uuid') }) - test('returns undefined for unknown typename', () => { - expect(uidStrategyFromTypename('UnknownStrategy')).toBeUndefined() + test('returns uuid as default for unknown typename', () => { + expect(uidStrategyFromTypename('UnknownStrategy')).toBe('uuid') }) }) diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts index 9ca082bd7f0..01fc378f491 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts @@ -459,12 +459,9 @@ export class AppManagementClient implements DeveloperPlatformClient { identifier: spec.identifier, externalIdentifier: spec.externalIdentifier, gated: false, - options: { - managementExperience: 'cli', - registrationLimit: spec.uidStrategy.appModuleLimit, - uidIsClientProvided: spec.uidStrategy.isClientProvided, - uidStrategy: uidStrategyFromTypename(spec.uidStrategy.__typename), - }, + managementExperience: 'cli', + registrationLimit: spec.uidStrategy.appModuleLimit, + uidStrategy: uidStrategyFromTypename(spec.uidStrategy.__typename), experience: normalizeExperience(spec.experience), validationSchema: spec.validationSchema, }), @@ -1383,7 +1380,7 @@ function normalizeExperience(raw: string): SpecificationExperience { } } -export function uidStrategyFromTypename(typename: string): 'single' | 'dynamic' | 'uuid' | undefined { +export function uidStrategyFromTypename(typename: string): 'single' | 'dynamic' | 'uuid' { switch (typename) { case 'UidStrategiesDynamic': return 'dynamic' @@ -1392,7 +1389,7 @@ export function uidStrategyFromTypename(typename: string): 'single' | 'dynamic' case 'UidStrategiesClientProvided': return 'uuid' default: - return undefined + return 'uuid' } } diff --git a/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts b/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts index c1ecc08c367..dcbabf5d355 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/partners-client.ts @@ -359,10 +359,9 @@ export class PartnersClient implements DeveloperPlatformClient { // Partners client does not support isClientProvided. Safe to assume that all modules are extension-style. return result.extensionSpecifications.map((spec) => ({ ...spec, - options: { - ...spec.options, - uidIsClientProvided: true, - }, + uidStrategy: spec.options.uidStrategy ?? 'uuid', + registrationLimit: spec.options.registrationLimit, + managementExperience: spec.options.managementExperience, })) } From ba24eccae871069074958e3156d155e51db130ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:06:24 +0000 Subject: [PATCH 02/11] Bump yaml from 2.7.0 to 2.8.3 Bumps [yaml](https://github.com/eemeli/yaml) from 2.7.0 to 2.8.3. - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.7.0...v2.8.3) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- packages/theme/package.json | 2 +- pnpm-lock.yaml | 229 +++++++++++------------------------- 2 files changed, 72 insertions(+), 159 deletions(-) diff --git a/packages/theme/package.json b/packages/theme/package.json index eb3f34df668..49c98f34424 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -47,7 +47,7 @@ "@shopify/theme-language-server-node": "2.20.2", "chokidar": "3.6.0", "h3": "1.15.9", - "yaml": "2.7.0" + "yaml": "2.8.3" }, "devDependencies": { "@shopify/theme-hot-reload": "^0.0.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c490b5452ef..9aeea964aa2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,7 +51,7 @@ importers: version: 22.0.0 '@shopify/eslint-plugin-cli': specifier: file:packages/eslint-plugin-cli - version: file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) '@shopify/generate-docs': specifier: 0.15.6 version: 0.15.6 @@ -66,7 +66,7 @@ importers: version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) ansi-colors: specifier: ^4.1.3 version: 4.1.3 @@ -144,7 +144,7 @@ importers: version: 5.9.3 vitest: specifier: ^3.1.4 - version: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + version: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3) zod: specifier: 3.24.4 version: 3.24.4 @@ -247,7 +247,7 @@ importers: version: 8.18.1 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) packages/cli: dependencies: @@ -275,7 +275,7 @@ importers: version: link:../app '@shopify/cli-hydrogen': specifier: 11.1.10 - version: 11.1.10(@graphql-codegen/cli@6.0.1(@parcel/watcher@2.5.6)(@types/node@18.19.70)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql-config@5.1.5(@types/node@22.19.15)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql@16.10.0)(react-dom@19.2.4(react@18.3.1))(react@18.3.1)(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) + version: 11.1.10(@graphql-codegen/cli@6.0.1(@parcel/watcher@2.5.6)(@types/node@18.19.70)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql-config@5.1.5(@types/node@22.19.15)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql@16.10.0)(react-dom@19.2.4(react@18.3.1))(react@18.3.1)(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3)) '@shopify/cli-kit': specifier: 3.92.0 version: link:../cli-kit @@ -293,7 +293,7 @@ importers: version: 3.0.0 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) esbuild-plugin-copy: specifier: ^2.1.1 version: 2.1.1(esbuild@0.27.4) @@ -513,7 +513,7 @@ importers: version: 3.0.4 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) msw: specifier: ^2.7.1 version: 2.12.10(@types/node@22.19.15)(typescript@5.9.3) @@ -541,7 +541,7 @@ importers: version: link:../cli-kit '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) esbuild-plugin-copy: specifier: ^2.1.1 version: 2.1.1(esbuild@0.27.4) @@ -583,7 +583,7 @@ importers: version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) '@vitest/eslint-plugin': specifier: 1.1.44 - version: 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) debug: specifier: 4.4.0 version: 4.4.0(supports-color@8.1.1) @@ -639,7 +639,7 @@ importers: devDependencies: '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) packages/plugin-did-you-mean: dependencies: @@ -655,7 +655,7 @@ importers: devDependencies: '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) packages/theme: dependencies: @@ -678,15 +678,15 @@ importers: specifier: 1.15.9 version: 1.15.9 yaml: - specifier: 2.7.0 - version: 2.7.0 + specifier: 2.8.3 + version: 2.8.3 devDependencies: '@shopify/theme-hot-reload': specifier: ^0.0.18 version: 0.0.18 '@vitest/coverage-istanbul': specifier: ^3.1.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0)) + version: 3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) node-stream-zip: specifier: ^1.15.0 version: 1.15.0 @@ -738,7 +738,7 @@ importers: version: 18.3.7(@types/react@18.3.12) '@vitejs/plugin-react': specifier: ^5.1.4 - version: 5.1.4(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) + version: 5.1.4(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3)) jsdom: specifier: ^25.0.0 version: 25.0.1 @@ -747,7 +747,7 @@ importers: version: 1.97.3 vite: specifier: 6.4.1 - version: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + version: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) packages/ui-extensions-server-kit: devDependencies: @@ -759,7 +759,7 @@ importers: version: 18.3.12 '@vitejs/plugin-react': specifier: ^5.1.4 - version: 5.1.4(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) + version: 5.1.4(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3)) jsdom: specifier: ^25.0.0 version: 25.0.1 @@ -771,7 +771,7 @@ importers: version: 18.3.1(react@18.3.1) vite: specifier: 6.4.1 - version: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + version: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) packages/ui-extensions-test-utils: devDependencies: @@ -8596,8 +8596,8 @@ packages: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} - undici@7.24.5: - resolution: {integrity: sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==} + undici@7.24.6: + resolution: {integrity: sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -8938,8 +8938,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} engines: {node: '>= 6'} yaml@2.7.0: @@ -8952,6 +8952,11 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -10948,7 +10953,7 @@ snapshots: string-env-interpolation: 1.0.1 ts-log: 2.2.7 tslib: 2.8.1 - yaml: 2.7.0 + yaml: 2.8.3 yargs: 17.7.2 optionalDependencies: '@parcel/watcher': 2.5.6 @@ -12574,7 +12579,7 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} - '@shopify/cli-hydrogen@11.1.10(@graphql-codegen/cli@6.0.1(@parcel/watcher@2.5.6)(@types/node@18.19.70)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql-config@5.1.5(@types/node@22.19.15)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql@16.10.0)(react-dom@19.2.4(react@18.3.1))(react@18.3.1)(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2))': + '@shopify/cli-hydrogen@11.1.10(@graphql-codegen/cli@6.0.1(@parcel/watcher@2.5.6)(@types/node@18.19.70)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql-config@5.1.5(@types/node@22.19.15)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3))(graphql@16.10.0)(react-dom@19.2.4(react@18.3.1))(react@18.3.1)(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3))': dependencies: '@ast-grep/napi': 0.34.1 '@oclif/core': 3.26.5 @@ -12600,19 +12605,19 @@ snapshots: optionalDependencies: '@graphql-codegen/cli': 6.0.1(@parcel/watcher@2.5.6)(@types/node@18.19.70)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3) graphql-config: 5.1.5(@types/node@22.19.15)(crossws@0.3.5)(graphql@16.10.0)(typescript@5.9.3) - vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) transitivePeerDependencies: - graphql - react - react-dom - '@shopify/eslint-plugin-cli@file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@shopify/eslint-plugin-cli@file:packages/eslint-plugin-cli(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3))': dependencies: '@babel/core': 7.27.4 '@shopify/eslint-plugin': 50.0.0(@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1)(typescript@5.9.3) '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2)) + '@vitest/eslint-plugin': 1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3)) debug: 4.4.0(supports-color@8.1.1) eslint: 9.39.3(jiti@2.6.1) eslint-config-prettier: 10.1.5(eslint@9.39.3(jiti@2.6.1)) @@ -13504,7 +13509,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react@5.1.4(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.4(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -13512,27 +13517,11 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color - - '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': - dependencies: - '@istanbuljs/schema': 0.1.3 - debug: 4.4.3(supports-color@8.1.1) - istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.3 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 - istanbul-reports: 3.2.0 - magicast: 0.3.5 - test-exclude: 7.0.2 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0))': + '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3))': dependencies: '@istanbuljs/schema': 0.1.3 debug: 4.4.3(supports-color@8.1.1) @@ -13544,11 +13533,11 @@ snapshots: magicast: 0.3.5 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0) + vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3))': dependencies: '@istanbuljs/schema': 0.1.3 debug: 4.4.3(supports-color@8.1.1) @@ -13560,25 +13549,25 @@ snapshots: magicast: 0.3.5 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vitest: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3))': dependencies: '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.3(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vitest: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3) - '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.1.44(@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3))': dependencies: '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.3(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2) + vitest: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3) '@vitest/expect@3.2.4': dependencies: @@ -13588,23 +13577,23 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.10(@types/node@18.19.70)(typescript@5.9.3) - vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) - '@vitest/mocker@3.2.4(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.10(@types/node@22.19.15)(typescript@5.9.3) - vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) '@vitest/pretty-format@3.2.4': dependencies: @@ -14411,7 +14400,7 @@ snapshots: import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 - yaml: 1.10.2 + yaml: 1.10.3 cosmiconfig@8.3.6(typescript@5.9.3): dependencies: @@ -16311,7 +16300,7 @@ snapshots: saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 6.0.1 - undici: 7.24.5 + undici: 7.24.6 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 @@ -16889,7 +16878,7 @@ snapshots: tree-kill: 1.2.2 tsconfig-paths: 4.2.0 tslib: 2.8.1 - yaml: 2.7.0 + yaml: 2.8.3 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: @@ -16941,7 +16930,7 @@ snapshots: tree-kill: 1.2.2 tsconfig-paths: 4.2.0 tslib: 2.8.1 - yaml: 2.7.0 + yaml: 2.8.3 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: @@ -17285,7 +17274,7 @@ snapshots: escape-string-regexp: 5.0.0 fast-glob: 3.3.3 matcher: 5.0.0 - yaml: 2.7.0 + yaml: 2.8.3 transitivePeerDependencies: - supports-color @@ -18511,7 +18500,7 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.24.5: + undici@7.24.6: optional: true unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -18606,34 +18595,13 @@ snapshots: validate-npm-package-name@5.0.1: {} - vite-node@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2): - dependencies: - cac: 6.7.14 - debug: 4.4.3(supports-color@8.1.1) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite-node@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.7.0): + vite-node@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.7.0) + vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -18648,13 +18616,13 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2): + vite-node@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -18669,7 +18637,7 @@ snapshots: - tsx - yaml - vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2): + vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -18682,9 +18650,9 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 sass: 1.97.3 - yaml: 2.8.2 + yaml: 2.8.3 - vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.7.0): + vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -18697,28 +18665,13 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 sass: 1.97.3 - yaml: 2.7.0 + yaml: 2.8.3 - vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2): - dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.59.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.19.15 - fsevents: 2.3.3 - jiti: 2.6.1 - sass: 1.97.3 - yaml: 2.8.2 - - vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2): + vitest@3.2.4(@types/node@18.19.70)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@18.19.70)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -18736,8 +18689,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) + vite-node: 3.2.4(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 18.19.70 @@ -18756,11 +18709,11 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.7.0): + vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.3): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -18778,50 +18731,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.7.0) - vite-node: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.7.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 22.19.15 - jsdom: 28.1.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vitest@3.2.4(@types/node@22.19.15)(jiti@2.6.1)(jsdom@28.1.0)(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(sass@1.97.3)(yaml@2.8.2): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.12.10(@types/node@22.19.15)(typescript@5.9.3))(vite@6.4.1(@types/node@18.19.70)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3(supports-color@8.1.1) - expect-type: 1.3.0 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) + vite-node: 3.2.4(@types/node@22.19.15)(jiti@2.6.1)(sass@1.97.3)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.15 @@ -19018,12 +18929,14 @@ snapshots: yallist@3.1.1: {} - yaml@1.10.2: {} + yaml@1.10.3: {} yaml@2.7.0: {} yaml@2.8.2: {} + yaml@2.8.3: {} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 From 0d393519da4e0f76df5faeadb72396a06380d6be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:02:46 +0000 Subject: [PATCH 03/11] Bump nx from 22.5.4 to 22.6.1 in the nx group across 1 directory Bumps the nx group with 1 update in the / directory: [nx](https://github.com/nrwl/nx/tree/HEAD/packages/nx). Updates `nx` from 22.5.4 to 22.6.1 - [Release notes](https://github.com/nrwl/nx/releases) - [Commits](https://github.com/nrwl/nx/commits/22.6.1/packages/nx) --- updated-dependencies: - dependency-name: nx dependency-version: 22.6.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: nx ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 221 ++++++++++++++++++++++++++----------------------- 2 files changed, 117 insertions(+), 106 deletions(-) diff --git a/package.json b/package.json index be68e78717a..cd81b6826d4 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "knip": "5.59.1", "liquidjs": "10.25.0", "node-fetch": "^3.3.2", - "nx": "22.5.4", + "nx": "22.6.1", "oclif": "4.22.96", "octokit-plugin-create-pull-request": "^3.12.2", "pathe": "1.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9aeea964aa2..c5d16875d23 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,7 +42,7 @@ importers: version: 5.0.2(graphql@16.10.0) '@nx/eslint-plugin': specifier: 22.0.2 - version: 22.0.2(@babel/traverse@7.29.0)(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-config-prettier@10.1.5(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(nx@22.5.4)(typescript@5.9.3) + version: 22.0.2(@babel/traverse@7.29.0)(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-config-prettier@10.1.5(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(nx@22.6.1)(typescript@5.9.3) '@nx/workspace': specifier: 22.0.2 version: 22.0.2 @@ -116,8 +116,8 @@ importers: specifier: ^3.3.2 version: 3.3.2 nx: - specifier: 22.5.4 - version: 22.5.4 + specifier: 22.6.1 + version: 22.6.1 oclif: specifier: 4.22.96 version: 4.22.96(@types/node@18.19.70) @@ -1842,14 +1842,14 @@ packages: resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} engines: {node: '>=20.19.0'} - '@emnapi/core@1.8.1': - resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} '@envelop/core@5.5.1': resolution: {integrity: sha512-3DQg8sFskDo386TkL5j12jyRAdip/8yzK3x7YGbZBgobZ4aKXrvDU0GppU0SnmrpQnNaiTUsxBs9LKkwQ/eyvw==} @@ -2710,8 +2710,8 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} - '@jest/diff-sequences@30.0.1': - resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} + '@jest/diff-sequences@30.3.0': + resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/get-type@30.1.0': @@ -2753,6 +2753,9 @@ packages: '@kwsites/promise-deferred@1.1.1': resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + '@ltd/j-toml@1.38.0': + resolution: {integrity: sha512-lYtBcmvHustHQtg4X7TXUu1Xa/tbLC3p2wLvgQI+fWVySguVZJF60Snxijw5EiohumxZbR10kWYFFebh1zotiw==} + '@luckycatfactory/esbuild-graphql-loader@3.8.1': resolution: {integrity: sha512-ovONIUSW6NAlCpiPMaVw4PpdFoO3Kqi8TGQ2hTtjKTQTdPpSOdekPI1ZRnwciTeUn0yCAQk7M2xdrbIZeTh6pw==} peerDependencies: @@ -2821,8 +2824,8 @@ packages: cpu: [arm64] os: [darwin] - '@nx/nx-darwin-arm64@22.5.4': - resolution: {integrity: sha512-Ib9znwSLQZSZ/9hhg5ODplpNhE/RhGVXzdfRj6YonTuWSj/kH3dLMio+4JEkjRdTQVm06cDW0KdwSgnwovqMGg==} + '@nx/nx-darwin-arm64@22.6.1': + resolution: {integrity: sha512-lixkEBGFdEsUiqEZg9LIyjfiTv12Sg1Es/yUgrdOQUAZu+5oiUPMoybyBwrvINl+fZw+PLh66jOmB4GSP2aUMQ==} cpu: [arm64] os: [darwin] @@ -2831,8 +2834,8 @@ packages: cpu: [x64] os: [darwin] - '@nx/nx-darwin-x64@22.5.4': - resolution: {integrity: sha512-DjyXuQMc93MPU2XdRsJYjzbv1tgCzMi+zm7O0gc4x3h+ECFjKkjzQBg67pqGdhE3TV27MAlVRKrgHStyK9iigg==} + '@nx/nx-darwin-x64@22.6.1': + resolution: {integrity: sha512-HvgtOtuWnEf0dpfWb05N0ptdFg040YgzsKFhXg6+qaBJg5Hg0e0AXPKaSgh2PCqCIDlKu40YtwVgF7KXxXAGlA==} cpu: [x64] os: [darwin] @@ -2841,8 +2844,8 @@ packages: cpu: [x64] os: [freebsd] - '@nx/nx-freebsd-x64@22.5.4': - resolution: {integrity: sha512-DhxdP8AhIfN0yCtFhZQcbp32MVN3L7UiTotYqqnOgwW922NRGSd5e+KEAWiJVrIO6TdgnI7prxpg1hfQQK0WDw==} + '@nx/nx-freebsd-x64@22.6.1': + resolution: {integrity: sha512-g2wUltGX+7/+mdTV5d6ODa0ylrNu/krgb9YdrsbhW6oZeXYm2LeLOAnYqIlL/Kx140NLrb5Kcz7bi7JrBAw4Ow==} cpu: [x64] os: [freebsd] @@ -2851,8 +2854,8 @@ packages: cpu: [arm] os: [linux] - '@nx/nx-linux-arm-gnueabihf@22.5.4': - resolution: {integrity: sha512-pv1x1afTaLAOxPxVhQneLeXgjclp11f9ORxR7jA4E86bSgc9OL92dLSCkXtLQzqPNOej6SZ2fO+PPHVMZwtaPQ==} + '@nx/nx-linux-arm-gnueabihf@22.6.1': + resolution: {integrity: sha512-TTqisFPAPrj35EihvzotBbajS+0bX++PQggmRVmDmGwSTrpySRJwZnKNHYDqP6s9tigDvkNJOJftK+GkBEFRRA==} cpu: [arm] os: [linux] @@ -2861,8 +2864,8 @@ packages: cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-gnu@22.5.4': - resolution: {integrity: sha512-mPji9PzleWPvXpmFDKaXpTymRgZkk/hW8JHGhvEZpKHHXMYgTGWC+BqOEM2A4dYC4bu4fi9RrteL7aouRRWJoQ==} + '@nx/nx-linux-arm64-gnu@22.6.1': + resolution: {integrity: sha512-uIkPcanSTIcyh7/6LOoX0YpGO/7GkVhMRgyM9Mg/7ItFjCtRaeuPEPrJESsaNeB5zIVVhI4cXbGrM9NDnagiiw==} cpu: [arm64] os: [linux] @@ -2871,8 +2874,8 @@ packages: cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-musl@22.5.4': - resolution: {integrity: sha512-hF/HvEhbCjcFpTgY7RbP1tUTbp0M1adZq4ckyW8mwhDWQ/MDsc8FnOHwCO3Bzy9ZeJM0zQUES6/m0Onz8geaEA==} + '@nx/nx-linux-arm64-musl@22.6.1': + resolution: {integrity: sha512-eqkG8s/7remiRZ1Lo2zIrFLSNsQ/0x9fAj++CV1nqFE+rfykPQhC48F8pqsq6tUQpI5HqRQEfQgv4CnFNpLR+w==} cpu: [arm64] os: [linux] @@ -2881,8 +2884,8 @@ packages: cpu: [x64] os: [linux] - '@nx/nx-linux-x64-gnu@22.5.4': - resolution: {integrity: sha512-1+vicSYEOtc7CNMoRCjo59no4gFe8w2nGIT127wk1yeW3EJzRVNlOA7Deu10NUUbzLeOvHc8EFOaU7clT+F7XQ==} + '@nx/nx-linux-x64-gnu@22.6.1': + resolution: {integrity: sha512-6DhSupCcDa6BYzQ48qsMK4LIdIO+y4E+4xuUBkX2YTGOZh58gctELCv7Gi6/FhiC8rzVzM7hDcygOvHCGc30zA==} cpu: [x64] os: [linux] @@ -2891,8 +2894,8 @@ packages: cpu: [x64] os: [linux] - '@nx/nx-linux-x64-musl@22.5.4': - resolution: {integrity: sha512-/KjndxVB14yU0SJOhqADHOWoTy4Y45h5RjW3cxcXlPSJZz7ar1FnlLne1rWMMMUttepc8ku+3T//SGKi2eu+Nw==} + '@nx/nx-linux-x64-musl@22.6.1': + resolution: {integrity: sha512-QqtfaBhdfLRKGucpP8RSv7KJ51XRWpfUcXPhkb/1dKP/b9/Z0kpaCgczGHdrAtX9m6haWw+sQXYGxnStZIg/TQ==} cpu: [x64] os: [linux] @@ -2901,8 +2904,8 @@ packages: cpu: [arm64] os: [win32] - '@nx/nx-win32-arm64-msvc@22.5.4': - resolution: {integrity: sha512-CrYt9FwhjOI6ZNy/G6YHLJmZuXCFJ24BCxugPXiZ7knDx7eGrr7owGgfht4SSiK3KCX40CvWCBJfqR4ZSgaSUA==} + '@nx/nx-win32-arm64-msvc@22.6.1': + resolution: {integrity: sha512-8pTWXphY5IIgY3edZ5SfzP8yPjBqoAxRV5snAYDctF4e0OC1nDOUims70jLesMle8DTSWiHPSfbLVfp2HkU9WQ==} cpu: [arm64] os: [win32] @@ -2911,8 +2914,8 @@ packages: cpu: [x64] os: [win32] - '@nx/nx-win32-x64-msvc@22.5.4': - resolution: {integrity: sha512-g5YByv4XsYwsYZvFe24A9bvfhZA+mwtIQt6qZtEVduZTT1hfhIsq0LXGHhkGoFLYwRMXSracWOqkalY0KT4IQw==} + '@nx/nx-win32-x64-msvc@22.6.1': + resolution: {integrity: sha512-XMYrtsR5O39uNR4fVpFs65rVB09FyLXvUM735r2rO7IUWWHxHWTAgVcc+gqQaAchBPqR9f1q+3u2i1Inub3Cdw==} cpu: [x64] os: [win32] @@ -4479,8 +4482,8 @@ packages: resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} - axios@1.13.5: - resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} + axios@1.13.6: + resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} @@ -4579,6 +4582,10 @@ packages: resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -4684,6 +4691,10 @@ packages: resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case-all@1.0.15: resolution: {integrity: sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==} @@ -6513,8 +6524,8 @@ packages: engines: {node: '>=10'} hasBin: true - jest-diff@30.2.0: - resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} + jest-diff@30.3.0: + resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jiti@2.6.1: @@ -6908,10 +6919,6 @@ packages: minimatch@3.1.4: resolution: {integrity: sha512-twmL+S8+7yIsE9wsqgzU3E8/LumN3M3QELrBZ20OdmQ9jB2JvW5oZtBEmft84k/Gs5CG9mqtWc6Y9vW+JEzGxw==} - minimatch@5.1.8: - resolution: {integrity: sha512-7RN35vit8DeBclkofOVmBY0eDAZZQd1HzmukRdSyz95CRh8FT54eqnbj0krQr3mrHR6sfRyYkyhwBWjoV5uqlQ==} - engines: {node: '>=10'} - minimatch@5.1.9: resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} @@ -7188,8 +7195,8 @@ packages: '@swc/core': optional: true - nx@22.5.4: - resolution: {integrity: sha512-L8wL7uCjnmpyvq4r2mN9s+oriUE4lY+mX9VgOpjj0ucRd5nzaEaBQppVs0zQGkbKC0BnHS8PGtnAglspd5Gh1Q==} + nx@22.6.1: + resolution: {integrity: sha512-b4eo52o5aCVt3oG6LPYvD2Cul3JFBMgr2p9OjMBIo6oU6QfSR693H2/UuUMepLtO6jcIniPKOcIrf6Ue8aXAww==} hasBin: true peerDependencies: '@swc-node/register': ^1.11.1 @@ -7540,8 +7547,8 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - pretty-format@30.2.0: - resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} + pretty-format@30.3.0: + resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} printable-characters@1.0.42: @@ -10657,16 +10664,16 @@ snapshots: '@csstools/css-tokenizer@4.0.0': optional: true - '@emnapi/core@1.8.1': + '@emnapi/core@1.9.1': dependencies: - '@emnapi/wasi-threads': 1.1.0 + '@emnapi/wasi-threads': 1.2.0 tslib: 2.8.1 - '@emnapi/runtime@1.8.1': + '@emnapi/runtime@1.9.1': dependencies: tslib: 2.8.1 - '@emnapi/wasi-threads@1.1.0': + '@emnapi/wasi-threads@1.2.0': dependencies: tslib: 2.8.1 @@ -11679,7 +11686,7 @@ snapshots: '@istanbuljs/schema@0.1.3': {} - '@jest/diff-sequences@30.0.1': {} + '@jest/diff-sequences@30.3.0': {} '@jest/get-type@30.1.0': {} @@ -11723,6 +11730,8 @@ snapshots: '@kwsites/promise-deferred@1.1.1': {} + '@ltd/j-toml@1.38.0': {} + '@luckycatfactory/esbuild-graphql-loader@3.8.1(esbuild@0.27.4)(graphql-tag@2.12.6(graphql@16.10.0))(graphql@16.10.0)': dependencies: esbuild: 0.27.4 @@ -11765,15 +11774,15 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.8.1 - '@emnapi/runtime': 1.8.1 + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 '@tybys/wasm-util': 0.10.1 optional: true '@napi-rs/wasm-runtime@0.2.4': dependencies: - '@emnapi/core': 1.8.1 - '@emnapi/runtime': 1.8.1 + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 '@tybys/wasm-util': 0.9.0 '@nodelib/fs.scandir@2.1.5': @@ -11799,21 +11808,21 @@ snapshots: tslib: 2.8.1 yargs-parser: 21.1.1 - '@nx/devkit@22.0.2(nx@22.5.4)': + '@nx/devkit@22.0.2(nx@22.6.1)': dependencies: '@zkochan/js-yaml': 0.0.7 ejs: 3.1.10 enquirer: 2.3.6 minimatch: 9.0.3 - nx: 22.5.4 + nx: 22.6.1 semver: 7.6.3 tslib: 2.8.1 yargs-parser: 21.1.1 - '@nx/eslint-plugin@22.0.2(@babel/traverse@7.29.0)(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-config-prettier@10.1.5(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(nx@22.5.4)(typescript@5.9.3)': + '@nx/eslint-plugin@22.0.2(@babel/traverse@7.29.0)(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-config-prettier@10.1.5(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(nx@22.6.1)(typescript@5.9.3)': dependencies: - '@nx/devkit': 22.0.2(nx@22.5.4) - '@nx/js': 22.0.2(@babel/traverse@7.29.0)(nx@22.5.4) + '@nx/devkit': 22.0.2(nx@22.6.1) + '@nx/js': 22.0.2(@babel/traverse@7.29.0)(nx@22.6.1) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.9.3) '@typescript-eslint/parser': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) @@ -11837,7 +11846,7 @@ snapshots: - typescript - verdaccio - '@nx/js@22.0.2(@babel/traverse@7.29.0)(nx@22.5.4)': + '@nx/js@22.0.2(@babel/traverse@7.29.0)(nx@22.6.1)': dependencies: '@babel/core': 7.27.4 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.27.4) @@ -11846,7 +11855,7 @@ snapshots: '@babel/preset-env': 7.29.0(@babel/core@7.27.4) '@babel/preset-typescript': 7.28.5(@babel/core@7.27.4) '@babel/runtime': 7.28.6 - '@nx/devkit': 22.0.2(nx@22.5.4) + '@nx/devkit': 22.0.2(nx@22.6.1) '@nx/workspace': 22.0.2 '@zkochan/js-yaml': 0.0.7 babel-plugin-const-enum: 1.2.0(@babel/core@7.27.4) @@ -11876,61 +11885,61 @@ snapshots: '@nx/nx-darwin-arm64@22.0.2': optional: true - '@nx/nx-darwin-arm64@22.5.4': + '@nx/nx-darwin-arm64@22.6.1': optional: true '@nx/nx-darwin-x64@22.0.2': optional: true - '@nx/nx-darwin-x64@22.5.4': + '@nx/nx-darwin-x64@22.6.1': optional: true '@nx/nx-freebsd-x64@22.0.2': optional: true - '@nx/nx-freebsd-x64@22.5.4': + '@nx/nx-freebsd-x64@22.6.1': optional: true '@nx/nx-linux-arm-gnueabihf@22.0.2': optional: true - '@nx/nx-linux-arm-gnueabihf@22.5.4': + '@nx/nx-linux-arm-gnueabihf@22.6.1': optional: true '@nx/nx-linux-arm64-gnu@22.0.2': optional: true - '@nx/nx-linux-arm64-gnu@22.5.4': + '@nx/nx-linux-arm64-gnu@22.6.1': optional: true '@nx/nx-linux-arm64-musl@22.0.2': optional: true - '@nx/nx-linux-arm64-musl@22.5.4': + '@nx/nx-linux-arm64-musl@22.6.1': optional: true '@nx/nx-linux-x64-gnu@22.0.2': optional: true - '@nx/nx-linux-x64-gnu@22.5.4': + '@nx/nx-linux-x64-gnu@22.6.1': optional: true '@nx/nx-linux-x64-musl@22.0.2': optional: true - '@nx/nx-linux-x64-musl@22.5.4': + '@nx/nx-linux-x64-musl@22.6.1': optional: true '@nx/nx-win32-arm64-msvc@22.0.2': optional: true - '@nx/nx-win32-arm64-msvc@22.5.4': + '@nx/nx-win32-arm64-msvc@22.6.1': optional: true '@nx/nx-win32-x64-msvc@22.0.2': optional: true - '@nx/nx-win32-x64-msvc@22.5.4': + '@nx/nx-win32-x64-msvc@22.6.1': optional: true '@nx/workspace@22.0.2': @@ -13200,7 +13209,7 @@ snapshots: '@ts-morph/common@0.18.1': dependencies: fast-glob: 3.3.3 - minimatch: 5.1.8 + minimatch: 5.1.9 mkdirp: 1.0.4 path-browserify: 1.0.1 @@ -13896,7 +13905,7 @@ snapshots: axe-core@4.11.1: {} - axios@1.13.5: + axios@1.13.6: dependencies: follow-redirects: 1.15.11 form-data: 4.0.5 @@ -14008,6 +14017,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -14138,6 +14151,8 @@ snapshots: chalk@5.4.1: {} + chalk@5.6.2: {} + change-case-all@1.0.15: dependencies: change-case: 4.1.2 @@ -14977,7 +14992,7 @@ snapshots: eslint: 9.39.3(jiti@2.6.1) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 - minimatch: 9.0.8 + minimatch: 10.2.4 semver: 7.7.4 stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 @@ -15550,7 +15565,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.8 + minimatch: 5.1.9 once: 1.4.0 global-agent@3.0.0: @@ -15642,7 +15657,7 @@ snapshots: cosmiconfig: 8.3.6(typescript@5.9.3) graphql: 16.10.0 jiti: 2.6.1 - minimatch: 9.0.8 + minimatch: 9.0.9 string-env-interpolation: 1.0.1 tslib: 2.8.1 transitivePeerDependencies: @@ -15665,7 +15680,7 @@ snapshots: cosmiconfig: 8.3.6(typescript@5.9.3) graphql: 16.10.0 jiti: 2.6.1 - minimatch: 9.0.8 + minimatch: 9.0.9 string-env-interpolation: 1.0.1 tslib: 2.8.1 transitivePeerDependencies: @@ -15872,7 +15887,7 @@ snapshots: ansi-escapes: 7.3.0 ansi-styles: 6.2.3 auto-bind: 5.0.1 - chalk: 5.4.1 + chalk: 5.6.2 cli-boxes: 3.0.0 cli-cursor: 4.0.0 cli-truncate: 4.0.0 @@ -16227,12 +16242,12 @@ snapshots: filelist: 1.0.6 picocolors: 1.1.1 - jest-diff@30.2.0: + jest-diff@30.3.0: dependencies: - '@jest/diff-sequences': 30.0.1 + '@jest/diff-sequences': 30.3.0 '@jest/get-type': 30.1.0 chalk: 4.1.2 - pretty-format: 30.2.0 + pretty-format: 30.3.0 jiti@2.6.1: {} @@ -16495,7 +16510,7 @@ snapshots: ansi-escapes: 7.3.0 cli-cursor: 5.0.0 slice-ansi: 7.1.2 - strip-ansi: 7.1.0 + strip-ansi: 7.2.0 wrap-ansi: 9.0.2 loglevel@1.9.2: {} @@ -16635,16 +16650,12 @@ snapshots: minimatch@10.2.4: dependencies: - brace-expansion: 5.0.3 + brace-expansion: 5.0.5 minimatch@3.1.4: dependencies: brace-expansion: 1.1.12 - minimatch@5.1.8: - dependencies: - brace-expansion: 2.0.2 - minimatch@5.1.9: dependencies: brace-expansion: 2.0.2 @@ -16850,7 +16861,7 @@ snapshots: '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.2 '@zkochan/js-yaml': 0.0.7 - axios: 1.13.5 + axios: 1.13.6 chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 @@ -16862,7 +16873,7 @@ snapshots: flat: 5.0.2 front-matter: 4.0.2 ignore: 7.0.5 - jest-diff: 30.2.0 + jest-diff: 30.3.0 jsonc-parser: 3.2.0 lines-and-columns: 2.0.3 minimatch: 9.0.3 @@ -16895,13 +16906,14 @@ snapshots: transitivePeerDependencies: - debug - nx@22.5.4: + nx@22.6.1: dependencies: + '@ltd/j-toml': 1.38.0 '@napi-rs/wasm-runtime': 0.2.4 '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.2 '@zkochan/js-yaml': 0.0.7 - axios: 1.13.5 + axios: 1.13.6 cli-cursor: 3.1.0 cli-spinners: 2.6.1 cliui: 8.0.1 @@ -16913,17 +16925,16 @@ snapshots: flat: 5.0.2 front-matter: 4.0.2 ignore: 7.0.5 - jest-diff: 30.2.0 + jest-diff: 30.3.0 jsonc-parser: 3.2.0 lines-and-columns: 2.0.3 minimatch: 10.2.4 - node-machine-id: 1.1.12 npm-run-path: 4.0.1 open: 8.4.2 ora: 5.3.0 picocolors: 1.1.1 resolve.exports: 2.0.3 - semver: 7.6.3 + semver: 7.7.4 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.5 @@ -16934,16 +16945,16 @@ snapshots: yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@nx/nx-darwin-arm64': 22.5.4 - '@nx/nx-darwin-x64': 22.5.4 - '@nx/nx-freebsd-x64': 22.5.4 - '@nx/nx-linux-arm-gnueabihf': 22.5.4 - '@nx/nx-linux-arm64-gnu': 22.5.4 - '@nx/nx-linux-arm64-musl': 22.5.4 - '@nx/nx-linux-x64-gnu': 22.5.4 - '@nx/nx-linux-x64-musl': 22.5.4 - '@nx/nx-win32-arm64-msvc': 22.5.4 - '@nx/nx-win32-x64-msvc': 22.5.4 + '@nx/nx-darwin-arm64': 22.6.1 + '@nx/nx-darwin-x64': 22.6.1 + '@nx/nx-freebsd-x64': 22.6.1 + '@nx/nx-linux-arm-gnueabihf': 22.6.1 + '@nx/nx-linux-arm64-gnu': 22.6.1 + '@nx/nx-linux-arm64-musl': 22.6.1 + '@nx/nx-linux-x64-gnu': 22.6.1 + '@nx/nx-linux-x64-musl': 22.6.1 + '@nx/nx-win32-arm64-msvc': 22.6.1 + '@nx/nx-win32-x64-msvc': 22.6.1 transitivePeerDependencies: - debug @@ -17062,7 +17073,7 @@ snapshots: bl: 4.1.0 chalk: 4.1.2 cli-cursor: 3.1.0 - cli-spinners: 2.9.2 + cli-spinners: 2.6.1 is-interactive: 1.0.0 log-symbols: 4.1.0 strip-ansi: 6.0.1 @@ -17329,7 +17340,7 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - pretty-format@30.2.0: + pretty-format@30.3.0: dependencies: '@jest/schemas': 30.0.5 ansi-styles: 5.2.0 @@ -17540,7 +17551,7 @@ snapshots: readdir-glob@1.1.3: dependencies: - minimatch: 5.1.8 + minimatch: 5.1.9 readdirp@3.6.0: dependencies: From 203c7ac0363495b8f7ecd43874634353f4b71798 Mon Sep 17 00:00:00 2001 From: Donald Merand Date: Fri, 20 Mar 2026 15:45:43 -0400 Subject: [PATCH 04/11] --json -j should not use color --- .../commands/app-config-validate.doc.ts | 34 +++++++++++++ .../examples/app-config-validate.example.sh | 1 + .../app-config-validate.interface.ts | 38 +++++++++++++++ .../interfaces/app-function-info.interface.ts | 2 +- .../app-function-replay.interface.ts | 2 +- .../interfaces/app-function-run.interface.ts | 2 +- .../commands/interfaces/app-info.interface.ts | 2 +- .../commands/interfaces/app-logs.interface.ts | 2 +- .../interfaces/app-versions-list.interface.ts | 2 +- .../interfaces/organization-list.interface.ts | 2 +- .../interfaces/theme-duplicate.interface.ts | 2 +- .../interfaces/theme-info.interface.ts | 2 +- .../interfaces/theme-list.interface.ts | 2 +- .../interfaces/theme-profile.interface.ts | 2 +- .../interfaces/theme-push.interface.ts | 2 +- .../generated/generated_docs_data.json | 48 +++++++++---------- packages/cli-kit/src/public/node/cli.test.ts | 21 ++++++++ packages/cli-kit/src/public/node/cli.ts | 5 +- packages/cli/README.md | 25 +++++----- packages/cli/oclif.manifest.json | 24 +++++----- 20 files changed, 159 insertions(+), 61 deletions(-) create mode 100644 docs-shopify.dev/commands/app-config-validate.doc.ts create mode 100644 docs-shopify.dev/commands/examples/app-config-validate.example.sh create mode 100644 docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts diff --git a/docs-shopify.dev/commands/app-config-validate.doc.ts b/docs-shopify.dev/commands/app-config-validate.doc.ts new file mode 100644 index 00000000000..cedde571a3e --- /dev/null +++ b/docs-shopify.dev/commands/app-config-validate.doc.ts @@ -0,0 +1,34 @@ +// This is an autogenerated file. Don't edit this file manually. +import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs' + +const data: ReferenceEntityTemplateSchema = { + name: 'app config validate', + description: `Validates the selected app configuration file and all extension configurations against their schemas and reports any errors found.`, + overviewPreviewDescription: `Validate your app configuration and extensions.`, + type: 'command', + isVisualComponent: false, + defaultExample: { + codeblock: { + tabs: [ + { + title: 'app config validate', + code: './examples/app-config-validate.example.sh', + language: 'bash', + }, + ], + title: 'app config validate', + }, + }, + definitions: [ + { + title: 'Flags', + description: 'The following flags are available for the `app config validate` command:', + type: 'appconfigvalidate', + }, + ], + category: 'app', + related: [ + ], +} + +export default data \ No newline at end of file diff --git a/docs-shopify.dev/commands/examples/app-config-validate.example.sh b/docs-shopify.dev/commands/examples/app-config-validate.example.sh new file mode 100644 index 00000000000..8d7e3ca54f0 --- /dev/null +++ b/docs-shopify.dev/commands/examples/app-config-validate.example.sh @@ -0,0 +1 @@ +shopify app config validate [flags] \ No newline at end of file diff --git a/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts b/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts new file mode 100644 index 00000000000..81b76932f0f --- /dev/null +++ b/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts @@ -0,0 +1,38 @@ +// This is an autogenerated file. Don't edit this file manually. +export interface appconfigvalidate { + /** + * The Client ID of your app. + * @environment SHOPIFY_FLAG_CLIENT_ID + */ + '--client-id '?: string + + /** + * The name of the app configuration. + * @environment SHOPIFY_FLAG_APP_CONFIG + */ + '-c, --config '?: string + + /** + * Disable color output. + * @environment SHOPIFY_FLAG_NO_COLOR + */ + '--no-color'?: '' + + /** + * The path to your app directory. + * @environment SHOPIFY_FLAG_PATH + */ + '--path '?: string + + /** + * Reset all your settings. + * @environment SHOPIFY_FLAG_RESET + */ + '--reset'?: '' + + /** + * Increase the verbosity of the output. + * @environment SHOPIFY_FLAG_VERBOSE + */ + '--verbose'?: '' +} diff --git a/docs-shopify.dev/commands/interfaces/app-function-info.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-info.interface.ts index 167ccc81019..5dc3d0ed135 100644 --- a/docs-shopify.dev/commands/interfaces/app-function-info.interface.ts +++ b/docs-shopify.dev/commands/interfaces/app-function-info.interface.ts @@ -13,7 +13,7 @@ export interface appfunctioninfo { '-c, --config '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts index 534052e7fcc..70bf6af0125 100644 --- a/docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts +++ b/docs-shopify.dev/commands/interfaces/app-function-replay.interface.ts @@ -13,7 +13,7 @@ export interface appfunctionreplay { '-c, --config '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/app-function-run.interface.ts b/docs-shopify.dev/commands/interfaces/app-function-run.interface.ts index 3e13075ee10..a37303ac33e 100644 --- a/docs-shopify.dev/commands/interfaces/app-function-run.interface.ts +++ b/docs-shopify.dev/commands/interfaces/app-function-run.interface.ts @@ -25,7 +25,7 @@ export interface appfunctionrun { '-i, --input '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/app-info.interface.ts b/docs-shopify.dev/commands/interfaces/app-info.interface.ts index 942bc6e9606..0c66843a421 100644 --- a/docs-shopify.dev/commands/interfaces/app-info.interface.ts +++ b/docs-shopify.dev/commands/interfaces/app-info.interface.ts @@ -13,7 +13,7 @@ export interface appinfo { '-c, --config '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/app-logs.interface.ts b/docs-shopify.dev/commands/interfaces/app-logs.interface.ts index 3ba6d882ff2..2ea79fb89d7 100644 --- a/docs-shopify.dev/commands/interfaces/app-logs.interface.ts +++ b/docs-shopify.dev/commands/interfaces/app-logs.interface.ts @@ -13,7 +13,7 @@ export interface applogs { '-c, --config '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts b/docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts index eda211aa75a..517f4ee5a34 100644 --- a/docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts +++ b/docs-shopify.dev/commands/interfaces/app-versions-list.interface.ts @@ -13,7 +13,7 @@ export interface appversionslist { '-c, --config '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/organization-list.interface.ts b/docs-shopify.dev/commands/interfaces/organization-list.interface.ts index a390905e246..84ca7073bb4 100644 --- a/docs-shopify.dev/commands/interfaces/organization-list.interface.ts +++ b/docs-shopify.dev/commands/interfaces/organization-list.interface.ts @@ -1,7 +1,7 @@ // This is an autogenerated file. Don't edit this file manually. export interface organizationlist { /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts b/docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts index 2f08109fa8b..33190b1d7be 100644 --- a/docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts +++ b/docs-shopify.dev/commands/interfaces/theme-duplicate.interface.ts @@ -13,7 +13,7 @@ export interface themeduplicate { '-f, --force'?: '' /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/theme-info.interface.ts b/docs-shopify.dev/commands/interfaces/theme-info.interface.ts index e327cdf8da7..7fd304c0ba7 100644 --- a/docs-shopify.dev/commands/interfaces/theme-info.interface.ts +++ b/docs-shopify.dev/commands/interfaces/theme-info.interface.ts @@ -13,7 +13,7 @@ export interface themeinfo { '-e, --environment '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/theme-list.interface.ts b/docs-shopify.dev/commands/interfaces/theme-list.interface.ts index 2c5b0da1f0f..d2880779a01 100644 --- a/docs-shopify.dev/commands/interfaces/theme-list.interface.ts +++ b/docs-shopify.dev/commands/interfaces/theme-list.interface.ts @@ -13,7 +13,7 @@ export interface themelist { '--id '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/theme-profile.interface.ts b/docs-shopify.dev/commands/interfaces/theme-profile.interface.ts index 97b29ed8760..8eee4acea34 100644 --- a/docs-shopify.dev/commands/interfaces/theme-profile.interface.ts +++ b/docs-shopify.dev/commands/interfaces/theme-profile.interface.ts @@ -7,7 +7,7 @@ export interface themeprofile { '-e, --environment '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/commands/interfaces/theme-push.interface.ts b/docs-shopify.dev/commands/interfaces/theme-push.interface.ts index 9f37a46e913..e9c22e4f71a 100644 --- a/docs-shopify.dev/commands/interfaces/theme-push.interface.ts +++ b/docs-shopify.dev/commands/interfaces/theme-push.interface.ts @@ -31,7 +31,7 @@ export interface themepush { '-x, --ignore '?: string /** - * Output the result as JSON. + * Output the result as JSON. Automatically disables color output. * @environment SHOPIFY_FLAG_JSON */ '-j, --json'?: '' diff --git a/docs-shopify.dev/generated/generated_docs_data.json b/docs-shopify.dev/generated/generated_docs_data.json index 8d43ba63afe..cf83eeb567c 100644 --- a/docs-shopify.dev/generated/generated_docs_data.json +++ b/docs-shopify.dev/generated/generated_docs_data.json @@ -1826,12 +1826,12 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appfunctioninfo {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appfunctioninfo {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -1927,7 +1927,7 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" }, @@ -1950,7 +1950,7 @@ "environmentValue": "SHOPIFY_FLAG_WATCH" } ], - "value": "export interface appfunctionreplay {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Specifies a log identifier to replay instead of selecting from a list. The identifier is provided in the output of `shopify app dev` and is the suffix of the log file name.\n * @environment SHOPIFY_FLAG_LOG\n */\n '-l, --log '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Re-run the function when the source code changes.\n * @environment SHOPIFY_FLAG_WATCH\n */\n '-w, --watch'?: ''\n}" + "value": "export interface appfunctionreplay {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Specifies a log identifier to replay instead of selecting from a list. The identifier is provided in the output of `shopify app dev` and is the suffix of the log file name.\n * @environment SHOPIFY_FLAG_LOG\n */\n '-l, --log '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Re-run the function when the source code changes.\n * @environment SHOPIFY_FLAG_WATCH\n */\n '-w, --watch'?: ''\n}" } } } @@ -2064,12 +2064,12 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appfunctionrun {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Name of the WebAssembly export to invoke.\n * @environment SHOPIFY_FLAG_EXPORT\n */\n '-e, --export '?: string\n\n /**\n * The input JSON to pass to the function. If omitted, standard input is used.\n * @environment SHOPIFY_FLAG_INPUT\n */\n '-i, --input '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appfunctionrun {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Name of the WebAssembly export to invoke.\n * @environment SHOPIFY_FLAG_EXPORT\n */\n '-e, --export '?: string\n\n /**\n * The input JSON to pass to the function. If omitted, standard input is used.\n * @environment SHOPIFY_FLAG_INPUT\n */\n '-i, --input '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your function directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -2697,12 +2697,12 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appinfo {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Outputs environment variables necessary for running and deploying web/.\n * @environment SHOPIFY_FLAG_OUTPUT_WEB_ENV\n */\n '--web-env'?: ''\n}" + "value": "export interface appinfo {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n\n /**\n * Outputs environment variables necessary for running and deploying web/.\n * @environment SHOPIFY_FLAG_OUTPUT_WEB_ENV\n */\n '--web-env'?: ''\n}" } } } @@ -3027,7 +3027,7 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" }, @@ -3041,7 +3041,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface applogs {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Filters output to the specified log source.\n * @environment SHOPIFY_FLAG_SOURCE\n */\n '--source '?: string\n\n /**\n * Filters output to the specified status (success or failure).\n * @environment SHOPIFY_FLAG_STATUS\n */\n '--status '?: string\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface applogs {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Filters output to the specified log source.\n * @environment SHOPIFY_FLAG_SOURCE\n */\n '--source '?: string\n\n /**\n * Filters output to the specified status (success or failure).\n * @environment SHOPIFY_FLAG_STATUS\n */\n '--status '?: string\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -3264,12 +3264,12 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appversionslist {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appversionslist {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -5730,12 +5730,12 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface organizationlist {\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface organizationlist {\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -6446,7 +6446,7 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" }, @@ -6478,7 +6478,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themeduplicate {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Force the duplicate operation to run without prompts or confirmations.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Name of the newly duplicated theme.\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeduplicate {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Force the duplicate operation to run without prompts or confirmations.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '-f, --force'?: ''\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Name of the newly duplicated theme.\n * @environment SHOPIFY_FLAG_NAME\n */\n '-n, --name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -6574,7 +6574,7 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" }, @@ -6597,7 +6597,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themeinfo {\n /**\n * Retrieve info from your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeinfo {\n /**\n * Retrieve info from your development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -6850,7 +6850,7 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" }, @@ -6864,7 +6864,7 @@ "environmentValue": "SHOPIFY_FLAG_STORE" } ], - "value": "export interface themelist {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Only list theme with the given ID.\n * @environment SHOPIFY_FLAG_ID\n */\n '--id '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Only list themes that contain the given name.\n * @environment SHOPIFY_FLAG_NAME\n */\n '--name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Only list themes with the given role.\n * @environment SHOPIFY_FLAG_ROLE\n */\n '--role '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themelist {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Only list theme with the given ID.\n * @environment SHOPIFY_FLAG_ID\n */\n '--id '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Only list themes that contain the given name.\n * @environment SHOPIFY_FLAG_NAME\n */\n '--name '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Only list themes with the given role.\n * @environment SHOPIFY_FLAG_ROLE\n */\n '--role '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -7380,7 +7380,7 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" }, @@ -7403,7 +7403,7 @@ "environmentValue": "SHOPIFY_FLAG_THEME_ID" } ], - "value": "export interface themeprofile {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * The url to be used as context\n * @environment SHOPIFY_FLAG_URL\n */\n '--url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themeprofile {\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * The password for storefronts with password protection.\n * @environment SHOPIFY_FLAG_STORE_PASSWORD\n */\n '--store-password '?: string\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * The url to be used as context\n * @environment SHOPIFY_FLAG_URL\n */\n '--url '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } @@ -7791,7 +7791,7 @@ "syntaxKind": "PropertySignature", "name": "-j, --json", "value": "\"\"", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON" }, @@ -7868,7 +7868,7 @@ "environmentValue": "SHOPIFY_FLAG_IGNORE" } ], - "value": "export interface themepush {\n /**\n * Allow push to a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * Push theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * Unique identifier for a development theme context (e.g., PR number, branch name). Reuses an existing development theme with this context name, or creates one if none exists.\n * @environment SHOPIFY_FLAG_DEVELOPMENT_CONTEXT\n */\n '-c, --development-context '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip uploading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * Output the result as JSON.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * Push theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting remote files that don't exist locally.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Upload only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Publish as the live theme after uploading.\n * @environment SHOPIFY_FLAG_PUBLISH\n */\n '-p, --publish'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Require theme check to pass without errors before pushing. Warnings are allowed.\n * @environment SHOPIFY_FLAG_STRICT_PUSH\n */\n '--strict'?: ''\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Create a new unpublished theme and push to it.\n * @environment SHOPIFY_FLAG_UNPUBLISHED\n */\n '-u, --unpublished'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface themepush {\n /**\n * Allow push to a live theme.\n * @environment SHOPIFY_FLAG_ALLOW_LIVE\n */\n '-a, --allow-live'?: ''\n\n /**\n * Push theme files from your remote development theme.\n * @environment SHOPIFY_FLAG_DEVELOPMENT\n */\n '-d, --development'?: ''\n\n /**\n * Unique identifier for a development theme context (e.g., PR number, branch name). Reuses an existing development theme with this context name, or creates one if none exists.\n * @environment SHOPIFY_FLAG_DEVELOPMENT_CONTEXT\n */\n '-c, --development-context '?: string\n\n /**\n * The environment to apply to the current command.\n * @environment SHOPIFY_FLAG_ENVIRONMENT\n */\n '-e, --environment '?: string\n\n /**\n * Skip uploading the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_IGNORE\n */\n '-x, --ignore '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * The listing preset to use for multi-preset themes. Applies preset files from listings/[preset-name] directory.\n * @environment SHOPIFY_FLAG_LISTING\n */\n '--listing '?: string\n\n /**\n * Push theme files from your remote live theme.\n * @environment SHOPIFY_FLAG_LIVE\n */\n '-l, --live'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Prevent deleting remote files that don't exist locally.\n * @environment SHOPIFY_FLAG_NODELETE\n */\n '-n, --nodelete'?: ''\n\n /**\n * Upload only the specified files (Multiple flags allowed). Wrap the value in double quotes if you're using wildcards.\n * @environment SHOPIFY_FLAG_ONLY\n */\n '-o, --only '?: string\n\n /**\n * Password generated from the Theme Access app or an Admin API token.\n * @environment SHOPIFY_CLI_THEME_TOKEN\n */\n '--password '?: string\n\n /**\n * The path where you want to run the command. Defaults to the current working directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Publish as the live theme after uploading.\n * @environment SHOPIFY_FLAG_PUBLISH\n */\n '-p, --publish'?: ''\n\n /**\n * Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com).\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Require theme check to pass without errors before pushing. Warnings are allowed.\n * @environment SHOPIFY_FLAG_STRICT_PUSH\n */\n '--strict'?: ''\n\n /**\n * Theme ID or name of the remote theme.\n * @environment SHOPIFY_FLAG_THEME_ID\n */\n '-t, --theme '?: string\n\n /**\n * Create a new unpublished theme and push to it.\n * @environment SHOPIFY_FLAG_UNPUBLISHED\n */\n '-u, --unpublished'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } diff --git a/packages/cli-kit/src/public/node/cli.test.ts b/packages/cli-kit/src/public/node/cli.test.ts index 7e6af517d3c..61f8f7d8ccb 100644 --- a/packages/cli-kit/src/public/node/cli.test.ts +++ b/packages/cli-kit/src/public/node/cli.test.ts @@ -20,6 +20,27 @@ describe('cli', () => { expect(env.FORCE_COLOR).toBe('0') }) + test('triggers no colour mode based on --json flag', async () => { + const launchCLI = vi.fn() + const env = {} as any + await runCLI({moduleURL: 'test', development: false}, launchCLI, ['--json'], env) + expect(env.FORCE_COLOR).toBe('0') + }) + + test('triggers no colour mode based on -j flag', async () => { + const launchCLI = vi.fn() + const env = {} as any + await runCLI({moduleURL: 'test', development: false}, launchCLI, ['-j'], env) + expect(env.FORCE_COLOR).toBe('0') + }) + + test('triggers no colour mode based on SHOPIFY_FLAG_JSON environment variable', async () => { + const launchCLI = vi.fn() + const env = {SHOPIFY_FLAG_JSON: 'TRUE'} as any + await runCLI({moduleURL: 'test', development: false}, launchCLI, [], env) + expect(env.FORCE_COLOR).toBe('0') + }) + test('triggers no colour mode based on NO_COLOR environment variable', async () => { const launchCLI = vi.fn() const env = {NO_COLOR: 'TRUE'} as any diff --git a/packages/cli-kit/src/public/node/cli.ts b/packages/cli-kit/src/public/node/cli.ts index a9aa86af88d..4adb3268f7a 100644 --- a/packages/cli-kit/src/public/node/cli.ts +++ b/packages/cli-kit/src/public/node/cli.ts @@ -62,8 +62,11 @@ function setupEnvironmentVariables( function forceNoColor(argv: string[] = process.argv, env: NodeJS.ProcessEnv = process.env) { if ( argv.includes('--no-color') || + argv.includes('--json') || + argv.includes('-j') || isTruthy(env.NO_COLOR) || isTruthy(env.SHOPIFY_FLAG_NO_COLOR) || + isTruthy(env[environmentVariables.json]) || env.TERM === 'dumb' ) { env.FORCE_COLOR = '0' @@ -142,7 +145,7 @@ export const globalFlags = { export const jsonFlag = { json: Flags.boolean({ char: 'j', - description: 'Output the result as JSON.', + description: 'Output the result as JSON. Automatically disables color output.', hidden: false, default: false, env: environmentVariables.json, diff --git a/packages/cli/README.md b/packages/cli/README.md index def3a91294f..16a4594ecf9 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -579,7 +579,7 @@ USAGE FLAGS -c, --config= [env: SHOPIFY_FLAG_APP_CONFIG] The name of the app configuration. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. --client-id= [env: SHOPIFY_FLAG_CLIENT_ID] The Client ID of your app. --no-color [env: SHOPIFY_FLAG_NO_COLOR] Disable color output. --path= [env: SHOPIFY_FLAG_PATH] The path to your function directory. @@ -611,7 +611,7 @@ USAGE FLAGS -c, --config= [env: SHOPIFY_FLAG_APP_CONFIG] The name of the app configuration. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. -l, --log= [env: SHOPIFY_FLAG_LOG] Specifies a log identifier to replay instead of selecting from a list. The identifier is provided in the output of `shopify app dev` and is the suffix of the log file name. @@ -644,7 +644,7 @@ FLAGS -e, --export= [env: SHOPIFY_FLAG_EXPORT] Name of the WebAssembly export to invoke. -i, --input= [env: SHOPIFY_FLAG_INPUT] The input JSON to pass to the function. If omitted, standard input is used. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. --client-id= [env: SHOPIFY_FLAG_CLIENT_ID] The Client ID of your app. --no-color [env: SHOPIFY_FLAG_NO_COLOR] Disable color output. --path= [env: SHOPIFY_FLAG_PATH] The path to your function directory. @@ -805,7 +805,7 @@ USAGE FLAGS -c, --config= [env: SHOPIFY_FLAG_APP_CONFIG] The name of the app configuration. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. --client-id= [env: SHOPIFY_FLAG_CLIENT_ID] The Client ID of your app. --no-color [env: SHOPIFY_FLAG_NO_COLOR] Disable color output. --path= [env: SHOPIFY_FLAG_PATH] The path to your app directory. @@ -867,7 +867,7 @@ USAGE FLAGS -c, --config= [env: SHOPIFY_FLAG_APP_CONFIG] The name of the app configuration. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. -s, --store=... [env: SHOPIFY_FLAG_STORE] Store URL. Must be an existing development or Shopify Plus sandbox store. --client-id= [env: SHOPIFY_FLAG_CLIENT_ID] The Client ID of your app. @@ -955,7 +955,7 @@ USAGE FLAGS -c, --config= [env: SHOPIFY_FLAG_APP_CONFIG] The name of the app configuration. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. --client-id= [env: SHOPIFY_FLAG_CLIENT_ID] The Client ID of your app. --no-color [env: SHOPIFY_FLAG_NO_COLOR] Disable color output. --path= [env: SHOPIFY_FLAG_PATH] The path to your app directory. @@ -1783,7 +1783,7 @@ USAGE $ shopify organization list [-j] [--no-color] [--verbose] FLAGS - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. --no-color [env: SHOPIFY_FLAG_NO_COLOR] Disable color output. --verbose [env: SHOPIFY_FLAG_VERBOSE] Increase the verbosity of the output. @@ -2290,7 +2290,7 @@ FLAGS -e, --environment=... [env: SHOPIFY_FLAG_ENVIRONMENT] The environment to apply to the current command. -f, --force [env: SHOPIFY_FLAG_FORCE] Force the duplicate operation to run without prompts or confirmations. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. -n, --name= [env: SHOPIFY_FLAG_NAME] Name of the newly duplicated theme. -s, --store= [env: SHOPIFY_FLAG_STORE] Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). @@ -2350,7 +2350,7 @@ USAGE FLAGS -d, --development [env: SHOPIFY_FLAG_DEVELOPMENT] Retrieve info from your development theme. -e, --environment=... [env: SHOPIFY_FLAG_ENVIRONMENT] The environment to apply to the current command. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. -s, --store= [env: SHOPIFY_FLAG_STORE] Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). -t, --theme= [env: SHOPIFY_FLAG_THEME_ID] Theme ID or name of the remote theme. @@ -2429,7 +2429,7 @@ USAGE FLAGS -e, --environment=... [env: SHOPIFY_FLAG_ENVIRONMENT] The environment to apply to the current command. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. -s, --store= [env: SHOPIFY_FLAG_STORE] Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). --id= [env: SHOPIFY_FLAG_ID] Only list theme with the given ID. @@ -2589,7 +2589,7 @@ USAGE FLAGS -e, --environment=... [env: SHOPIFY_FLAG_ENVIRONMENT] The environment to apply to the current command. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. -s, --store= [env: SHOPIFY_FLAG_STORE] Store URL. It can be the store prefix (example) or the full myshopify.com URL (example.myshopify.com, https://example.myshopify.com). -t, --theme= [env: SHOPIFY_FLAG_THEME_ID] Theme ID or name of the remote theme. @@ -2702,7 +2702,8 @@ FLAGS -d, --development [env: SHOPIFY_FLAG_DEVELOPMENT] Push theme files from your remote development theme. -e, --environment=... [env: SHOPIFY_FLAG_ENVIRONMENT] The environment to apply to the current command. - -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color + output. -l, --live [env: SHOPIFY_FLAG_LIVE] Push theme files from your remote live theme. -n, --nodelete [env: SHOPIFY_FLAG_NODELETE] Prevent deleting remote files that don't exist locally. diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index 329f37fb024..febd24ce52b 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -1585,7 +1585,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -1673,7 +1673,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -1798,7 +1798,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -2444,7 +2444,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -2656,7 +2656,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -2964,7 +2964,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -5343,7 +5343,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -6314,7 +6314,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -6414,7 +6414,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -6620,7 +6620,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -7062,7 +7062,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", @@ -7456,7 +7456,7 @@ "json": { "allowNo": false, "char": "j", - "description": "Output the result as JSON.", + "description": "Output the result as JSON. Automatically disables color output.", "env": "SHOPIFY_FLAG_JSON", "hidden": false, "name": "json", From cb30aed62ebee31446b20c6a55b194cb95e495b1 Mon Sep 17 00:00:00 2001 From: Donald Merand Date: Fri, 20 Mar 2026 12:18:39 -0400 Subject: [PATCH 05/11] Add --json to validate First pass, not final agent shape --- .../app-config-validate.interface.ts | 6 +++ .../generated/generated_docs_data.json | 11 ++++- .../cli/commands/app/config/validate.test.ts | 49 +++++++++++++++++++ .../src/cli/commands/app/config/validate.ts | 5 +- .../app/src/cli/services/validate.test.ts | 48 ++++++++++++++++++ packages/app/src/cli/services/validate.ts | 20 ++++++-- packages/cli/README.md | 5 +- packages/cli/oclif.manifest.json | 9 ++++ 8 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 packages/app/src/cli/commands/app/config/validate.test.ts diff --git a/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts b/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts index 81b76932f0f..89220a7e035 100644 --- a/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts +++ b/docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts @@ -12,6 +12,12 @@ export interface appconfigvalidate { */ '-c, --config '?: string + /** + * Output the result as JSON. Automatically disables color output. + * @environment SHOPIFY_FLAG_JSON + */ + '-j, --json'?: '' + /** * Disable color output. * @environment SHOPIFY_FLAG_NO_COLOR diff --git a/docs-shopify.dev/generated/generated_docs_data.json b/docs-shopify.dev/generated/generated_docs_data.json index cf83eeb567c..223711f2ac4 100644 --- a/docs-shopify.dev/generated/generated_docs_data.json +++ b/docs-shopify.dev/generated/generated_docs_data.json @@ -832,9 +832,18 @@ "description": "The name of the app configuration.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-config-validate.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-j, --json", + "value": "\"\"", + "description": "Output the result as JSON. Automatically disables color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface appconfigvalidate {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + "value": "export interface appconfigvalidate {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } } } diff --git a/packages/app/src/cli/commands/app/config/validate.test.ts b/packages/app/src/cli/commands/app/config/validate.test.ts new file mode 100644 index 00000000000..5ae0a8203e5 --- /dev/null +++ b/packages/app/src/cli/commands/app/config/validate.test.ts @@ -0,0 +1,49 @@ +import Validate from './validate.js' +import {linkedAppContext} from '../../../services/app-context.js' +import {validateApp} from '../../../services/validate.js' +import {testAppLinked} from '../../../models/app/app.test-data.js' +import {describe, expect, test, vi} from 'vitest' + +vi.mock('../../../services/app-context.js') +vi.mock('../../../services/validate.js') + +describe('app config validate command', () => { + test('calls validateApp with json: false by default', async () => { + // Given + const app = testAppLinked() + vi.mocked(linkedAppContext).mockResolvedValue({app} as Awaited>) + vi.mocked(validateApp).mockResolvedValue() + + // When + await Validate.run([], import.meta.url) + + // Then + expect(validateApp).toHaveBeenCalledWith(app, {json: false}) + }) + + test('calls validateApp with json: true when --json flag is passed', async () => { + // Given + const app = testAppLinked() + vi.mocked(linkedAppContext).mockResolvedValue({app} as Awaited>) + vi.mocked(validateApp).mockResolvedValue() + + // When + await Validate.run(['--json'], import.meta.url) + + // Then + expect(validateApp).toHaveBeenCalledWith(app, {json: true}) + }) + + test('calls validateApp with json: true when -j flag is passed', async () => { + // Given + const app = testAppLinked() + vi.mocked(linkedAppContext).mockResolvedValue({app} as Awaited>) + vi.mocked(validateApp).mockResolvedValue() + + // When + await Validate.run(['-j'], import.meta.url) + + // Then + expect(validateApp).toHaveBeenCalledWith(app, {json: true}) + }) +}) diff --git a/packages/app/src/cli/commands/app/config/validate.ts b/packages/app/src/cli/commands/app/config/validate.ts index 02fca4f7458..c597c5228e7 100644 --- a/packages/app/src/cli/commands/app/config/validate.ts +++ b/packages/app/src/cli/commands/app/config/validate.ts @@ -2,7 +2,7 @@ import {appFlags} from '../../../flags.js' import {validateApp} from '../../../services/validate.js' import AppLinkedCommand, {AppLinkedCommandOutput} from '../../../utilities/app-linked-command.js' import {linkedAppContext} from '../../../services/app-context.js' -import {globalFlags} from '@shopify/cli-kit/node/cli' +import {globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli' export default class Validate extends AppLinkedCommand { static summary = 'Validate your app configuration and extensions.' @@ -14,6 +14,7 @@ export default class Validate extends AppLinkedCommand { static flags = { ...globalFlags, ...appFlags, + ...jsonFlag, } public async run(): Promise { @@ -27,7 +28,7 @@ export default class Validate extends AppLinkedCommand { unsafeTolerateErrors: true, }) - await validateApp(app) + await validateApp(app, {json: flags.json}) return {app} } diff --git a/packages/app/src/cli/services/validate.test.ts b/packages/app/src/cli/services/validate.test.ts index e29950ee7bc..c475c4399d0 100644 --- a/packages/app/src/cli/services/validate.test.ts +++ b/packages/app/src/cli/services/validate.test.ts @@ -2,9 +2,17 @@ import {validateApp} from './validate.js' import {testAppLinked} from '../models/app/app.test-data.js' import {AppErrors} from '../models/app/loader.js' import {describe, expect, test, vi} from 'vitest' +import {outputResult} from '@shopify/cli-kit/node/output' import {renderError, renderSuccess} from '@shopify/cli-kit/node/ui' import {AbortSilentError} from '@shopify/cli-kit/node/error' +vi.mock('@shopify/cli-kit/node/output', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + outputResult: vi.fn(), + } +}) vi.mock('@shopify/cli-kit/node/ui') describe('validateApp', () => { @@ -18,6 +26,20 @@ describe('validateApp', () => { // Then expect(renderSuccess).toHaveBeenCalledWith({headline: 'App configuration is valid.'}) expect(renderError).not.toHaveBeenCalled() + expect(outputResult).not.toHaveBeenCalled() + }) + + test('outputs json success when --json is enabled and there are no errors', async () => { + // Given + const app = testAppLinked() + + // When + await validateApp(app, {json: true}) + + // Then + expect(outputResult).toHaveBeenCalledWith(JSON.stringify({valid: true, errors: []}, null, 2)) + expect(renderSuccess).not.toHaveBeenCalled() + expect(renderError).not.toHaveBeenCalled() }) test('renders errors and throws when there are validation errors', async () => { @@ -35,6 +57,31 @@ describe('validateApp', () => { body: expect.stringContaining('client_id is required'), }) expect(renderSuccess).not.toHaveBeenCalled() + expect(outputResult).not.toHaveBeenCalled() + }) + + test('outputs json errors and throws when --json is enabled and there are validation errors', async () => { + // Given + const errors = new AppErrors() + errors.addError('/path/to/shopify.app.toml', 'client_id is required') + errors.addError('/path/to/extensions/my-ext/shopify.extension.toml', 'invalid type "unknown"') + const app = testAppLinked() + app.errors = errors + + // When / Then + await expect(validateApp(app, {json: true})).rejects.toThrow(AbortSilentError) + expect(outputResult).toHaveBeenCalledWith( + JSON.stringify( + { + valid: false, + errors: ['client_id is required', 'invalid type "unknown"'], + }, + null, + 2, + ), + ) + expect(renderError).not.toHaveBeenCalled() + expect(renderSuccess).not.toHaveBeenCalled() }) test('renders success when errors object exists but is empty', async () => { @@ -48,5 +95,6 @@ describe('validateApp', () => { // Then expect(renderSuccess).toHaveBeenCalledWith({headline: 'App configuration is valid.'}) + expect(outputResult).not.toHaveBeenCalled() }) }) diff --git a/packages/app/src/cli/services/validate.ts b/packages/app/src/cli/services/validate.ts index e8a5a0edbc3..d27efebeeaf 100644 --- a/packages/app/src/cli/services/validate.ts +++ b/packages/app/src/cli/services/validate.ts @@ -1,18 +1,32 @@ import {AppLinkedInterface} from '../models/app/app.js' -import {stringifyMessage} from '@shopify/cli-kit/node/output' +import {outputResult, stringifyMessage} from '@shopify/cli-kit/node/output' import {renderError, renderSuccess} from '@shopify/cli-kit/node/ui' import {AbortSilentError} from '@shopify/cli-kit/node/error' -export async function validateApp(app: AppLinkedInterface): Promise { +interface ValidateAppOptions { + json: boolean +} + +export async function validateApp(app: AppLinkedInterface, options: ValidateAppOptions = {json: false}): Promise { const errors = app.errors - if (errors.isEmpty()) { + if (!errors || errors.isEmpty()) { + if (options.json) { + outputResult(JSON.stringify({valid: true, errors: []}, null, 2)) + return + } + renderSuccess({headline: 'App configuration is valid.'}) return } const errorMessages = errors.toJSON().map((error) => stringifyMessage(error).trim()) + if (options.json) { + outputResult(JSON.stringify({valid: false, errors: errorMessages}, null, 2)) + throw new AbortSilentError() + } + renderError({ headline: 'Validation errors found.', body: errorMessages.join('\n\n'), diff --git a/packages/cli/README.md b/packages/cli/README.md index 16a4594ecf9..bcaa53e5e81 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -312,11 +312,12 @@ Validate your app configuration and extensions. ``` USAGE - $ shopify app config validate [--client-id | -c ] [--no-color] [--path ] [--reset | ] - [--verbose] + $ shopify app config validate [--client-id | -c ] [-j] [--no-color] [--path ] [--reset | ] + [--verbose] FLAGS -c, --config= [env: SHOPIFY_FLAG_APP_CONFIG] The name of the app configuration. + -j, --json [env: SHOPIFY_FLAG_JSON] Output the result as JSON. Automatically disables color output. --client-id= [env: SHOPIFY_FLAG_CLIENT_ID] The Client ID of your app. --no-color [env: SHOPIFY_FLAG_NO_COLOR] Disable color output. --path= [env: SHOPIFY_FLAG_PATH] The path to your app directory. diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index febd24ce52b..ba23f85d8b5 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -690,6 +690,15 @@ "name": "config", "type": "option" }, + "json": { + "allowNo": false, + "char": "j", + "description": "Output the result as JSON. Automatically disables color output.", + "env": "SHOPIFY_FLAG_JSON", + "hidden": false, + "name": "json", + "type": "boolean" + }, "no-color": { "allowNo": false, "description": "Disable color output.", From 504fa5c8d79d3176c029c240c4395af6f2eadecb Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Thu, 19 Mar 2026 15:49:01 -0400 Subject: [PATCH 06/11] Fix infinite 401 retry loop when app logs resubscribe fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the JWT for app log polling expires, handleFetchAppLogsError calls onResubscribe() to get a fresh token. If onResubscribe() itself throws (network error, expired session), the exception propagates unhandled, causing the dev polling loop to retry every 5s with the same expired JWT — an infinite 401 loop. Wrap onResubscribe() in a try-catch so failures fall back to a 60s retry interval instead of propagating. This is a 12x reduction in 401 rate per affected client and allows self-healing when the underlying issue resolves. --- .../app-logs/dev/poll-app-logs.test.ts | 24 +++++++++++++++ .../logs-command/render-json-logs.test.ts | 29 +++++++++++++++++++ .../app/src/cli/services/app-logs/utils.ts | 7 ++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts index 38a5022fd0b..7a572b8e2c7 100644 --- a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts @@ -385,6 +385,30 @@ describe('pollAppLogs', () => { expect(vi.getTimerCount()).toEqual(1) }) + test('retries at 60s interval when resubscribe throws on 401', async () => { + // Given + const response = {errors: ['Unauthorized'], status: 401} + const mockedDeveloperPlatformClient = testDeveloperPlatformClient({ + appLogs: vi.fn().mockResolvedValue(response), + }) + const failingResubscribe = vi.fn().mockRejectedValue(new Error('Network error')) + + // When + await pollAppLogs({ + stdout, + appLogsFetchInput: {jwtToken: JWT_TOKEN}, + developerPlatformClient: mockedDeveloperPlatformClient, + resubscribeCallback: failingResubscribe, + storeName: 'storeName', + organizationId: 'organizationId', + logsDir: TEST_LOGS_DIR, + }) + + // Then + expect(failingResubscribe).toHaveBeenCalled() + expect(vi.getTimerCount()).toEqual(1) + }) + test('displays error message, waits, and retries if error occurred', async () => { // Given const outputDebugSpy = vi.spyOn(output, 'outputDebug') diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts index 09ce09e04b9..fc9dc46420a 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts @@ -101,6 +101,35 @@ describe('renderJsonLogs', () => { expect(outputResult).not.toHaveBeenCalled() }) + test('should handle 401 with resubscribe failure and retry at throttle interval', async () => { + const mockErrorResponse = { + errors: [{status: 401, message: 'Unauthorized'}], + } + const pollAppLogsMock = vi.fn().mockResolvedValue(mockErrorResponse) + vi.mocked(pollAppLogs).mockImplementation(pollAppLogsMock) + const throttleRetryInterval = 60000 + const handleFetchAppLogsErrorMock = vi.fn(() => { + return Promise.resolve({nextJwtToken: null, retryIntervalMs: throttleRetryInterval}) + }) + vi.mocked(handleFetchAppLogsError).mockImplementation(handleFetchAppLogsErrorMock) + + const storeNameById = new Map() + storeNameById.set('1', 'storeName') + await renderJsonLogs({ + pollOptions: {cursor: 'cursor', filters: {status: undefined, sources: undefined}, jwtToken: 'jwtToken'}, + options: { + variables: {shopIds: [], apiKey: ''}, + developerPlatformClient: testDeveloperPlatformClient(), + }, + storeNameById, + organizationId: 'organizationId', + }) + + expect(handleFetchAppLogsError).toHaveBeenCalled() + expect(pollAppLogs).toHaveBeenCalled() + expect(vi.getTimerCount()).toEqual(1) + }) + test('should handle error response and retry as expected', async () => { const mockErrorResponse = { errors: [{status: 500, message: 'Server Error'}], diff --git a/packages/app/src/cli/services/app-logs/utils.ts b/packages/app/src/cli/services/app-logs/utils.ts index e80a1f37475..f2db84a4c2b 100644 --- a/packages/app/src/cli/services/app-logs/utils.ts +++ b/packages/app/src/cli/services/app-logs/utils.ts @@ -119,7 +119,12 @@ export const handleFetchAppLogsError = async ( outputDebug(`Errors: ${errors.map((error) => error.message).join(', ')}`) if (errors.some((error) => error.status === 401)) { - nextJwtToken = await input.onResubscribe() + try { + nextJwtToken = await input.onResubscribe() + } catch (resubscribeError) { + outputDebug(`Failed to resubscribe to app logs: ${resubscribeError}`) + retryIntervalMs = POLLING_THROTTLE_RETRY_INTERVAL_MS + } } else if (errors.some((error) => error.status === 429)) { retryIntervalMs = POLLING_THROTTLE_RETRY_INTERVAL_MS input.onThrottle(retryIntervalMs) From fe0648a5f872ce2195bf7294da433f5a79fceb96 Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Thu, 19 Mar 2026 16:12:03 -0400 Subject: [PATCH 07/11] address feedback --- .../app/src/cli/services/app-logs/dev/poll-app-logs.test.ts | 6 ++++++ .../services/app-logs/logs-command/render-json-logs.test.ts | 3 ++- packages/app/src/cli/services/app-logs/utils.ts | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts index 7a572b8e2c7..c2539cf6492 100644 --- a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts @@ -387,6 +387,9 @@ describe('pollAppLogs', () => { test('retries at 60s interval when resubscribe throws on 401', async () => { // Given + const outputDebugSpy = vi.spyOn(output, 'outputDebug') + const outputWarnSpy = vi.spyOn(output, 'outputWarn') + const timeoutSpy = vi.spyOn(global, 'setTimeout') const response = {errors: ['Unauthorized'], status: 401} const mockedDeveloperPlatformClient = testDeveloperPlatformClient({ appLogs: vi.fn().mockResolvedValue(response), @@ -406,6 +409,9 @@ describe('pollAppLogs', () => { // Then expect(failingResubscribe).toHaveBeenCalled() + expect(outputDebugSpy).toHaveBeenCalledWith(expect.stringContaining('Failed to resubscribe')) + expect(outputWarnSpy).toHaveBeenCalledWith('Request throttled while polling app logs.', stdout) + expect(timeoutSpy).toHaveBeenCalledWith(expect.any(Function), 60000) expect(vi.getTimerCount()).toEqual(1) }) diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts index fc9dc46420a..4573ee1537a 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts @@ -101,7 +101,7 @@ describe('renderJsonLogs', () => { expect(outputResult).not.toHaveBeenCalled() }) - test('should handle 401 with resubscribe failure and retry at throttle interval', async () => { + test('should retry at throttle interval when handleFetchAppLogsError returns null token', async () => { const mockErrorResponse = { errors: [{status: 401, message: 'Unauthorized'}], } @@ -127,6 +127,7 @@ describe('renderJsonLogs', () => { expect(handleFetchAppLogsError).toHaveBeenCalled() expect(pollAppLogs).toHaveBeenCalled() + expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), throttleRetryInterval) expect(vi.getTimerCount()).toEqual(1) }) diff --git a/packages/app/src/cli/services/app-logs/utils.ts b/packages/app/src/cli/services/app-logs/utils.ts index f2db84a4c2b..d7da1dd93d1 100644 --- a/packages/app/src/cli/services/app-logs/utils.ts +++ b/packages/app/src/cli/services/app-logs/utils.ts @@ -124,6 +124,7 @@ export const handleFetchAppLogsError = async ( } catch (resubscribeError) { outputDebug(`Failed to resubscribe to app logs: ${resubscribeError}`) retryIntervalMs = POLLING_THROTTLE_RETRY_INTERVAL_MS + input.onThrottle(retryIntervalMs) } } else if (errors.some((error) => error.status === 429)) { retryIntervalMs = POLLING_THROTTLE_RETRY_INTERVAL_MS From c6a3af2f47b5d371b31bee6b28bca9838299b9b0 Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Fri, 20 Mar 2026 10:12:27 -0400 Subject: [PATCH 08/11] stop trying to resubscribe after max attempts --- .../app-logs/dev/poll-app-logs.test.ts | 30 +++++++++++++ .../services/app-logs/dev/poll-app-logs.ts | 16 +++++++ .../logs-command/render-json-logs.test.ts | 35 ++++++++++++++- .../app-logs/logs-command/render-json-logs.ts | 19 ++++++++ .../components/hooks/usePollAppLogs.test.tsx | 43 +++++++++++++++++++ .../ui/components/hooks/usePollAppLogs.ts | 17 +++++++- .../app/src/cli/services/app-logs/utils.ts | 7 ++- 7 files changed, 162 insertions(+), 5 deletions(-) diff --git a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts index c2539cf6492..5062ca94f98 100644 --- a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.test.ts @@ -1,6 +1,7 @@ import {pollAppLogs} from './poll-app-logs.js' import {writeAppLogsToFile} from './write-app-logs.js' import {FunctionRunLog} from '../types.js' +import {MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES} from '../utils.js' import {testDeveloperPlatformClient} from '../../../models/app/app.test-data.js' import {describe, expect, test, vi, beforeEach, afterEach} from 'vitest' import * as components from '@shopify/cli-kit/node/ui/components' @@ -442,6 +443,35 @@ describe('pollAppLogs', () => { expect(vi.getTimerCount()).toEqual(1) }) + test('stops polling after MAX consecutive resubscribe failures', async () => { + // Given + const outputWarnSpy = vi.spyOn(output, 'outputWarn') + const response = {errors: ['Unauthorized'], status: 401} + const mockedDeveloperPlatformClient = testDeveloperPlatformClient({ + appLogs: vi.fn().mockResolvedValue(response), + }) + const failingResubscribe = vi.fn().mockRejectedValue(new Error('Network error')) + + // When - start with failures already at MAX - 1 + await pollAppLogs({ + stdout, + appLogsFetchInput: {jwtToken: JWT_TOKEN}, + developerPlatformClient: mockedDeveloperPlatformClient, + resubscribeCallback: failingResubscribe, + storeName: 'storeName', + organizationId: 'organizationId', + logsDir: TEST_LOGS_DIR, + consecutiveResubscribeFailures: MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES - 1, + }) + + // Then - should output terminal message and NOT schedule a timer + expect(outputWarnSpy).toHaveBeenCalledWith( + 'App log streaming session has expired. Please restart your dev session.', + stdout, + ) + expect(vi.getTimerCount()).toEqual(0) + }) + test('displays error message, waits, and retries if response contained bad JSON', async () => { // Given const outputDebugSpy = vi.spyOn(output, 'outputDebug') diff --git a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts index a74fa5be0cc..56df2724ff2 100644 --- a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts +++ b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts @@ -10,6 +10,7 @@ import { LOG_TYPE_REQUEST_EXECUTION, REQUEST_EXECUTION_IN_BACKGROUND_NO_CACHED_RESPONSE_REASON, REQUEST_EXECUTION_IN_BACKGROUND_CACHE_ABOUT_TO_EXPIRE_REASON, + MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES, handleFetchAppLogsError, AppLogsOptions, } from '../utils.js' @@ -29,6 +30,7 @@ export const pollAppLogs = async ({ organizationId, abortSignal, logsDir, + consecutiveResubscribeFailures = 0, }: { stdout: Writable appLogsFetchInput: AppLogsOptions @@ -38,6 +40,7 @@ export const pollAppLogs = async ({ organizationId: string abortSignal?: AbortSignal logsDir: string + consecutiveResubscribeFailures?: number }) => { if (abortSignal?.aborted) { return @@ -46,11 +49,13 @@ export const pollAppLogs = async ({ try { let nextJwtToken = jwtToken let retryIntervalMs = POLLING_INTERVAL_MS + let nextConsecutiveResubscribeFailures = consecutiveResubscribeFailures const response = await developerPlatformClient.appLogs({jwtToken, cursor}, organizationId) const {errors, status} = response as AppLogsError if (status === 200) { + nextConsecutiveResubscribeFailures = 0 const {app_logs: appLogs} = response as AppLogsSuccess for (const log of appLogs) { @@ -102,6 +107,16 @@ export const pollAppLogs = async ({ }, }) + if (result.resubscribeFailed) { + nextConsecutiveResubscribeFailures += 1 + if (nextConsecutiveResubscribeFailures >= MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES) { + outputWarn('App log streaming session has expired. Please restart your dev session.', stdout) + return + } + } else { + nextConsecutiveResubscribeFailures = 0 + } + if (result.nextJwtToken) { nextJwtToken = result.nextJwtToken } @@ -123,6 +138,7 @@ export const pollAppLogs = async ({ organizationId, abortSignal, logsDir, + consecutiveResubscribeFailures: nextConsecutiveResubscribeFailures, }).catch((error) => { outputDebug(`Unexpected error during polling: ${error}}\n`) }) diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts index 4573ee1537a..b57c5c3a127 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts @@ -1,6 +1,6 @@ import {renderJsonLogs} from './render-json-logs.js' import {pollAppLogs} from './poll-app-logs.js' -import {handleFetchAppLogsError} from '../utils.js' +import {handleFetchAppLogsError, MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES} from '../utils.js' import {testDeveloperPlatformClient} from '../../../models/app/app.test-data.js' import {outputInfo, outputResult} from '@shopify/cli-kit/node/output' import {describe, expect, vi, test, beforeEach, afterEach} from 'vitest' @@ -109,7 +109,7 @@ describe('renderJsonLogs', () => { vi.mocked(pollAppLogs).mockImplementation(pollAppLogsMock) const throttleRetryInterval = 60000 const handleFetchAppLogsErrorMock = vi.fn(() => { - return Promise.resolve({nextJwtToken: null, retryIntervalMs: throttleRetryInterval}) + return Promise.resolve({nextJwtToken: null, retryIntervalMs: throttleRetryInterval, resubscribeFailed: false}) }) vi.mocked(handleFetchAppLogsError).mockImplementation(handleFetchAppLogsErrorMock) @@ -131,6 +131,37 @@ describe('renderJsonLogs', () => { expect(vi.getTimerCount()).toEqual(1) }) + test('should stop polling after MAX consecutive resubscribe failures', async () => { + const mockErrorResponse = { + errors: [{status: 401, message: 'Unauthorized'}], + } + const pollAppLogsMock = vi.fn().mockResolvedValue(mockErrorResponse) + vi.mocked(pollAppLogs).mockImplementation(pollAppLogsMock) + const handleFetchAppLogsErrorMock = vi.fn(() => { + return Promise.resolve({nextJwtToken: null, retryIntervalMs: 60000, resubscribeFailed: true}) + }) + vi.mocked(handleFetchAppLogsError).mockImplementation(handleFetchAppLogsErrorMock) + + const storeNameById = new Map() + storeNameById.set('1', 'storeName') + await renderJsonLogs({ + pollOptions: {cursor: 'cursor', filters: {status: undefined, sources: undefined}, jwtToken: 'jwtToken'}, + options: { + variables: {shopIds: [], apiKey: ''}, + developerPlatformClient: testDeveloperPlatformClient(), + }, + storeNameById, + organizationId: 'organizationId', + consecutiveResubscribeFailures: MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES - 1, + }) + + expect(handleFetchAppLogsError).toHaveBeenCalled() + expect(outputInfo).toHaveBeenCalledWith( + JSON.stringify({message: 'App log streaming session has expired. Please restart your dev session.'}), + ) + expect(vi.getTimerCount()).toEqual(0) + }) + test('should handle error response and retry as expected', async () => { const mockErrorResponse = { errors: [{status: 500, message: 'Server Error'}], diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts index eb2e9cf5e2a..d4bda7b20f5 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts @@ -2,6 +2,7 @@ import {pollAppLogs} from './poll-app-logs.js' import {PollOptions, SubscribeOptions, ErrorResponse, SuccessResponse} from '../types.js' import { POLLING_INTERVAL_MS, + MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES, handleFetchAppLogsError, subscribeToAppLogs, toFormattedAppLogJson, @@ -14,15 +15,18 @@ export async function renderJsonLogs({ options: {variables, developerPlatformClient}, storeNameById, organizationId, + consecutiveResubscribeFailures = 0, }: { pollOptions: PollOptions options: SubscribeOptions storeNameById: Map organizationId: string + consecutiveResubscribeFailures?: number }): Promise { const response = await pollAppLogs({pollOptions, developerPlatformClient, organizationId}) let retryIntervalMs = POLLING_INTERVAL_MS let nextJwtToken = pollOptions.jwtToken + let nextConsecutiveResubscribeFailures = consecutiveResubscribeFailures const errorResponse = response as ErrorResponse @@ -40,10 +44,24 @@ export async function renderJsonLogs({ }, }) + if (result.resubscribeFailed) { + nextConsecutiveResubscribeFailures += 1 + if (nextConsecutiveResubscribeFailures >= MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES) { + outputInfo( + JSON.stringify({message: 'App log streaming session has expired. Please restart your dev session.'}), + ) + return + } + } else { + nextConsecutiveResubscribeFailures = 0 + } + if (result.nextJwtToken) { nextJwtToken = result.nextJwtToken } retryIntervalMs = result.retryIntervalMs + } else { + nextConsecutiveResubscribeFailures = 0 } const {cursor: nextCursor, appLogs} = response as SuccessResponse @@ -76,6 +94,7 @@ export async function renderJsonLogs({ }, storeNameById, organizationId, + consecutiveResubscribeFailures: nextConsecutiveResubscribeFailures, }).catch((error) => { throw error }) diff --git a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx index 8c950cdfde2..8db428d8197 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx +++ b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx @@ -7,6 +7,7 @@ import { POLLING_ERROR_RETRY_INTERVAL_MS, POLLING_INTERVAL_MS, POLLING_THROTTLE_RETRY_INTERVAL_MS, + MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES, parseFunctionRunPayload, } from '../../../../utils.js' import { @@ -512,6 +513,48 @@ describe('usePollAppLogs', () => { expect(hook.lastResult?.errors).toHaveLength(0) }) + test('stops polling after MAX consecutive resubscribe failures', async () => { + const mockedPollAppLogs = vi.fn().mockResolvedValue(POLL_APP_LOGS_FOR_LOGS_401_RESPONSE) + vi.mocked(pollAppLogs).mockImplementation(mockedPollAppLogs) + + const mockedDeveloperPlatformClient = testDeveloperPlatformClient() + const resubscribeCallback = vi.fn().mockRejectedValue(new Error('Session expired')) + + const hook = renderHook(() => + usePollAppLogs({ + initialJwt: MOCKED_JWT_TOKEN, + filters: EMPTY_FILTERS, + resubscribeCallback, + storeNameById: STORE_NAME_BY_ID, + developerPlatformClient: mockedDeveloperPlatformClient, + organizationId: MOCKED_ORGANIZATION_ID, + }), + ) + + // needed to await the render + await vi.advanceTimersByTimeAsync(0) + + // Wait for the first poll + await waitForMockCalls(mockedPollAppLogs, 1) + + // Advance through MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES - 1 more polls + for (let i = 1; i < MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES; i++) { + // eslint-disable-next-line no-await-in-loop + await vi.advanceTimersToNextTimerAsync() + // eslint-disable-next-line no-await-in-loop + await waitForMockCalls(mockedPollAppLogs, i + 1) + } + + // Flush React 19 batched state updates + await vi.advanceTimersByTimeAsync(0) + + expect(hook.lastResult?.errors).toEqual([ + 'App log streaming session has expired. Please restart your dev session.', + ]) + // Polling should have stopped - no more timers scheduled + expect(vi.getTimerCount()).toEqual(0) + }) + test("ignores logs from stores that don't have a matching shop name", async () => { const mockedPollAppLogs = vi.fn().mockResolvedValue(POLL_APP_LOGS_FOR_LOGS_RESPONSE) vi.mocked(pollAppLogs).mockImplementation(mockedPollAppLogs) diff --git a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts index cc6f4704cd6..61be1734b54 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts @@ -2,6 +2,7 @@ import {useSelfAdjustingInterval} from './useSelfAdjustingInterval.js' import { ONE_MILLION, POLLING_INTERVAL_MS, + MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES, parseFunctionRunPayload, LOG_TYPE_FUNCTION_RUN, LOG_TYPE_RESPONSE_FROM_CACHE, @@ -57,6 +58,7 @@ async function performPoll({ organizationId, }) + let resubscribeFailed = false const errorResponse = response as ErrorResponse if (errorResponse.errors) { @@ -73,6 +75,8 @@ async function performPoll({ }, }) + resubscribeFailed = result.resubscribeFailed + if (result.nextJwtToken) { nextJwtToken = result.nextJwtToken } @@ -134,7 +138,7 @@ async function performPoll({ } } - return {nextJwtToken, retryIntervalMs, cursor: nextCursor ?? cursor} + return {nextJwtToken, retryIntervalMs, cursor: nextCursor ?? cursor, resubscribeFailed} } export function usePollAppLogs({ @@ -150,6 +154,7 @@ export function usePollAppLogs({ const nextJwtToken = useRef(initialJwt) const retryIntervalMs = useRef(0) const cursor = useRef('') + const consecutiveResubscribeFailures = useRef(0) const performPollCallback = useCallback(async () => { const res = await performPoll({ @@ -164,6 +169,16 @@ export function usePollAppLogs({ organizationId, }) + if (res.resubscribeFailed) { + consecutiveResubscribeFailures.current += 1 + if (consecutiveResubscribeFailures.current >= MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES) { + setErrors(['App log streaming session has expired. Please restart your dev session.']) + return {retryIntervalMs: 0} + } + } else { + consecutiveResubscribeFailures.current = 0 + } + // ESLint is concerned about these updates being atomic, but the approach to useSelfAdjustingInterval ensures that is the case. // eslint-disable-next-line require-atomic-updates nextJwtToken.current = res.nextJwtToken diff --git a/packages/app/src/cli/services/app-logs/utils.ts b/packages/app/src/cli/services/app-logs/utils.ts index d7da1dd93d1..78a46976059 100644 --- a/packages/app/src/cli/services/app-logs/utils.ts +++ b/packages/app/src/cli/services/app-logs/utils.ts @@ -20,6 +20,7 @@ import {Writable} from 'stream' export const POLLING_INTERVAL_MS = 450 export const POLLING_ERROR_RETRY_INTERVAL_MS = 5 * 1000 export const POLLING_THROTTLE_RETRY_INTERVAL_MS = 60 * 1000 +export const MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES = 5 export const ONE_MILLION = 1000000 export const LOG_TYPE_FUNCTION_RUN = 'function_run' export const LOG_TYPE_FUNCTION_NETWORK_ACCESS = 'function_network_access' @@ -109,11 +110,12 @@ export interface AppLogsOptions { export const handleFetchAppLogsError = async ( input: FetchAppLogsErrorOptions, -): Promise<{retryIntervalMs: number; nextJwtToken: string | null}> => { +): Promise<{retryIntervalMs: number; nextJwtToken: string | null; resubscribeFailed: boolean}> => { const {errors} = input.response let retryIntervalMs = POLLING_INTERVAL_MS let nextJwtToken = null + let resubscribeFailed = false if (errors.length > 0) { outputDebug(`Errors: ${errors.map((error) => error.message).join(', ')}`) @@ -124,6 +126,7 @@ export const handleFetchAppLogsError = async ( } catch (resubscribeError) { outputDebug(`Failed to resubscribe to app logs: ${resubscribeError}`) retryIntervalMs = POLLING_THROTTLE_RETRY_INTERVAL_MS + resubscribeFailed = true input.onThrottle(retryIntervalMs) } } else if (errors.some((error) => error.status === 429)) { @@ -135,7 +138,7 @@ export const handleFetchAppLogsError = async ( } } - return {retryIntervalMs, nextJwtToken} + return {retryIntervalMs, nextJwtToken, resubscribeFailed} } export function sourcesForApp(app: AppInterface): string[] { From f66f48febc8eb1c775ff3136519c75ec357e0eec Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Fri, 20 Mar 2026 10:50:19 -0400 Subject: [PATCH 09/11] more fixes --- .../app-logs/logs-command/render-json-logs.test.ts | 8 +++++--- .../services/app-logs/logs-command/render-json-logs.ts | 4 +--- .../ui/components/hooks/usePollAppLogs.test.tsx | 4 +--- packages/app/src/cli/services/app-logs/utils.ts | 1 + 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts index b57c5c3a127..62313752ec2 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts @@ -171,9 +171,11 @@ describe('renderJsonLogs', () => { const mockRetryInterval = 1000 const handleFetchAppLogsErrorMock = vi.fn((input) => { input.onUnknownError(mockRetryInterval) - return new Promise<{retryIntervalMs: number; nextJwtToken: string | null}>((resolve, _reject) => { - resolve({nextJwtToken: 'new-jwt-token', retryIntervalMs: mockRetryInterval}) - }) + return new Promise<{retryIntervalMs: number; nextJwtToken: string | null; resubscribeFailed: boolean}>( + (resolve, _reject) => { + resolve({nextJwtToken: 'new-jwt-token', retryIntervalMs: mockRetryInterval, resubscribeFailed: false}) + }, + ) }) vi.mocked(handleFetchAppLogsError).mockImplementation(handleFetchAppLogsErrorMock) diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts index d4bda7b20f5..f7bdad9504a 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts @@ -47,9 +47,7 @@ export async function renderJsonLogs({ if (result.resubscribeFailed) { nextConsecutiveResubscribeFailures += 1 if (nextConsecutiveResubscribeFailures >= MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES) { - outputInfo( - JSON.stringify({message: 'App log streaming session has expired. Please restart your dev session.'}), - ) + outputInfo(JSON.stringify({message: 'App log streaming session has expired. Please restart your dev session.'})) return } } else { diff --git a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx index 8db428d8197..9d4964deaf8 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx +++ b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.test.tsx @@ -548,9 +548,7 @@ describe('usePollAppLogs', () => { // Flush React 19 batched state updates await vi.advanceTimersByTimeAsync(0) - expect(hook.lastResult?.errors).toEqual([ - 'App log streaming session has expired. Please restart your dev session.', - ]) + expect(hook.lastResult?.errors).toEqual(['App log streaming session has expired. Please restart your dev session.']) // Polling should have stopped - no more timers scheduled expect(vi.getTimerCount()).toEqual(0) }) diff --git a/packages/app/src/cli/services/app-logs/utils.ts b/packages/app/src/cli/services/app-logs/utils.ts index 78a46976059..a6c3bebbec5 100644 --- a/packages/app/src/cli/services/app-logs/utils.ts +++ b/packages/app/src/cli/services/app-logs/utils.ts @@ -123,6 +123,7 @@ export const handleFetchAppLogsError = async ( if (errors.some((error) => error.status === 401)) { try { nextJwtToken = await input.onResubscribe() + // eslint-disable-next-line no-catch-all/no-catch-all } catch (resubscribeError) { outputDebug(`Failed to resubscribe to app logs: ${resubscribeError}`) retryIntervalMs = POLLING_THROTTLE_RETRY_INTERVAL_MS From c65a05bc74ee402cb9dec7f8f9be1b4f7ffa34b4 Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Tue, 24 Mar 2026 11:14:48 -0400 Subject: [PATCH 10/11] address comment --- .../services/app-logs/dev/poll-app-logs.ts | 4 ++-- .../logs-command/render-json-logs.test.ts | 23 ++++++++++++------- .../app-logs/logs-command/render-json-logs.ts | 4 ++-- .../ui/components/hooks/usePollAppLogs.ts | 10 ++++---- .../app/src/cli/services/app-logs/utils.ts | 11 +++++---- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts index 56df2724ff2..3fe334c40ce 100644 --- a/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts +++ b/packages/app/src/cli/services/app-logs/dev/poll-app-logs.ts @@ -107,13 +107,13 @@ export const pollAppLogs = async ({ }, }) - if (result.resubscribeFailed) { + if (result.resubscribeResult === 'failed') { nextConsecutiveResubscribeFailures += 1 if (nextConsecutiveResubscribeFailures >= MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES) { outputWarn('App log streaming session has expired. Please restart your dev session.', stdout) return } - } else { + } else if (result.resubscribeResult === 'succeeded') { nextConsecutiveResubscribeFailures = 0 } diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts index 62313752ec2..42359b91ec2 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.test.ts @@ -102,6 +102,7 @@ describe('renderJsonLogs', () => { }) test('should retry at throttle interval when handleFetchAppLogsError returns null token', async () => { + const timeoutSpy = vi.spyOn(global, 'setTimeout') const mockErrorResponse = { errors: [{status: 401, message: 'Unauthorized'}], } @@ -109,7 +110,11 @@ describe('renderJsonLogs', () => { vi.mocked(pollAppLogs).mockImplementation(pollAppLogsMock) const throttleRetryInterval = 60000 const handleFetchAppLogsErrorMock = vi.fn(() => { - return Promise.resolve({nextJwtToken: null, retryIntervalMs: throttleRetryInterval, resubscribeFailed: false}) + return Promise.resolve({ + nextJwtToken: null, + retryIntervalMs: throttleRetryInterval, + resubscribeResult: 'not_attempted' as const, + }) }) vi.mocked(handleFetchAppLogsError).mockImplementation(handleFetchAppLogsErrorMock) @@ -127,7 +132,7 @@ describe('renderJsonLogs', () => { expect(handleFetchAppLogsError).toHaveBeenCalled() expect(pollAppLogs).toHaveBeenCalled() - expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), throttleRetryInterval) + expect(timeoutSpy).toHaveBeenCalledWith(expect.any(Function), throttleRetryInterval) expect(vi.getTimerCount()).toEqual(1) }) @@ -138,7 +143,7 @@ describe('renderJsonLogs', () => { const pollAppLogsMock = vi.fn().mockResolvedValue(mockErrorResponse) vi.mocked(pollAppLogs).mockImplementation(pollAppLogsMock) const handleFetchAppLogsErrorMock = vi.fn(() => { - return Promise.resolve({nextJwtToken: null, retryIntervalMs: 60000, resubscribeFailed: true}) + return Promise.resolve({nextJwtToken: null, retryIntervalMs: 60000, resubscribeResult: 'failed' as const}) }) vi.mocked(handleFetchAppLogsError).mockImplementation(handleFetchAppLogsErrorMock) @@ -171,11 +176,13 @@ describe('renderJsonLogs', () => { const mockRetryInterval = 1000 const handleFetchAppLogsErrorMock = vi.fn((input) => { input.onUnknownError(mockRetryInterval) - return new Promise<{retryIntervalMs: number; nextJwtToken: string | null; resubscribeFailed: boolean}>( - (resolve, _reject) => { - resolve({nextJwtToken: 'new-jwt-token', retryIntervalMs: mockRetryInterval, resubscribeFailed: false}) - }, - ) + return new Promise<{ + retryIntervalMs: number + nextJwtToken: string | null + resubscribeResult: 'succeeded' | 'failed' | 'not_attempted' + }>((resolve, _reject) => { + resolve({nextJwtToken: 'new-jwt-token', retryIntervalMs: mockRetryInterval, resubscribeResult: 'not_attempted'}) + }) }) vi.mocked(handleFetchAppLogsError).mockImplementation(handleFetchAppLogsErrorMock) diff --git a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts index f7bdad9504a..a1bb110297e 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/render-json-logs.ts @@ -44,13 +44,13 @@ export async function renderJsonLogs({ }, }) - if (result.resubscribeFailed) { + if (result.resubscribeResult === 'failed') { nextConsecutiveResubscribeFailures += 1 if (nextConsecutiveResubscribeFailures >= MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES) { outputInfo(JSON.stringify({message: 'App log streaming session has expired. Please restart your dev session.'})) return } - } else { + } else if (result.resubscribeResult === 'succeeded') { nextConsecutiveResubscribeFailures = 0 } diff --git a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts index 61be1734b54..d2c9016fad4 100644 --- a/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts +++ b/packages/app/src/cli/services/app-logs/logs-command/ui/components/hooks/usePollAppLogs.ts @@ -58,7 +58,7 @@ async function performPoll({ organizationId, }) - let resubscribeFailed = false + let resubscribeResult: 'succeeded' | 'failed' | 'not_attempted' = 'not_attempted' const errorResponse = response as ErrorResponse if (errorResponse.errors) { @@ -75,7 +75,7 @@ async function performPoll({ }, }) - resubscribeFailed = result.resubscribeFailed + resubscribeResult = result.resubscribeResult if (result.nextJwtToken) { nextJwtToken = result.nextJwtToken @@ -138,7 +138,7 @@ async function performPoll({ } } - return {nextJwtToken, retryIntervalMs, cursor: nextCursor ?? cursor, resubscribeFailed} + return {nextJwtToken, retryIntervalMs, cursor: nextCursor ?? cursor, resubscribeResult} } export function usePollAppLogs({ @@ -169,13 +169,13 @@ export function usePollAppLogs({ organizationId, }) - if (res.resubscribeFailed) { + if (res.resubscribeResult === 'failed') { consecutiveResubscribeFailures.current += 1 if (consecutiveResubscribeFailures.current >= MAX_CONSECUTIVE_RESUBSCRIBE_FAILURES) { setErrors(['App log streaming session has expired. Please restart your dev session.']) return {retryIntervalMs: 0} } - } else { + } else if (res.resubscribeResult === 'succeeded') { consecutiveResubscribeFailures.current = 0 } diff --git a/packages/app/src/cli/services/app-logs/utils.ts b/packages/app/src/cli/services/app-logs/utils.ts index a6c3bebbec5..728e2e0ff25 100644 --- a/packages/app/src/cli/services/app-logs/utils.ts +++ b/packages/app/src/cli/services/app-logs/utils.ts @@ -108,14 +108,16 @@ export interface AppLogsOptions { } } +type ResubscribeResult = 'succeeded' | 'failed' | 'not_attempted' + export const handleFetchAppLogsError = async ( input: FetchAppLogsErrorOptions, -): Promise<{retryIntervalMs: number; nextJwtToken: string | null; resubscribeFailed: boolean}> => { +): Promise<{retryIntervalMs: number; nextJwtToken: string | null; resubscribeResult: ResubscribeResult}> => { const {errors} = input.response let retryIntervalMs = POLLING_INTERVAL_MS let nextJwtToken = null - let resubscribeFailed = false + let resubscribeResult: ResubscribeResult = 'not_attempted' if (errors.length > 0) { outputDebug(`Errors: ${errors.map((error) => error.message).join(', ')}`) @@ -123,11 +125,12 @@ export const handleFetchAppLogsError = async ( if (errors.some((error) => error.status === 401)) { try { nextJwtToken = await input.onResubscribe() + resubscribeResult = 'succeeded' // eslint-disable-next-line no-catch-all/no-catch-all } catch (resubscribeError) { outputDebug(`Failed to resubscribe to app logs: ${resubscribeError}`) retryIntervalMs = POLLING_THROTTLE_RETRY_INTERVAL_MS - resubscribeFailed = true + resubscribeResult = 'failed' input.onThrottle(retryIntervalMs) } } else if (errors.some((error) => error.status === 429)) { @@ -139,7 +142,7 @@ export const handleFetchAppLogsError = async ( } } - return {retryIntervalMs, nextJwtToken, resubscribeFailed} + return {retryIntervalMs, nextJwtToken, resubscribeResult} } export function sourcesForApp(app: AppInterface): string[] { From 1039df196892ef059ef405462f16d2fbc78f24e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaac=20Rold=C3=A1n?= Date: Fri, 27 Mar 2026 19:50:13 +0100 Subject: [PATCH 11/11] Apply suggestions from code review --- .../services/generate/fetch-extension-specifications.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/app/src/cli/services/generate/fetch-extension-specifications.ts b/packages/app/src/cli/services/generate/fetch-extension-specifications.ts index f34d799aaca..a752d56b726 100644 --- a/packages/app/src/cli/services/generate/fetch-extension-specifications.ts +++ b/packages/app/src/cli/services/generate/fetch-extension-specifications.ts @@ -46,8 +46,11 @@ export async function fetchSpecifications({ // Hardcoded value for the post purchase extension because the value is wrong in the API if (spec.identifier === 'checkout_post_purchase') spec.surface = 'post_purchase' - // Hardcoded value for the webhook_subscription extension because the value is wrong in the API - if (spec.identifier === 'webhook_subscription') spec.experience = 'configuration' + // Hardcoded values for the webhook_subscription extension because the values are wrong in the API + if (spec.identifier === 'webhook_subscription') { + spec.experience = 'configuration' + spec.uidStrategy = 'dynamic' + } return spec }) @@ -126,7 +129,7 @@ function mergeLocalAndRemoteSpec( experience: remoteSpec.experience as 'extension' | 'configuration', registrationLimit: remoteSpec.registrationLimit, uidStrategy: remoteSpec.uidStrategy, - surface: remoteSpec.surface ?? '', + surface: remoteSpec.surface ?? localSpec.surface, } return merged }