Skip to content

LTRAC-1962: feat(cli) - Put checkout on the storefront's domain for native hosting - #3243

Open
jorgemoya wants to merge 22 commits into
jorgemoya/ltrac-1946-cli-stop-telling-merchants-a-checkout-subdomain-cant-befrom
jorgemoya/ltrac-1962-cli-set-the-channels-checkout-url-to-the-provisioned
Open

jorgemoya wants to merge 22 commits into
jorgemoya/ltrac-1946-cli-stop-telling-merchants-a-checkout-subdomain-cant-befrom
jorgemoya/ltrac-1962-cli-set-the-channels-checkout-url-to-the-provisioned

Conversation

@jorgemoya

@jorgemoya jorgemoya commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Linear: LTRAC-1962, LTRAC-2014

Stacked on #3240. Absorbs #3247. Needs nothing from ignition: the checkout hostname belongs to the channel and is released by sites-service, not by project teardown.

What/Why?

A native-hosted channel stayed on its mybigcommerce.com URL, with checkout on the default channel's domain. For a storefront on the managed zone, this puts checkout on https://c.<project>.<zone>:

  • deploy --update-site-url --update-checkout-url sets it without asking.
  • A plain interactive deploy asks two questions, each checked separately every time: point the channel at the deployment, then move checkout to c.. Both default to No, and a "no" is saved per channel in .bigcommerce/project.json.
  • channels update offers the checkout URL after a site URL change, because that change deletes it.

It writes first, then waits. The checkout-url PUT is what provisions the hostname: sites-service passes it to bcserver ADD_DOMAIN, which creates the DNS record, the custom hostname and the certificate, in about 90s on integration. The CLI waits up to 6 minutes for TLS, and DELETEs the URL if no certificate issues.

Worth a look:

  • Managed zone only. A merchant domain still prompts.
  • An existing custom checkout URL is left alone.
  • An unchanged site URL isn't re-sent. sites-service deletes the checkout URL on every site URL update (WorkWithDomains.chooseDomainsForUpdate).
  • Channel and hostname come from the deploy, never a picker. The channel is BIGCOMMERCE_CHANNEL_ID, with deployment secrets first, as OpenNext resolves it at runtime.
  • No prompts without a TTY or with CI set.

Testing

Flow, site-flow, deploy-channel-urls, channels and deploy specs pass, including with CI=true; tsc and eslint are clean. Verified on integration: two confirmations, then … is serving checkout., and checkout renders on c.<project>.

Migration

None.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
catalyst Ready Ready Preview Sep 25, 2026 6:30pm UTC

Request Review

@changeset-bot

changeset-bot Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7a1c68a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@bigcommerce/catalyst Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Bundle Size Report

Comparing against baseline from b341810 (2026-09-25).

No bundle size changes detected.

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Unlighthouse Performance Comparison — Vercel

Comparing PR preview deployment Unlighthouse scores vs production Unlighthouse scores.

Summary Score

Aggregate score across all categories as reported by Unlighthouse.

Prod Desktop Prod Mobile Preview Desktop Preview Mobile
Score 91 95 92 95

Category Scores

Category Prod Desktop Prod Mobile Preview Desktop Preview Mobile
Performance 74 85 77 82
Accessibility 95 98 95 92
Best Practices 100 100 100 100
SEO 100 100 100 100

Core Web Vitals

Metric Prod Desktop Prod Mobile Preview Desktop Preview Mobile
LCP 3.9 s 4.3 s 3.6 s 4.8 s
CLS 0.039 0.003 0 0
FCP 1.2 s 1.2 s 1.2 s 1.2 s
TBT 0 ms 0 ms 0 ms 0 ms
Max Potential FID 50 ms 50 ms 50 ms 50 ms
Time to Interactive 3.9 s 4.3 s 3.6 s 4.9 s

Full Unlighthouse report →

…hostname

`deploy --update-site-url --update-checkout-url` asked the merchant to type a
checkout URL, defaulting to a `checkout.` subdomain that nothing provisions on a
managed hosting zone. Derive the hostname native hosting actually creates and
set it without prompting.

The hostname is derived, not transported. ignition builds the same name from the
same prefix, so carrying it over the API would add a field that can disagree
with reality — and would have needed a `bc-interfaces` release, which would have
blocked this on a cross-repo dependency.

Wait for that hostname to serve a valid certificate before writing. The
checkout-url endpoint does no certificate validation of its own: it accepts any
hostname sharing a main domain with the storefront, whether or not anything
answers there. Setting it early leaves checkout resolving without a
certificate, which is worse for a shopper than the inherited URL it replaced.
The wait matches how long BigCommerce keeps trying before giving up, and a
hostname that never comes up leaves checkout alone rather than being written.

`runChannelSiteUrlFlow` now reports which hostname it set, so the checkout step
derives from that rather than guessing which of a project's hostnames was
chosen. Without a site URL update there is nothing to derive from, so that path
prompts exactly as before — as does a storefront on a custom domain.

Refs LTRAC-1962
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jorgemoya
jorgemoya force-pushed the jorgemoya/ltrac-1962-cli-set-the-channels-checkout-url-to-the-provisioned branch from bf0f288 to f023db4 Compare September 24, 2026 15:43
@jorgemoya
jorgemoya force-pushed the jorgemoya/ltrac-1946-cli-stop-telling-merchants-a-checkout-subdomain-cant-be branch from 75362a0 to 63d7c03 Compare September 24, 2026 15:43
jorgemoya and others added 2 commits September 24, 2026 14:30
…certificate

The flow waited for the `c.` checkout hostname to serve a certificate and
only then set it as the channel's checkout URL, expecting ignition to have
provisioned the hostname. Testing on integration showed the checkout-url
PUT is itself what provisions it: sites-service registers the hostname with
bcserver, which creates the DNS record and Cloudflare custom hostname and
issues the certificate. With ignition also registering it, the PUT failed
with canonical-in-use; without ignition, waiting first could never finish.

Now the flow writes the checkout URL, then waits up to six minutes for the
certificate. If none issues it deletes the checkout URL, which also
releases the hostname in bcserver, so checkout falls back to the default
channel's rather than staying broken. An existing custom checkout URL is
left alone, and a re-run that finds the hostname already set only waits.

The managed-zone branch moves into runChannelCheckoutUrlFlow behind a
`storefrontHostname` option, so deploy only passes the hostname through,
and it only fires for hostnames on the zones native hosting generates. A
merchant domain from `catalyst domains add` now prompts as before instead
of having a `c.` subdomain registered for it.

Refs LTRAC-1962
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jorgemoya jorgemoya changed the title LTRAC-1962: feat(cli) - Derive the checkout URL from the provisioned hostname LTRAC-1962: feat(cli) - Set the managed-zone checkout URL on deploy Sep 24, 2026
@jorgemoya
jorgemoya marked this pull request as ready for review September 24, 2026 19:39
@jorgemoya
jorgemoya requested a review from a team as a code owner September 24, 2026 19:39
@jorgemoya
jorgemoya marked this pull request as draft September 24, 2026 19:47
jorgemoya and others added 3 commits September 24, 2026 15:32
A deploy without --update-site-url or --update-checkout-url left the
channel on its mybigcommerce.com storefront URL and the default channel's
checkout, and said nothing, so the address bar changed domain at payment
unless the merchant knew the flags.

After an interactive deploy, if the channel the build targets doesn't
already point at the project, ask whether to update its site URL, with that
channel and the new hostname pre-selected. If the site then sits on an
auto-generated hostname and checkout is elsewhere, ask whether to move
checkout to c.<hostname>, using the same write-then-wait flow as the flag.
Declining that prints the cross-domain warning instead.

Declining the site URL is saved per channel in project.json so later
deploys stay quiet. Checkout declines aren't saved, since the site URL
prompt that leads to it doesn't come back. Explicit flags, channels
update, and deploys without a TTY behave as before.

Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… one

The post-deploy site URL offer opened the channel picker with the deployed
channel pre-selected. The deploy already knows which channel the build
targets, so asking again only invited pointing a different channel at this
storefront. Pass the channel through; only the hostname is prompted for.
That leaves the picker's default-channel option unused, so it goes.

Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…annel

The post-deploy offer took BIGCOMMERCE_CHANNEL_ID from the env files first
and fell back to deployment secrets. At runtime it's the other way round:
OpenNext copies the worker's bindings onto process.env first and only fills
unset keys from the env files baked in at build time. So with both set, the
offer could name a different channel from the one the storefront serves.
Check the secrets (project.json env and --secret) first.

Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jorgemoya and others added 3 commits September 24, 2026 15:48
…for it

After agreeing to point the channel at the deployment, the merchant still
got a hostname picker with the new deployment pre-selected. The deploy
already reports the hostname it went live on, so pass it through. The
picker now only shows if the deploy status carried no hostname.

Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sites-service deletes a channel's checkout URL on every site URL update,
including an update to the same URL (WorkWithDomains.chooseDomainsForUpdate
puts every non-canonical domain but the updated one up for deletion), and
the deletion releases the hostname in bcserver. So a re-deploy with
--update-site-url --update-checkout-url dropped the `c.` checkout hostname,
then re-registered it, leaving checkout without a certificate for a minute
or two on every deploy.

Read the site first and skip the PUT when the primary already matches. The
read is best-effort: if it fails, write as before.

Refs LTRAC-1962
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jorgemoya and others added 2 commits September 24, 2026 16:31
…fter channels update

The checkout offer only existed as the second step of the site URL offer,
and deploys skip that once the site points at the project. So checkout was
never offered again after one decline, never offered at all when the site
URL was set some other way, and a checkout later dropped by a site URL
change went unnoticed.

Check the two separately on every deploy. The checkout offer moves into a
shared offerManagedCheckoutUrl: on the managed zone, when checkout is on
another domain and wasn't customized there by the merchant, offer the `c.`
hostname. A decline is now saved (declinedCheckoutUrlChannels), since
re-checking every deploy would otherwise ask every time.

channels update makes the same offer after it updates a site URL, because
that update deletes the channel's checkout URL. As an explicit command it
asks despite an earlier decline, and falls back to the cross-domain warning
when there's nothing to offer.

Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The site and checkout offers after a deploy defaulted to Yes, so pressing
Enter past an unexpected question rewrote a live channel's URLs. Nothing
asked for them, so default to No. channels update keeps Yes for its
checkout follow-up, since the site URL change there was requested.

Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jorgemoya and others added 5 commits September 25, 2026 10:49
The post-deploy offers and the channels update checkout follow-up only
checked for a TTY. Some CI setups allocate a pseudo-terminal (docker run
-t, script), where a prompt waits for input nobody gives and the job hangs.
Also skip when CI is set, which CI systems define.

Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Refs LTRAC-1962
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Refs LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LTRAC-2014's post-deploy offers ship in the same PR as the managed-zone
checkout flow, so describe them in one changelog entry.

Refs LTRAC-1962, LTRAC-2014
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jorgemoya jorgemoya changed the title LTRAC-1962: feat(cli) - Set the managed-zone checkout URL on deploy LTRAC-1962: feat(cli) - Put checkout on the storefront's domain for native hosting Sep 25, 2026
jorgemoya and others added 2 commits September 25, 2026 12:20
Refs LTRAC-1962
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ckout-url alone

Without --update-site-url the checkout flow had no storefront hostname, so a
managed-zone channel was prompted with a checkout. default and never waited
for the certificate. That is also the command the certificate-timeout message
tells people to re-run. Derive the hostname from the channel's primary URL
instead. An explicit --checkout-url is still written as given.

Refs LTRAC-1962
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 7a1c68a7 Deployed Sep 25, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants