Skip to content

Add production preview store create command#7764

Open
alfonso-noriega wants to merge 1 commit into
mainfrom
productionize-preview-store-create-main
Open

Add production preview store create command#7764
alfonso-noriega wants to merge 1 commit into
mainfrom
productionize-preview-store-create-main

Conversation

@alfonso-noriega

@alfonso-noriega alfonso-noriega commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

This productionizes shopify store create preview on top of the shipped preview-store backend endpoint so an agent can create a preview store and immediately use the returned Admin API token through existing store command auth plumbing.

The command targets the production endpoint contract from shop/world:

  • unauthenticated POST /services/preview-stores
  • request body with optional top-level name
  • optional country sent as variables.storeCreatePayload.country
  • CLI attribution headers for rollout/rate-limit/tracking
  • response body with shop details, placeholder_account_uuid, admin_api_token, and access_url

WHAT is this pull request doing?

  • Adds shopify store create preview with flags:
    • --name
    • --country with two-letter code validation
    • --json
    • existing global --no-color / --verbose
  • Calls https://<app-management-fqdn>/services/preview-stores without Basic auth or Identity auth.
  • Sends:
    • X-Shopify-CLI-Instance from a stable locally persisted install id
    • X-Shopify-CLI-Version
    • User-Agent
    • JSON accept/content headers
    • variables.storeCreatePayload.country when --country is provided
  • Parses the production response shape:
    • shop.id
    • shop.name
    • shop.domain
    • placeholder_account_uuid when present
    • admin_api_token
    • access_url
  • Persists the returned Admin API token into the existing local store-auth session cache, tagged as kind: 'preview', so the store is immediately usable by shopify store execute --store <domain> without shopify store auth.
  • Persists preview-store metadata, including the returned access URL, in the store-auth session cache.
  • Prints the backend-returned access URL in text output and includes it in JSON output.
  • Redacts both admin_api_token and tokenized access_url from malformed-response diagnostics.
  • Adds generated command README, OCLIF manifest, shopify.dev command interface docs, and a changeset.

Notes / open questions

  • Preview-store token expiry is intentionally not managed in this PR.
  • The CLI handles both the requested 422 preview_store_create_failed path and the currently observed backend 500 preview_store_create_failed path defensively.
  • Store-auth persistence is performed before best-effort store FQDN metadata recording so a metadata failure does not orphan a successfully created preview store without local credentials.

How to test your changes?

Ideally, the endpoint will be ready in prod to test this (protected behind a flag) and we can test as follows:

  • Enable flag for your CLI instance UUID
  • Run from this branch pnpm shopify store create preview --country US
  • A new preview store should be created
  • The returned access URL should open the preview store
  • pnpm shopify store execute --store <returned-domain> should use the cached preview-store Admin API token

Local validation run:

  • pnpm --filter @shopify/store exec vitest run src/cli/commands/store/create/preview.test.ts src/cli/services/store/create/preview/client.test.ts src/cli/services/store/create/preview/index.test.ts src/cli/services/store/create/preview/result.test.ts src/cli/services/store/auth/session-store.test.ts
  • pnpm nx run store:lint --skip-nx-cache --output-style=stream
  • pnpm --filter @shopify/store run type-check
  • /usr/bin/git diff --check

Post-release steps

None.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows) — local persistence uses existing LocalStorage; command logic is platform-neutral.
  • I've considered possible documentation changes — command README, OCLIF manifest, generated docs interface, and generated docs data are updated.
  • I've considered analytics changes to measure impact — request sends CLI instance/version/user-agent headers read by the backend tracking path; store FQDN metadata is recorded after persistence.
  • The change is user-facing — minor changeset added for @shopify/cli and @shopify/store.

alfonso-noriega commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@github-actions github-actions Bot added the Area: @shopify/cli @shopify/cli package issues label Jun 9, 2026
@alfonso-noriega alfonso-noriega force-pushed the productionize-preview-store-create-main branch 6 times, most recently from a95b7a4 to 897e9ea Compare June 9, 2026 11:52
@alfonso-noriega alfonso-noriega force-pushed the productionize-preview-store-create-main branch 5 times, most recently from e6b9771 to f0160e7 Compare June 10, 2026 13:52
@alfonso-noriega alfonso-noriega force-pushed the productionize-preview-store-create-main branch 2 times, most recently from 72f8f19 to b504c98 Compare June 11, 2026 12:24
@alfonso-noriega alfonso-noriega marked this pull request as ready for review June 11, 2026 13:29
@alfonso-noriega alfonso-noriega requested review from a team as code owners June 11, 2026 13:29
@alfonso-noriega alfonso-noriega force-pushed the productionize-preview-store-create-main branch from b504c98 to c3f7626 Compare June 11, 2026 14:35

@tizmagik tizmagik left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor thing inline, otherwise lgtm


Review assisted by pair-review

const acquiredAt = dependencies.now().toISOString()
const userId = previewUserId(response)

await dependencies.recordStoreFqdnMetadata(response.shop.domain, false)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐛 Bug: Two concerns at this call site, both pointing at the same fix:

  1. Ordering risk: Both recordStoreFqdnMetadata calls precede setStoredStoreAppSession. The test does not persist a store session when recording store metadata fails locks this in, but at that point the backend has already created the preview store and issued an admin token — if metadata throws (e.g., 'bubble' contexts), the token is dropped and the merchant is left with an orphaned store and no local credential. Metadata is best-effort observability; it should not gate token persistence.

  2. Redundant pair of calls: In auth/index.ts the validated:falsevalidated:true transition straddles the OAuth handshake, so both states are meaningful. Here the two calls fire back-to-back with no intervening validation step, and recordStoreFqdnMetadata Object.assigns into a shared bag — so the false write is immediately overwritten by true and adds no telemetry signal.

Suggestion: Persist the session first, then record metadata once with true:

Suggested change
await dependencies.recordStoreFqdnMetadata(response.shop.domain, false)
dependencies.setStoredStoreAppSession({
store: response.shop.domain,
clientId: STORE_AUTH_APP_CLIENT_ID,
userId,
accessToken: response.adminApiToken,
scopes: [],
acquiredAt,
kind: 'preview',
preview: {
shopId: response.shop.id,
name: response.shop.name,
createdAt: acquiredAt,
...(response.placeholderAccountUuid ? {placeholderAccountUuid: response.placeholderAccountUuid} : {}),
...(country ? {country} : {}),
},
})
dependencies.setLastSeenUserId(userId)
await dependencies.recordStoreFqdnMetadata(response.shop.domain, true)

@alfonso-noriega alfonso-noriega force-pushed the productionize-preview-store-create-main branch from c3f7626 to 07d1745 Compare June 12, 2026 12:28
@alfonso-noriega alfonso-noriega force-pushed the productionize-preview-store-create-main branch from 07d1745 to f4ec45d Compare June 12, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: @shopify/cli @shopify/cli package issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants