From 8b6e75a7cb52036fbac3d5730ff3655367c2dd4e Mon Sep 17 00:00:00 2001 From: Donald Merand Date: Mon, 18 May 2026 15:11:50 -0400 Subject: [PATCH] Add public shop_domain to CLI command analytics --- packages/app/src/cli/metadata.ts | 3 ++- packages/app/src/cli/services/dev.ts | 1 + .../src/cli/services/store-context.test.ts | 26 +++++++++++++++++++ .../app/src/cli/services/store-context.ts | 3 ++- packages/cli-kit/src/public/node/metadata.ts | 1 + .../cli-kit/src/public/node/monorail.test.ts | 2 ++ packages/cli-kit/src/public/node/monorail.ts | 3 ++- .../cli/services/store/attribution.test.ts | 4 ++- .../src/cli/services/store/attribution.ts | 6 ++++- .../theme/src/cli/utilities/theme-command.ts | 1 + 10 files changed, 45 insertions(+), 5 deletions(-) diff --git a/packages/app/src/cli/metadata.ts b/packages/app/src/cli/metadata.ts index 79f11dbde89..8a42399084d 100644 --- a/packages/app/src/cli/metadata.ts +++ b/packages/app/src/cli/metadata.ts @@ -10,7 +10,8 @@ type CmdFieldsFromMonorail = PickByPrefix & PickByPrefix & PickByPrefix & - PickByPrefix + PickByPrefix & + Pick type CmdSensitiveFieldsFromMonorail = PickByPrefix & PickByPrefix & diff --git a/packages/app/src/cli/services/dev.ts b/packages/app/src/cli/services/dev.ts index 2798403311b..fe5180840b0 100644 --- a/packages/app/src/cli/services/dev.ts +++ b/packages/app/src/cli/services/dev.ts @@ -476,6 +476,7 @@ async function logMetadataForDev(options: { cmd_dev_tunnel_custom_hash: tunnelType === 'custom' ? hashString(options.tunnelUrl) : undefined, cmd_dev_urls_updated: options.shouldUpdateURLs, store_fqdn_hash: hashString(options.storeFqdn), + shop_domain: options.storeFqdn, cmd_app_dependency_installation_skipped: options.devOptions.skipDependenciesInstallation, })) diff --git a/packages/app/src/cli/services/store-context.test.ts b/packages/app/src/cli/services/store-context.test.ts index 6b3bd1e0306..330d8ab59ae 100644 --- a/packages/app/src/cli/services/store-context.test.ts +++ b/packages/app/src/cli/services/store-context.test.ts @@ -174,6 +174,7 @@ describe('storeContext', () => { expect(meta).toEqual( expect.objectContaining({ store_fqdn_hash: hashString(mockStore.shopDomain), + shop_domain: mockStore.shopDomain, }), ) @@ -186,6 +187,31 @@ describe('storeContext', () => { }) }) + test('normalizes the selected store before logging metadata', async () => { + await inTemporaryDirectory(async (dir) => { + const unnormalizedStore = testOrganizationStore({shopId: 'store1', shopDomain: 'test-store'}) + vi.mocked(fetchStore).mockResolvedValue(unnormalizedStore) + await prepareAppFolder(mockApp, dir) + + await storeContext({appContextResult, forceReselectStore: false}) + + const meta = metadata.getAllPublicMetadata() + expect(meta).toEqual( + expect.objectContaining({ + store_fqdn_hash: hashString('test-store.myshopify.com'), + shop_domain: 'test-store.myshopify.com', + }), + ) + + const sensitiveMeta = metadata.getAllSensitiveMetadata() + expect(sensitiveMeta).toEqual( + expect.objectContaining({ + store_fqdn: 'test-store.myshopify.com', + }), + ) + }) + }) + test('adds hidden config to gitignore if needed', async () => { await inTemporaryDirectory(async (dir) => { await prepareAppFolder(mockApp, dir) diff --git a/packages/app/src/cli/services/store-context.ts b/packages/app/src/cli/services/store-context.ts index a0df8b837eb..9af3e3c9093 100644 --- a/packages/app/src/cli/services/store-context.ts +++ b/packages/app/src/cli/services/store-context.ts @@ -64,8 +64,8 @@ export async function storeContext({ selectedStore = await selectStore(allStores, organization, developerPlatformClient) } - await logMetadata(selectedStore, forceReselectStore) selectedStore.shopDomain = normalizeStoreFqdn(selectedStore.shopDomain) + await logMetadata(selectedStore, forceReselectStore) // Save the selected store in the hidden config file if (selectedStore.shopDomain !== cachedStoreURL || !devStoreUrlFromHiddenConfig) { @@ -82,6 +82,7 @@ async function logMetadata(selectedStore: OrganizationStore, resetUsed: boolean) await metadata.addPublicMetadata(() => ({ cmd_app_reset_used: resetUsed, store_fqdn_hash: hashString(selectedStore.shopDomain), + shop_domain: selectedStore.shopDomain, })) await metadata.addSensitiveMetadata(() => ({ diff --git a/packages/cli-kit/src/public/node/metadata.ts b/packages/cli-kit/src/public/node/metadata.ts index 1b6223f7b4b..79862d3c8a2 100644 --- a/packages/cli-kit/src/public/node/metadata.ts +++ b/packages/cli-kit/src/public/node/metadata.ts @@ -182,6 +182,7 @@ type CmdFieldsFromMonorail = PickByPrefix & PickByPrefix & PickByPrefix & PickByPrefix & + Pick & PickByPrefix const coreData = createRuntimeMetadataContainer< diff --git a/packages/cli-kit/src/public/node/monorail.test.ts b/packages/cli-kit/src/public/node/monorail.test.ts index 1a4df1ed46a..1f5fd29642a 100644 --- a/packages/cli-kit/src/public/node/monorail.test.ts +++ b/packages/cli-kit/src/public/node/monorail.test.ts @@ -70,6 +70,7 @@ describe('monorail', () => { user_id: '42', store_fqdn_hash: 'hashed-store', store_fqdn_validated: true, + shop_domain: 'shop.myshopify.com', }, { args: '--store shop.myshopify.com', @@ -98,6 +99,7 @@ describe('monorail', () => { user_id: '42', store_fqdn_hash: 'hashed-store', store_fqdn_validated: true, + shop_domain: 'shop.myshopify.com', args: '--store shop.myshopify.com', store_fqdn: 'shop.myshopify.com', }, diff --git a/packages/cli-kit/src/public/node/monorail.ts b/packages/cli-kit/src/public/node/monorail.ts index 66b9ce1e9db..982dd34ad2d 100644 --- a/packages/cli-kit/src/public/node/monorail.ts +++ b/packages/cli-kit/src/public/node/monorail.ts @@ -10,7 +10,7 @@ const url = 'https://monorail-edge.shopifysvc.com/v1/produce' type Optional = T | null // This is the topic name of the main event we log to Monorail, the command tracker -export const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.24' +export const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.25' export interface Schemas { [MONORAIL_COMMAND_TOPIC]: { @@ -46,6 +46,7 @@ export interface Schemas { is_employee: boolean store_fqdn_hash?: Optional store_fqdn_validated?: Optional + shop_domain?: Optional user_id: string // Any and all commands diff --git a/packages/store/src/cli/services/store/attribution.test.ts b/packages/store/src/cli/services/store/attribution.test.ts index 799a5971061..32d390141b8 100644 --- a/packages/store/src/cli/services/store/attribution.test.ts +++ b/packages/store/src/cli/services/store/attribution.test.ts @@ -12,7 +12,7 @@ describe('store command attribution', () => { vi.mocked(hashString).mockReturnValue('hashed-store') }) - test('records the sensitive, hashed, and validation state for a store fqdn', async () => { + test('records the sensitive, hashed, validation, and public shop domain for a store fqdn', async () => { await recordStoreFqdnMetadata('shop.myshopify.com', true) expect(addSensitiveMetadata).toHaveBeenCalledWith(expect.any(Function)) @@ -21,7 +21,9 @@ describe('store command attribution', () => { expect(vi.mocked(addPublicMetadata).mock.calls[0]![0]()).toEqual({ store_fqdn_hash: 'hashed-store', store_fqdn_validated: true, + shop_domain: 'shop.myshopify.com', }) expect(hashString).toHaveBeenCalledWith('shop.myshopify.com') }) + }) diff --git a/packages/store/src/cli/services/store/attribution.ts b/packages/store/src/cli/services/store/attribution.ts index 7479bc7891e..aac5ef3760f 100644 --- a/packages/store/src/cli/services/store/attribution.ts +++ b/packages/store/src/cli/services/store/attribution.ts @@ -3,5 +3,9 @@ import {addPublicMetadata, addSensitiveMetadata} from '@shopify/cli-kit/node/met export async function recordStoreFqdnMetadata(storeFqdn: string, validated: boolean): Promise { await addSensitiveMetadata(() => ({store_fqdn: storeFqdn})) - await addPublicMetadata(() => ({store_fqdn_hash: hashString(storeFqdn), store_fqdn_validated: validated})) + await addPublicMetadata(() => ({ + store_fqdn_hash: hashString(storeFqdn), + store_fqdn_validated: validated, + shop_domain: storeFqdn, + })) } diff --git a/packages/theme/src/cli/utilities/theme-command.ts b/packages/theme/src/cli/utilities/theme-command.ts index 1c63e8b9970..59f9a462c63 100644 --- a/packages/theme/src/cli/utilities/theme-command.ts +++ b/packages/theme/src/cli/utilities/theme-command.ts @@ -387,6 +387,7 @@ export default abstract class ThemeCommand extends Command { const data = compileData() await addPublicMetadata(() => ({ store_fqdn_hash: hashString(session.storeFqdn), + shop_domain: session.storeFqdn, cmd_theme_timings: JSON.stringify(data.timings), cmd_theme_errors: JSON.stringify(data.errors),