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 now targets the production endpoint contract from shop/world:

  • unauthenticated POST /services/preview-stores
  • request body with optional name and explicit country_code
  • CLI attribution headers for rollout/rate-limit/tracking
  • response body with shop details and admin_api_token

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
  • Parses the production response shape:
    • shop.id
    • shop.name
    • shop.domain
    • placeholder_account_uuid when present
    • admin_api_token
  • 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.
  • Adds preview-store metadata sanitization to the store-auth session cache.
  • Keeps output structured and link-free for now because the backend does not return storefront/save URLs yet.
  • Adds generated command README, OCLIF manifest, shopify.dev command interface docs, and a changeset.

Notes / open questions

  • The create response currently does not include save/account links, so JSON/text output intentionally omits those fields. They can be added later without changing the existing shape.
  • The CLI handles both the requested 422 preview_store_create_failed path and the currently observed backend 500 preview_store_create_failed path defensively.

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
  • A new preview store should be created and the provided links working (preview and claim)

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 before/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

This stack of pull requests is managed by Graphite. Learn more about stacking.

@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)

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