LTRAC-910: ref(cli) - Reduce create-catalyst to a thin wrapper over catalyst create#3053
Draft
jorgemoya wants to merge 75 commits into
Draft
Conversation
Deploy now runs the Catalyst build pipeline before bundling, so users no longer need to manually run `catalyst build && catalyst deploy`.
skip build step when --prebuilt is passed; fail with actionable error when .bigcommerce/dist/ is missing or empty.
* feat(cli): map ignition error codes to actionable messages
* feat(cli): add crash reporting with trace ids Centralized error handling via withErrorHandler HOF, singleton telemetry with UUID trace ids, X-Correlation-Id headers on all API calls, and global uncaught exception handlers. On any CLI error, a trace ID is displayed for support debugging. * refactor(cli): remove traceId() and trackError() abstractions * fix(cli): update deploy tests to match error handler string output The error handler extracts the message string from Error objects before passing to consola.error, so tests should expect strings, not Error objects. * refactor(cli): move error handling from per-command HOF to top-level try/catch Replace the withErrorHandler() HOF pattern with a single try/catch around program.parseAsync() in the entry point. This makes error handling automatic for all commands instead of requiring each command author to remember to wrap their action. - Add commandName property to Telemetry, set by preAction hook via Commander's actionCommand parameter - Delete error-handler.ts and its spec - Update tests to assert error propagation via rejects.toThrow() * fix(cli): address PR feedback on error handling - Remove redundant closeAndFlush() from try block (postAction hook already handles it) - Only show trace ID when telemetry is enabled; prompt disabled users to enable telemetry without showing an unlookable trace ID * fix(cli): wrap entry point in IIFE for module compatibility
OAuth device code flow for browser-based authentication. Stores credentials in .bigcommerce/project.json.
…tility (#2888) Add resolveCredentials() that resolves storeHash/accessToken from flags, env vars, or stored config, with unified error message mentioning `catalyst auth login`. Apply to project create/list/link and deploy.
users should run next dev directly instead
start command now only runs opennextjs-cloudflare preview. vanilla next.js users should run next start directly.
Apply `.configureHelp({ showGlobalOptions: true })` to every Command and
subcommand so `catalyst <command> --help` surfaces the root-level
`--env-path` option (and other globals) under a "Global Options"
section. Previously these were only visible on `catalyst --help`.
Refs LTRAC-612
Co-authored-by: Claude <noreply@anthropic.com>
…son (#2997) * LTRAC-444: fix(cli) - Read store hash and access token from project.json `catalyst logs tail` and `catalyst logs query` now resolve credentials via `resolveCredentials`, falling back to `.bigcommerce/project.json` when `--store-hash` / `--access-token` flags or `CATALYST_STORE_HASH` / `CATALYST_ACCESS_TOKEN` env vars are not provided. This matches the behavior already used by `project`, `deploy`, and `build`, and removes the need to re-pass credentials after running `catalyst project link`. Also migrates the shared `--store-hash` / `--access-token` option helpers from the legacy `BIGCOMMERCE_*` env var names to `CATALYST_*` for consistency with the rest of the CLI. Fixes LTRAC-444 Co-Authored-By: Claude <noreply@anthropic.com> * LTRAC-444: fix(cli) - Migrate projectUuidOption env var to CATALYST_PROJECT_UUID The shared `projectUuidOption()` helper was still using the legacy `BIGCOMMERCE_PROJECT_UUID` env var name. It was missed in the earlier `CATALYST_*` rename sweep because `logs` was the only consumer at the time. The inline declarations in `build.ts` and `deploy.ts` already use `CATALYST_PROJECT_UUID`, so this aligns the helper with the rest of the CLI and the alpha.2 patch notes. Refs LTRAC-444 Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
wrangler@4.24.3 produces a broken bundle for Next.js 16.2.x: the app-page-turbo.runtime.prod.js webpack runtime fails to initialize at request time with "Cannot read properties of undefined (reading 'require')". wrangler@4.90.0 bundles it correctly. Refs TRAC-668 Co-authored-by: Claude <noreply@anthropic.com>
Move @commander-js/extra-typings from devDependencies to dependencies. It is externalized in the tsup build and must be installed at runtime; previously missing from the published package caused CLI startup to fail with ERR_MODULE_NOT_FOUND. Co-Authored-By: Claude <noreply@anthropic.com>
The deploy command used to silently scan process.env for an allowlist of keys (BIGCOMMERCE_STORE_HASH, BIGCOMMERCE_CHANNEL_ID, BIGCOMMERCE_STOREFRONT_TOKEN, BIGCOMMERCE_API_HOST, BIGCOMMERCE_GRAPHQL_API_DOMAIN, AUTH_SECRET) and ship any matches as deployment secrets. A developer with .env.local populated for local dev could push those dev values to production without noticing. Require explicit --secret KEY=VALUE declarations instead, matching the explicit-only model other deploy CLIs (Vercel, Netlify, Wrangler) follow. Co-authored-by: Claude <noreply@anthropic.com>
…eractive (#3026) * LTRAC-613: feat(cli) - Make auth login and project create onboarding interactive First-time users hit `failed to request device code: 404 Not Found` when running `catalyst auth login` before `catalyst project create`, with no obvious way to recover. Make the login flow self-sufficient by adding a manual-credentials fallback: if the device-code endpoint fails, the CLI warns with the underlying reason, asks whether to fall back to entering a store hash + access token directly, and validates the manual creds against the store profile API before persisting them. `catalyst project create` no longer fails fast when credentials are missing — it kicks off the same interactive login flow inline, so users don't need to know the ordering. `catalyst create` (scaffolding) picks up the manual fallback automatically since it shares the orchestrator. Refs LTRAC-613 Co-Authored-By: Claude <noreply@anthropic.com> * LTRAC-613: chore(cli) - Drop changeset for interactive auth onboarding Refs LTRAC-613 Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…3027) When the API proxy half-closes the socket — bytes stop arriving but no FIN or error is surfaced — `reader.read()` blocks forever, so the 1-minute connection TTL check below it never runs and the stream goes silent until the user restarts `catalyst logs tail`. Race `reader.read()` against the remaining TTL so the TTL acts as an absolute deadline. When it fires we cancel the reader, break out of the inner loop, and the outer reconnect loop opens a fresh stream. Warn the user only when no data arrived during the window — healthy rotations stay silent to match existing behavior. Refs LTRAC-440 Co-authored-by: Claude <noreply@anthropic.com>
Wrangler's `--outdir` writes the deployment bundle alongside whatever is
already in `.bigcommerce/dist` rather than replacing the directory. When
Wrangler is upgraded between builds — or any prior artifact lingers —
old files end up in the zip uploaded to the server.
In one observed case the dist contained both the current Wrangler 4.x
plain wasm names and `?module`-suffixed copies from an older Wrangler
version. The `?` in the filenames confused the server-side multipart
upload to Cloudflare and the deploy failed with:
Uncaught Error: No such module "<hash>-resvg.wasm".
imported from "worker.js"
Wipe the dist directory at the start of `buildCatalystProject` so each
build starts from a clean slate.
Refs LTRAC-814
Co-authored-by: Claude <noreply@anthropic.com>
Split the SSE reader's connection lifecycle from its read pump. The
outer loop in `tailLogs` now owns opening streams, retrying transient
errors, and emitting user-facing reconnect messages. The inner loop
becomes a standalone `pumpUntilRotation` that reads bytes from a single
connection and returns a `Rotation` value ('ttl' | 'idle-timeout' |
'stream-done') describing why it stopped, instead of using break +
side-effecting warnings.
No behavior change — every rotation reason and error path maps to the
same user-facing output and retry semantics as before, and the existing
test suite passes unmodified.
Refs LTRAC-440
Co-authored-by: Claude <noreply@anthropic.com>
* LTRAC-807: fix(cli) - Strip @vercel/otel hook in Commerce Hosting setup
`core/instrumentation.ts` registers `@vercel/otel`. OpenNext bundles the
storefront as a Node-style worker, so the bundler resolves `@vercel/otel`
through its `node` export condition and pulls `@opentelemetry/sdk-node`
into the worker chunk. At cold start, workerd evaluates Node-only side
effects that `nodejs_compat` doesn't cover and throws — Next.js's
instrumentation loader surfaces this as "Failed to prepare server" on
every cold start in `catalyst logs tail`.
No code in `/core` actually consumes the tracer, so we drop the file (and
the `@vercel/otel` dependency) as part of `setupCommerceHosting`, next to
the existing `convertProxyToMiddleware` step. The change is scoped to the
Commerce Hosting opt-in path; self-hosted / Vercel deploys keep the file.
Fixes LTRAC-807
Co-Authored-By: Claude <noreply@anthropic.com>
* LTRAC-807: fix(cli) - Run OTel cleanup on already-transformed projects
The first patch only removed `core/instrumentation.ts` and `@vercel/otel`
as part of `setupCommerceHosting`, which is gated by `!isTransformed` in
both `offerCommerceHostingSetup` and `deploy`. Existing Commerce Hosting
users — those already transformed — never hit that code path on re-link
or re-deploy, so they kept seeing the cold-start error.
Extract the cleanup into `cleanupCloudflareIncompatibilities` and call it
from the transformed branches of both flows (and from `setupCommerceHosting`
itself, for fresh users). Idempotent and silent unless it actually removed
something — in which case it logs a one-line `consola.info` so the user
sees what changed.
Refs LTRAC-807
Co-Authored-By: Claude <noreply@anthropic.com>
* LTRAC-807: fix(cli) - Prompt before removing instrumentation hook
Vercel users who customized `core/instrumentation.ts` would have their work
silently wiped when running `catalyst project link` or `catalyst deploy`,
because the cleanup helper unconditionally deleted the file and dropped
`@vercel/otel`. Make the cleanup interactive instead: in a TTY, prompt
before doing anything; in non-TTY (CI), warn and skip so headless deploys
preserve customizations. The dep removal is tied to the file decision —
if the file stays, the dep stays (the customized file probably imports it).
`setupCommerceHosting` is now async (it awaits the cleanup). All callers
(`offerCommerceHostingSetup`, `deploy`, `create`, `runCommerceHostingSetup`)
are updated to await it.
Refs LTRAC-807
Co-Authored-By: Claude <noreply@anthropic.com>
* LTRAC-807: style(cli) - Add blank line after instrumentation prompt
The "Removed core/instrumentation.ts ..." (or "Leaving ...") info log
landed directly under the user's Yes/No answer with no spacing, making
the prompt and the result visually run together. Insert a `consola.log('')`
right after the prompt resolves so the answer and the result are
separated by a blank line.
Refs LTRAC-807
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
…s tail (#3038) * LTRAC-808: fix(cli) - Suppress OpenNext IMAGES binding warning in logs tail OpenNext's Cloudflare image handler logs `env.IMAGES binding is not defined` on every `/_next/image` request when no IMAGES binding is configured, then falls back to serving the original bytes. Native Hosting intentionally runs without that binding, so the warning is expected noise that flooded testers watching `catalyst logs tail`. Filter the warning out of the human-readable log formats and drop events that contain nothing but suppressed noise. Raw `--format json` output is left untouched so piped consumers still see the full stream. Fixes LTRAC-808 Co-Authored-By: Claude <noreply@anthropic.com> * LTRAC-808: chore(cli) - Drop changeset (not needed on alpha branch) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…#3039) Passing `--secret KEY=VALUE` for every env var on every `catalyst deploy` is cumbersome and error-prone, and got worse after implicit secret detection was removed (LTRAC-640): nothing reaches a deployment unless every secret is re-typed. Add a `catalyst env` command group (`add`, `remove`, `list`) that stores deployment secrets in `.bigcommerce/project.json` (gitignored, alongside the already-persisted access token). `catalyst deploy` now sends these automatically, merging them with any inline `--secret` flags — inline flags win on conflict so a stored value can still be overridden per-run. Stored vars are deploy-only (not injected into the local build) and are always sent as `secret`. Values are masked in all command output. A shared `parseEnvAssignment` splits on the first `=`, so values containing `=` (e.g. base64/tokens) survive intact — a fix over deploy's prior `split('=')`. Refs LTRAC-442 Co-authored-by: Claude <noreply@anthropic.com>
…3040) Expired device-code access tokens caused `project list`, `deploy`, `logs tail`, and `auth whoami` to fail with a generic "Unauthorized" message, leaving users unsure they needed to re-authenticate. The CLI stores no expiry/refresh metadata, so silent renewal isn't possible. Add a shared `SessionExpiredError` plus `assertAuthorized(response)` and call it at every authenticated fetch site so a 401 consistently directs the user to run `catalyst auth login`. 403 (e.g. "Infrastructure Projects API not enabled") is intentionally left unchanged since it is overloaded for scope/feature-flag errors. Refs LTRAC-441 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l-worker) (#3041) The OpenNext `env.IMAGES binding is not defined` warning is a platform fact, not a per-client preference: Commerce Hosting intentionally runs without that binding, so the warning is always noise for every consumer. Filtering it in the CLI (#3038) only helped users on a new enough CLI and did nothing for the copies forwarded into Sentry. The suppression now lives in the ignition-tail-worker, where it applies to all CLI versions and consumers at once and is also dropped from Sentry. Remove the now-redundant CLI-side filter and its tests so there is a single source of truth. Must merge AFTER the tail-worker change is deployed; otherwise newer-CLI users briefly see the warning again until the worker filter is live. Refs LTRAC-808 Co-authored-by: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…3045) The build pinned compatibility_date to 2025-09-15 while the deployment service stamps a current date at deploy time, so workers ran under newer Cloudflare runtime semantics than they were built against. Compute the date as current UTC date minus one month, matching the same offset the deployment service applies, so build and deploy semantics stay aligned. Refs LTRAC-873 Co-authored-by: Claude <noreply@anthropic.com>
…catalyst create` create-catalyst now delegates to `@bigcommerce/catalyst`: its entry resolves the catalyst bin from its own dependency tree and spawns `catalyst create`, forwarding all args (stdio inherited, exit code and signals propagated). All scaffolding logic now lives in @bigcommerce/catalyst. - Add @bigcommerce/catalyst as a workspace dependency; drop the ~20 runtime deps the old in-package commands needed. - Delete the duplicated commands/, utils/, prompts/, and hooks/. - Bump the tsup target to node24 so esbuild preserves `import.meta.url`. Package name and `bin` are unchanged, so `pnpm create catalyst` / `npx create-catalyst` keep working. The dropped init/integration/telemetry subcommands are superseded by `catalyst channel link`, (integration dropped), and `catalyst telemetry`. Refs LTRAC-910 Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: c7e8ce0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
Refs LTRAC-910 Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
Bundle Size ReportComparing against baseline from
Per-Route First Load JS
|
Contributor
Unlighthouse Performance Comparison — VercelComparing PR preview deployment Unlighthouse scores vs production Unlighthouse scores. Summary ScoreAggregate score across all categories as reported by Unlighthouse.
Category Scores
Core Web Vitals
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linear: LTRAC-910
Part of LTRAC-138 — consolidating
create-catalystinto thecatalystCLI (Phase 2).What/Why?
create-catalystshipped its own full copy of the scaffolding flow (create/init/integration/telemetry+ a largeutils//prompts/). Now that@bigcommerce/catalystownscreate, this reducescreate-catalystto a thin wrapper that delegates to it — single source of truth, mirroring howcreate-next-appfrontsnext.Delegation (option B — spawn): the entry resolves the
@bigcommerce/catalystbin from its own dependency tree (createRequire→ the package'sbin) and spawnscatalyst create, forwarding all args with inherited stdio and propagating the child's exit code / signals. Because@bigcommerce/catalystis a regulardependency,pnpm create catalyst/npx create-catalystinstall it alongside the wrapper — no globalcatalystneeded.@bigcommerce/catalyst(workspace:^) as a dependency; dropped ~20 runtime deps the old in-package commands required.commands/,utils/,prompts/,hooks/(keptnode-version.spec.ts, moved tosrc/).targettonode24so esbuild preservesimport.meta.url(a lower target shimmed it to{}, which brokecreateRequire).Scope note (changed from the original ticket)
The ticket assumed
init+integrationwere ported into@bigcommerce/catalyst. They weren't:integrationwas dropped (LTRAC-909 canceled) andinit's useful behavior becamecatalyst channel link(LTRAC-908). So this wrapper is scaffold-only —create-catalyst'sinit/integration/telemetrysubcommands are dropped. In the consolidated CLI:init→catalyst channel link,integration→ dropped,telemetry→catalyst telemetry.Testing
pnpm build,pnpm typecheck,pnpm lint,pnpm testall pass inpackages/create-catalyst(thenode-versiongating test is retained).End-to-end: built both packages and ran
node packages/create-catalyst/dist/index.js create --help→ it shows@bigcommerce/catalyst create's banner + help, confirming delegation. Exit codes/signals are mirrored from the child.Release / rollout
create-catalystand@bigcommerce/catalystmust now be published in lockstep — theworkspace:^is rewritten to a concrete version at publish, so the dependency range must include the published catalyst version. Changesets should bump both together.Migration
pnpm create catalyst/npx create-catalystUX is unchanged for scaffolding. Anyone who usedcreate-catalyst init/integration/telemetrydirectly should switch to thecatalyst …equivalents noted above.