feat(builder): support Shopify scaffolding in application builder#902
feat(builder): support Shopify scaffolding in application builder#902tannerlinsley wants to merge 1 commit intomainfrom
Conversation
Bumps @tanstack/create to ^0.66.0 to pick up the shopify add-on and shopify-storefront example, then plumbs the new CLI surface through the builder so users can configure storefronts end to end: - buildCliCommand (prompt path) emits --template (gated by an allowlist of real CLI template ids) and --add-on-config (serialized featureOptions) - new "ecommerce" intent + customerAccount detection in the deterministic resolver, plus a "Build a shop" quick prompt - new "Storefront" preset wired to the shopify-storefront example via Template.exampleId; setTemplate selects the example and locks its required add-ons - ecommerce category in FeaturePicker with an id-based override so the shopify add-on lands in the new bucket - AI recipe summary now includes featureOptions so generated prompts reflect customer-account selections - workspace useCliCommand mirrors buildCliCommand (--template, --add-on-config, dedupe example-locked add-ons) - applyStarterRecipe preserves featureOptions for example-locked add-ons - compile.ts passes intent: false (newly required by 0.66.0)
✅ Deploy Preview for tanstack ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThis PR adds e-commerce intent detection and a storefront template preset to the TanStack builder. It introduces category overrides to map Shopify features to an ecommerce category, updates builder state to support example templates with locked dependencies, enhances CLI generation to include template and feature-option configuration, and augments AI prompts with normalized feature-option metadata. ChangesE-commerce Feature Intent & Storefront
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/builder/useBuilderUrl.ts`:
- Around line 252-258: The add-on generation currently only excludes
example-locked dependencies (exampleLockedFeatures) but can still include the
selected example ID itself; update the calculation of addOnFeatures in
useBuilderUrl.ts so it also filters out the selectedExample ID (when present) in
addition to exampleLockedFeatures—i.e., ensure addOnFeatures = features.filter(f
=> !exampleLockedFeatures.has(f) && f !== selectedExample) so the selected
example won't appear both as --template and in --add-ons; keep references to
exampleLockedFeatures, selectedExample, availableExamples and addOnFeatures when
making the change.
In `@src/utils/application-starter.ts`:
- Around line 1278-1281: The advanced-builder and download URLs are losing
storefront-specific Shopify config (featureOptions and template) causing
mismatches with the displayed cliCommand which preserves them via
buildAddOnConfigArg; update buildAdvancedBuilderUrl and buildDownloadUrl to
accept and include recipe.featureOptions (and recipe.template for downloads) the
same way buildAddOnConfigArg is used when building cliCommand so the
advanced-builder link and download CTA produce the identical starter as the
command; locate and modify the buildAdvancedBuilderUrl and buildDownloadUrl
functions to accept featureOptions/template parameters and append those values
to their generated query/payload just like buildAddOnConfigArg does for
cliCommand.
- Around line 693-699: The ecommerce branch in applyInputOverrides (case
'ecommerce') sets recipe.featureOptions.shopify.customerAccount when
ecommerceCustomerAccountPatterns match, but applyInputOverrides is called after
this branch and may also enable the generic "better-auth" flow, producing both
shopify.customerAccount and better-auth simultaneously; modify the flow so that
when you set recipe.template = 'shopify-storefront' and enable
recipe.featureOptions.shopify.customerAccount you also suppress or remove
addition of the generic auth feature (the code path that enables
"better-auth")—for example add a flag or clear the generic auth option inside
the ecommerce case (referencing the ecommerce branch,
recipe.featureOptions.shopify, and the applyInputOverrides/better-auth logic) so
only the Shopify-specific customer account scaffold is produced.
- Around line 1231-1242: The current POSIX-only shellQuoteSingle and
buildAddOnConfigArg produce a command that breaks on Windows; update
buildAddOnConfigArg to produce platform-aware quoting by detecting Windows
(process.platform === 'win32') and using a Windows-friendly quoting strategy
(wrap the JSON string in double quotes and escape embedded double
quotes/backslashes for cmd.exe/PowerShell) while keeping the existing
single-quote POSIX escaping via shellQuoteSingle for non-Windows. Modify or add
a helper (e.g., shellQuoteWindows or platformQuote) and have buildAddOnConfigArg
call the appropriate function so the resulting --add-on-config value in the
cliCommand is valid for both Windows and POSIX shells.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a306f80f-5968-4ed1-bb03-bd7d89417dd1
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
package.jsonsrc/builder/api/compile.tssrc/builder/api/features.tssrc/builder/templates.tssrc/components/builder/FeaturePicker.tsxsrc/components/builder/store.tssrc/components/builder/useBuilderUrl.tssrc/utils/application-starter.server.tssrc/utils/application-starter.ts
| const exampleLockedFeatures = selectedExample | ||
| ? new Set( | ||
| availableExamples.find((e) => e.id === selectedExample)?.requires ?? [], | ||
| ) | ||
| : new Set<string>() | ||
| const addOnFeatures = features.filter((f) => !exampleLockedFeatures.has(f)) | ||
|
|
There was a problem hiding this comment.
Exclude the selected example ID from --add-ons generation.
Line 257 currently removes only example-locked dependencies. If features contains the example ID itself, the command can emit both --template and the same ID in --add-ons.
Suggested fix
- const addOnFeatures = features.filter((f) => !exampleLockedFeatures.has(f))
+ const addOnFeatures = features.filter(
+ (f) => f !== selectedExample && !exampleLockedFeatures.has(f),
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const exampleLockedFeatures = selectedExample | |
| ? new Set( | |
| availableExamples.find((e) => e.id === selectedExample)?.requires ?? [], | |
| ) | |
| : new Set<string>() | |
| const addOnFeatures = features.filter((f) => !exampleLockedFeatures.has(f)) | |
| const exampleLockedFeatures = selectedExample | |
| ? new Set( | |
| availableExamples.find((e) => e.id === selectedExample)?.requires ?? [], | |
| ) | |
| : new Set<string>() | |
| const addOnFeatures = features.filter( | |
| (f) => f !== selectedExample && !exampleLockedFeatures.has(f), | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/builder/useBuilderUrl.ts` around lines 252 - 258, The add-on
generation currently only excludes example-locked dependencies
(exampleLockedFeatures) but can still include the selected example ID itself;
update the calculation of addOnFeatures in useBuilderUrl.ts so it also filters
out the selectedExample ID (when present) in addition to
exampleLockedFeatures—i.e., ensure addOnFeatures = features.filter(f =>
!exampleLockedFeatures.has(f) && f !== selectedExample) so the selected example
won't appear both as --template and in --add-ons; keep references to
exampleLockedFeatures, selectedExample, availableExamples and addOnFeatures when
making the change.
| case 'ecommerce': { | ||
| recipe.template = 'shopify-storefront' | ||
| if ( | ||
| ecommerceCustomerAccountPatterns.some((pattern) => pattern.test(input)) | ||
| ) { | ||
| recipe.featureOptions.shopify = { customerAccount: 'enabled' } | ||
| } |
There was a problem hiding this comment.
Don't layer generic auth on top of Shopify customer accounts.
applyInputOverrides() still runs after this branch, so briefs like “Shopify storefront with customer login/sign in” will both enable shopify.customerAccount here and add better-auth later. That produces the wrong scaffold for the storefront flow.
Possible fix
function applyInputOverrides(input: string, recipe: ApplicationStarterRecipe) {
+ const hasShopifyCustomerAccount =
+ recipe.template === 'shopify-storefront' &&
+ recipe.featureOptions.shopify?.customerAccount === 'enabled'
+
if (hasNegativeFeatureConstraint(input, 'clerk')) {
recipe.features = recipe.features.filter((feature) => feature !== 'clerk')
} else if (/\bclerk\b/i.test(input)) {
replaceExclusive(recipe, ['better-auth', 'clerk', 'workos'], 'clerk')
@@
} else if (
+ !hasShopifyCustomerAccount &&
!hasAuthOverlapConstraint(input) &&
/\b(authentication|auth|login|sign ?in|sign ?up|oauth|sessions?)\b/i.test(
input,
)
) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/utils/application-starter.ts` around lines 693 - 699, The ecommerce
branch in applyInputOverrides (case 'ecommerce') sets
recipe.featureOptions.shopify.customerAccount when
ecommerceCustomerAccountPatterns match, but applyInputOverrides is called after
this branch and may also enable the generic "better-auth" flow, producing both
shopify.customerAccount and better-auth simultaneously; modify the flow so that
when you set recipe.template = 'shopify-storefront' and enable
recipe.featureOptions.shopify.customerAccount you also suppress or remove
addition of the generic auth feature (the code path that enables
"better-auth")—for example add a flag or clear the generic auth option inside
the ecommerce case (referencing the ecommerce branch,
recipe.featureOptions.shopify, and the applyInputOverrides/better-auth logic) so
only the Shopify-specific customer account scaffold is produced.
| function shellQuoteSingle(value: string): string { | ||
| return `'${value.replace(/'/g, `'\\''`)}'` | ||
| } | ||
|
|
||
| function buildAddOnConfigArg( | ||
| featureOptions: ApplicationStarterRecipe['featureOptions'], | ||
| ): string | null { | ||
| const entries = Object.entries(featureOptions).filter( | ||
| ([, options]) => options && Object.keys(options).length > 0, | ||
| ) | ||
| if (entries.length === 0) return null | ||
| return shellQuoteSingle(JSON.stringify(Object.fromEntries(entries))) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the full context of the application-starter.ts file
# to understand how cliCommand and buildAddOnConfigArg are used
cd src/utils && wc -l application-starter.tsRepository: TanStack/tanstack.com
Length of output: 93
🏁 Script executed:
# Search for cliCommand references in the file
rg "cliCommand" src/utils/application-starter.ts -n -B 2 -A 2Repository: TanStack/tanstack.com
Length of output: 1721
🏁 Script executed:
# Search for buildAddOnConfigArg usage
rg "buildAddOnConfigArg" src/utils/application-starter.ts -n -B 3 -A 3Repository: TanStack/tanstack.com
Length of output: 565
🏁 Script executed:
# Search for shellQuoteSingle usage
rg "shellQuoteSingle" src/ -n -B 2 -A 2Repository: TanStack/tanstack.com
Length of output: 667
🏁 Script executed:
# Check if there's any platform detection or shell-aware logic
rg "process\.platform|win32|cwd\.shell|shell.*win|powershell" src/utils/application-starter.ts -nRepository: TanStack/tanstack.com
Length of output: 47
🏁 Script executed:
# Find buildCliCommand function definition
rg "function buildCliCommand|const buildCliCommand|buildCliCommand.*=" src/utils/application-starter.ts -n -A 30Repository: TanStack/tanstack.com
Length of output: 1096
🏁 Script executed:
# Get more context around the command building
sed -n '1250,1290p' src/utils/application-starter.tsRepository: TanStack/tanstack.com
Length of output: 1125
🏁 Script executed:
# Check if there's any documentation or comments about shell support
rg "shell|windows|cmd|powershell|cross-platform" src/utils/application-starter.ts -i -n -B 1 -A 1Repository: TanStack/tanstack.com
Length of output: 308
🏁 Script executed:
# Check for any related issues or TODOs about Windows/shell compatibility
rg "TODO|FIXME|BUG|HACK" src/utils/application-starter.ts -n -B 2 -A 2Repository: TanStack/tanstack.com
Length of output: 47
🏁 Script executed:
# Check if there's any shell detection logic in the entire codebase
rg "process\.platform|win32|shell|powershell" src/ -i -t ts -t tsx -l | head -20Repository: TanStack/tanstack.com
Length of output: 93
🏁 Script executed:
# Look for any Windows-specific command handling
rg "windows|cmd\.exe|powershell" . -i -t ts -t tsx --max-count 10Repository: TanStack/tanstack.com
Length of output: 93
🏁 Script executed:
# Check the `@tanstack/cli` package to see if there's shell awareness there
fd "cli" . -t d -i | head -10Repository: TanStack/tanstack.com
Length of output: 92
🏁 Script executed:
# Check if there are any tests or examples showing this command in action
rg "add-on-config" . -t ts -t tsx -B 3 -A 3Repository: TanStack/tanstack.com
Length of output: 93
🏁 Script executed:
# Look at the entire buildCliCommand function with context
sed -n '1245,1283p' src/utils/application-starter.tsRepository: TanStack/tanstack.com
Length of output: 1123
🏁 Script executed:
# Check if there's any documentation about the command format
rg "npx.*@tanstack/cli" . -B 3 -A 3 --max-count 20Repository: TanStack/tanstack.com
Length of output: 2415
🏁 Script executed:
# Look for any Windows or cross-platform handling in related files
find src -name "*.ts" | xargs grep -l "shell\|windows\|cmd" 2>/dev/null | head -10Repository: TanStack/tanstack.com
Length of output: 215
🏁 Script executed:
# Check if the command is processed differently on different platforms
rg "commandParts\|buildCliCommand" src/ -B 2 -A 5 | head -50Repository: TanStack/tanstack.com
Length of output: 47
🏁 Script executed:
# Search for any GitHub issues or documentation about Windows support
find . -name "*.md" -o -name "*.txt" | xargs grep -l "windows\|cmd\|powershell" 2>/dev/null | head -10Repository: TanStack/tanstack.com
Length of output: 135
🏁 Script executed:
# Check the actual structure - does the command need shell parsing at runtime?
rg "exec\|spawn\|shell.*true" src/utils/application-starter.ts -nRepository: TanStack/tanstack.com
Length of output: 47
Use shell-aware quoting for the --add-on-config argument to support Windows users.
shellQuoteSingle() applies POSIX shell escaping ('\'\' syntax) which is correct for sh/bash but invalid in cmd.exe and PowerShell. Since cliCommand is a user-facing copy-paste string embedded in guidance text, Windows users will get a broken command without modification. The --add-on-config argument will not parse correctly unless the quoting is shell-aware or a platform-specific variant is provided.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/utils/application-starter.ts` around lines 1231 - 1242, The current
POSIX-only shellQuoteSingle and buildAddOnConfigArg produce a command that
breaks on Windows; update buildAddOnConfigArg to produce platform-aware quoting
by detecting Windows (process.platform === 'win32') and using a Windows-friendly
quoting strategy (wrap the JSON string in double quotes and escape embedded
double quotes/backslashes for cmd.exe/PowerShell) while keeping the existing
single-quote POSIX escaping via shellQuoteSingle for non-Windows. Modify or add
a helper (e.g., shellQuoteWindows or platformQuote) and have buildAddOnConfigArg
call the appropriate function so the resulting --add-on-config value in the
cliCommand is valid for both Windows and POSIX shells.
| const addOnConfig = buildAddOnConfigArg(recipe.featureOptions) | ||
| if (addOnConfig) { | ||
| commandParts.push('--add-on-config', addOnConfig) | ||
| } |
There was a problem hiding this comment.
Keep the builder/download outputs consistent with the new storefront recipe.
cliCommand now preserves Shopify config, but buildAdvancedBuilderUrl() still drops featureOptions, and buildDownloadUrl() drops both template and featureOptions. For storefront results, the advanced-builder link and download CTA can generate a different starter than the command shown here.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/utils/application-starter.ts` around lines 1278 - 1281, The
advanced-builder and download URLs are losing storefront-specific Shopify config
(featureOptions and template) causing mismatches with the displayed cliCommand
which preserves them via buildAddOnConfigArg; update buildAdvancedBuilderUrl and
buildDownloadUrl to accept and include recipe.featureOptions (and
recipe.template for downloads) the same way buildAddOnConfigArg is used when
building cliCommand so the advanced-builder link and download CTA produce the
identical starter as the command; locate and modify the buildAdvancedBuilderUrl
and buildDownloadUrl functions to accept featureOptions/template parameters and
append those values to their generated query/payload just like
buildAddOnConfigArg does for cliCommand.

Summary
@tanstack/createto^0.66.0to pick up the new shopify add-on andshopify-storefrontexample--templateand--add-on-configthrough both CLI command builders (the prompt-drivenbuildCliCommandand the workspace-drivenuseCliCommand) so storefront configurations round-trip correctlyecommerceintent (withcustomerAccountdetection), a "Build a shop" quick prompt, a "Storefront" preset wired to the example, anecommerceFeaturePicker category, and afeatureOptionsline in the AI recipe summary so generated prompts reflect customer-account selectionsTest plan
pnpm test(tsc + lint) passes/api/builder/featuresreturns the shopify add-on undercategory: "ecommerce"with thecustomerAccountoption, andshopify-storefrontinexamples/api/application-starter/resolvewith an ecommerce brief producescliCommand: npx @tanstack/cli@latest create … --template shopify-storefront --add-on-config '{"shopify":{"customerAccount":"enabled"}}'--add-ons …only (template allowlist holds)/builder?template=storefront&shopify.customerAccount=enabledrenders the same CLI flags live/builderSummary by CodeRabbit
New Features
Chores
@tanstack/createdependency from^0.63.4to^0.66.0