@tanstack/create 0.64.0 → 0.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +81 -0
- package/dist/create-app.js +72 -16
- package/dist/file-helpers.js +14 -0
- package/dist/frameworks/react/add-ons/ai/info.json +1 -1
- package/dist/frameworks/react/add-ons/better-auth/info.json +1 -1
- package/dist/frameworks/react/add-ons/clerk/README.md +42 -1
- package/dist/frameworks/react/add-ons/clerk/assets/src/routes/demo/clerk.tsx +94 -11
- package/dist/frameworks/react/add-ons/clerk/info.json +1 -1
- package/dist/frameworks/react/add-ons/compiler/info.json +1 -1
- package/dist/frameworks/react/add-ons/convex/info.json +1 -1
- package/dist/frameworks/react/add-ons/drizzle/info.json +1 -1
- package/dist/frameworks/react/add-ons/mcp/info.json +1 -1
- package/dist/frameworks/react/add-ons/neon/info.json +1 -1
- package/dist/frameworks/react/add-ons/paraglide/info.json +1 -1
- package/dist/frameworks/react/add-ons/prisma/info.json +1 -1
- package/dist/frameworks/react/add-ons/shadcn/info.json +1 -1
- package/dist/frameworks/react/add-ons/shopify/README.md +86 -0
- package/dist/frameworks/react/add-ons/shopify/assets/_dot_env.local.append +19 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/account-nav.tsx.ejs +41 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/add-to-cart-button.tsx +48 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/cart-line-item.tsx +94 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/cart-summary.tsx +111 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/empty-state.tsx +29 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/money.tsx +11 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/product-card.tsx +74 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/product-grid.tsx +24 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/shop-image.tsx +57 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/shop.css +58 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/components/shop/variant-selector.tsx +79 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/hooks/use-cart.ts +276 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/hooks/use-customer.ts.ejs +22 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/integrations/shopify/header-cart.tsx +37 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/lib/shopify/customer-queries.ts.ejs +228 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/lib/shopify/format.ts +33 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/lib/shopify/queries.ts +684 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.addresses.tsx.ejs +67 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.callback.tsx.ejs +45 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.index.tsx.ejs +70 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.login.tsx.ejs +59 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.logout.tsx.ejs +16 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.orders.$id.tsx.ejs +126 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.orders.tsx.ejs +50 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.tsx.ejs +34 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.cart.tsx +45 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.collections.$handle.tsx +66 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.index.tsx +36 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.pages.$handle.tsx +39 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.policies.$handle.tsx +30 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.products.$handle.tsx +106 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.search.tsx +75 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/routes/shop.tsx +78 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/cart.functions.ts +207 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/catalog.functions.ts +244 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/cookies.ts +29 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/customer-client.ts.ejs +99 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/customer-cookies.ts.ejs +49 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/customer.functions.ts.ejs +168 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/env.ts +89 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/oauth.ts.ejs +301 -0
- package/dist/frameworks/react/add-ons/shopify/assets/src/server/shopify/storefront-client.ts +101 -0
- package/dist/frameworks/react/add-ons/shopify/info.json +104 -0
- package/dist/frameworks/react/add-ons/shopify/package.json +6 -0
- package/dist/frameworks/react/add-ons/shopify/small-logo.svg +1 -0
- package/dist/frameworks/react/add-ons/strapi/info.json +1 -1
- package/dist/frameworks/react/add-ons/t3env/info.json +1 -1
- package/dist/frameworks/react/add-ons/workos/info.json +1 -1
- package/dist/frameworks/react/examples/shopify-storefront/README.md +39 -0
- package/dist/frameworks/react/examples/shopify-storefront/assets/src/components/FeaturedCollections.tsx +43 -0
- package/dist/frameworks/react/examples/shopify-storefront/assets/src/components/ShopHero.tsx +39 -0
- package/dist/frameworks/react/examples/shopify-storefront/assets/src/routes/index.tsx +65 -0
- package/dist/frameworks/react/examples/shopify-storefront/info.json +18 -0
- package/dist/frameworks/react/examples/shopify-storefront/package.json +3 -0
- package/dist/frameworks/react/hosts/cloudflare/README.md +11 -0
- package/dist/frameworks/react/hosts/cloudflare/info.json +1 -1
- package/dist/frameworks/react/hosts/netlify/README.md +11 -0
- package/dist/frameworks/react/hosts/netlify/info.json +1 -1
- package/dist/frameworks/react/hosts/nitro/README.md +12 -0
- package/dist/frameworks/react/hosts/nitro/info.json +1 -1
- package/dist/frameworks/react/hosts/railway/README.md +10 -0
- package/dist/frameworks/react/hosts/railway/info.json +1 -1
- package/dist/frameworks/react/project/base/src/components/Header.tsx.ejs +34 -34
- package/dist/frameworks/solid/add-ons/better-auth/info.json +1 -1
- package/dist/frameworks/solid/add-ons/convex/info.json +1 -1
- package/dist/frameworks/solid/add-ons/solid-ui/info.json +1 -1
- package/dist/frameworks/solid/add-ons/strapi/info.json +1 -1
- package/dist/frameworks/solid/add-ons/t3env/info.json +1 -1
- package/dist/frameworks/solid/hosts/cloudflare/README.md +11 -0
- package/dist/frameworks/solid/hosts/cloudflare/info.json +1 -1
- package/dist/frameworks/solid/hosts/netlify/README.md +11 -0
- package/dist/frameworks/solid/hosts/netlify/info.json +1 -1
- package/dist/frameworks/solid/hosts/nitro/README.md +12 -0
- package/dist/frameworks/solid/hosts/nitro/info.json +1 -1
- package/dist/frameworks/solid/hosts/railway/README.md +10 -0
- package/dist/frameworks/solid/hosts/railway/info.json +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/intent.js +1 -1
- package/dist/types/file-helpers.d.ts +1 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/create-app.ts +86 -22
- package/src/file-helpers.ts +20 -0
- package/src/frameworks/react/add-ons/ai/info.json +1 -1
- package/src/frameworks/react/add-ons/better-auth/info.json +1 -1
- package/src/frameworks/react/add-ons/clerk/README.md +42 -1
- package/src/frameworks/react/add-ons/clerk/assets/src/routes/demo/clerk.tsx +94 -11
- package/src/frameworks/react/add-ons/clerk/info.json +1 -1
- package/src/frameworks/react/add-ons/compiler/info.json +1 -1
- package/src/frameworks/react/add-ons/convex/info.json +1 -1
- package/src/frameworks/react/add-ons/drizzle/info.json +1 -1
- package/src/frameworks/react/add-ons/mcp/info.json +1 -1
- package/src/frameworks/react/add-ons/neon/info.json +1 -1
- package/src/frameworks/react/add-ons/paraglide/info.json +1 -1
- package/src/frameworks/react/add-ons/prisma/info.json +1 -1
- package/src/frameworks/react/add-ons/shadcn/info.json +1 -1
- package/src/frameworks/react/add-ons/shopify/README.md +86 -0
- package/src/frameworks/react/add-ons/shopify/assets/_dot_env.local.append +19 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/account-nav.tsx.ejs +41 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/add-to-cart-button.tsx +48 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/cart-line-item.tsx +94 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/cart-summary.tsx +111 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/empty-state.tsx +29 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/money.tsx +11 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/product-card.tsx +74 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/product-grid.tsx +24 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/shop-image.tsx +57 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/shop.css +58 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/components/shop/variant-selector.tsx +79 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/hooks/use-cart.ts +276 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/hooks/use-customer.ts.ejs +22 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/integrations/shopify/header-cart.tsx +37 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/lib/shopify/customer-queries.ts.ejs +228 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/lib/shopify/format.ts +33 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/lib/shopify/queries.ts +684 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.addresses.tsx.ejs +67 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.callback.tsx.ejs +45 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.index.tsx.ejs +70 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.login.tsx.ejs +59 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.logout.tsx.ejs +16 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.orders.$id.tsx.ejs +126 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.orders.tsx.ejs +50 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.account.tsx.ejs +34 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.cart.tsx +45 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.collections.$handle.tsx +66 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.index.tsx +36 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.pages.$handle.tsx +39 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.policies.$handle.tsx +30 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.products.$handle.tsx +106 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.search.tsx +75 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/routes/shop.tsx +78 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/cart.functions.ts +207 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/catalog.functions.ts +244 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/cookies.ts +29 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/customer-client.ts.ejs +99 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/customer-cookies.ts.ejs +49 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/customer.functions.ts.ejs +168 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/env.ts +89 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/oauth.ts.ejs +301 -0
- package/src/frameworks/react/add-ons/shopify/assets/src/server/shopify/storefront-client.ts +101 -0
- package/src/frameworks/react/add-ons/shopify/info.json +104 -0
- package/src/frameworks/react/add-ons/shopify/package.json +6 -0
- package/src/frameworks/react/add-ons/shopify/small-logo.svg +1 -0
- package/src/frameworks/react/add-ons/strapi/info.json +1 -1
- package/src/frameworks/react/add-ons/t3env/info.json +1 -1
- package/src/frameworks/react/add-ons/workos/info.json +1 -1
- package/src/frameworks/react/examples/shopify-storefront/README.md +39 -0
- package/src/frameworks/react/examples/shopify-storefront/assets/src/components/FeaturedCollections.tsx +43 -0
- package/src/frameworks/react/examples/shopify-storefront/assets/src/components/ShopHero.tsx +39 -0
- package/src/frameworks/react/examples/shopify-storefront/assets/src/routes/index.tsx +65 -0
- package/src/frameworks/react/examples/shopify-storefront/info.json +18 -0
- package/src/frameworks/react/examples/shopify-storefront/package.json +3 -0
- package/src/frameworks/react/hosts/cloudflare/README.md +11 -0
- package/src/frameworks/react/hosts/cloudflare/info.json +1 -1
- package/src/frameworks/react/hosts/netlify/README.md +11 -0
- package/src/frameworks/react/hosts/netlify/info.json +1 -1
- package/src/frameworks/react/hosts/nitro/README.md +12 -0
- package/src/frameworks/react/hosts/nitro/info.json +1 -1
- package/src/frameworks/react/hosts/railway/README.md +10 -0
- package/src/frameworks/react/hosts/railway/info.json +1 -1
- package/src/frameworks/react/project/base/src/components/Header.tsx.ejs +34 -34
- package/src/frameworks/solid/add-ons/better-auth/info.json +1 -1
- package/src/frameworks/solid/add-ons/convex/info.json +1 -1
- package/src/frameworks/solid/add-ons/solid-ui/info.json +1 -1
- package/src/frameworks/solid/add-ons/strapi/info.json +1 -1
- package/src/frameworks/solid/add-ons/t3env/info.json +1 -1
- package/src/frameworks/solid/hosts/cloudflare/README.md +11 -0
- package/src/frameworks/solid/hosts/cloudflare/info.json +1 -1
- package/src/frameworks/solid/hosts/netlify/README.md +11 -0
- package/src/frameworks/solid/hosts/netlify/info.json +1 -1
- package/src/frameworks/solid/hosts/nitro/README.md +12 -0
- package/src/frameworks/solid/hosts/nitro/info.json +1 -1
- package/src/frameworks/solid/hosts/railway/README.md +10 -0
- package/src/frameworks/solid/hosts/railway/info.json +1 -1
- package/src/index.ts +1 -0
- package/src/integrations/intent.ts +1 -1
- package/tests/create-app.test.ts +95 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,86 @@
|
|
|
1
1
|
# @tanstack/create
|
|
2
2
|
|
|
3
|
+
## 0.66.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat(cli, create): add Shopify storefront add-on + storefront template ([`814d222`](https://github.com/TanStack/cli/commit/814d222ac04e839eabe56abce5dcbe66d751c5d8))
|
|
8
|
+
|
|
9
|
+
Headless Shopify support for TanStack Start apps, scaffold-ready and
|
|
10
|
+
runtime-portable. The pitch: prove that TanStack Start is a first-class
|
|
11
|
+
target for Shopify, not just Next.js Commerce or Hydrogen.
|
|
12
|
+
|
|
13
|
+
**`shopify` add-on** — additive. `tanstack add shopify` mounts `/shop/*`
|
|
14
|
+
routes alongside an existing app without touching the home page. Includes:
|
|
15
|
+
|
|
16
|
+
- Storefront API client (server-only fetch via `createServerFn`, public
|
|
17
|
+
token by default + optional private token for higher rate limits and
|
|
18
|
+
buyer-IP forwarding).
|
|
19
|
+
- Hand-written GraphQL queries with hydrogen-react types (type-only;
|
|
20
|
+
zero runtime weight).
|
|
21
|
+
- httpOnly cookie cart (`tanstack_cart_id`) + React Query single-key
|
|
22
|
+
cache + optimistic updates with module-level mutation counter to
|
|
23
|
+
batch invalidations during rapid clicks.
|
|
24
|
+
- Hydrogen-demo parity routes: shop landing, product detail (with
|
|
25
|
+
variants + availability), collections, cart, search, Shopify CMS
|
|
26
|
+
pages, policies.
|
|
27
|
+
- Hydrogen-stock UI components (ProductCard, VariantSelector,
|
|
28
|
+
AddToCartButton, CartLineItem, CartSummary, ShopImage with CDN
|
|
29
|
+
transforms, Money via Intl) themed with six CSS custom properties
|
|
30
|
+
for easy reskinning.
|
|
31
|
+
- Header cart-count badge via the `header-user` integration slot.
|
|
32
|
+
- Shopify-hosted checkout (redirect to `cart.checkoutUrl`).
|
|
33
|
+
- **Optional Customer Account API** behind a `customerAccount` select
|
|
34
|
+
option. Hand-rolled OAuth 2.1 PKCE with `.well-known` discovery
|
|
35
|
+
cached in module memory (no usable npm client exists yet),
|
|
36
|
+
HMAC-signed httpOnly session cookies (HS256), lazy token refresh,
|
|
37
|
+
account dashboard / orders / order detail / addresses routes — all
|
|
38
|
+
EJS-guarded so the files only emit when enabled.
|
|
39
|
+
|
|
40
|
+
**`shopify-storefront` template** — storefront-first.
|
|
41
|
+
`tanstack create my-shop --template shopify-storefront` cascades the
|
|
42
|
+
`shopify` add-on (which cascades `tanstack-query`) and replaces the
|
|
43
|
+
home route with a polished landing (hero + featured collections + best
|
|
44
|
+
sellers grid).
|
|
45
|
+
|
|
46
|
+
**Zero-config first run.** Defaults to Shopify's public Hydrogen demo
|
|
47
|
+
store (`hydrogen-preview.myshopify.com`) so the storefront renders
|
|
48
|
+
real products immediately. Override the four env vars in `.env.local`
|
|
49
|
+
(or your deploy target's dashboard) to point at your store. Demo
|
|
50
|
+
defaults are baked into source as fallbacks, so the experience doesn't
|
|
51
|
+
break when a runtime doesn't load `.env` files into `process.env`.
|
|
52
|
+
|
|
53
|
+
**Portable.** Cookie ops via `@tanstack/react-start/server`; crypto via
|
|
54
|
+
Web Crypto (`crypto.subtle`); generic `CDN-Cache-Control` for browse
|
|
55
|
+
(`s-maxage=300, stale-while-revalidate=600`) and `private, no-store`
|
|
56
|
+
for cart. Works on Node, Cloudflare Workers, Shopify Oxygen (just
|
|
57
|
+
Workers), Vercel, Netlify, Bun, Deno.
|
|
58
|
+
|
|
59
|
+
**Header layout fix.** While the cart-count badge is the new
|
|
60
|
+
right-aligned action, the base scaffold's `Header` was placing the
|
|
61
|
+
social icons left-of-center on `sm+`. Reordered the JSX so navigation
|
|
62
|
+
sits between the logo and the right-side actions in DOM order, with
|
|
63
|
+
one mobile-only `order-3` to keep `flex-wrap` putting nav on its own
|
|
64
|
+
row. Result: logo → nav → (auto-spaced) → cart/social/theme on every
|
|
65
|
+
breakpoint, and a more sensible reading order for screen readers.
|
|
66
|
+
|
|
67
|
+
## 0.65.0
|
|
68
|
+
|
|
69
|
+
### Minor Changes
|
|
70
|
+
|
|
71
|
+
- feat(cli, create): close the gap between `tanstack create` and shipping a real app ([#445](https://github.com/TanStack/cli/pull/445))
|
|
72
|
+
|
|
73
|
+
A bundle of UX improvements aimed at beginners (especially those coming from Next.js) and the AI agents they pair with:
|
|
74
|
+
|
|
75
|
+
- **Tailored post-creation next steps.** The scaffold completion message now lists the env vars you still need to fill in `.env.local`, links the docs for each shipping-critical integration you picked (auth, database, ORM, deployment), and surfaces the Intent-wired AGENTS.md / CLAUDE.md with concrete prompt examples.
|
|
76
|
+
- **Pre-creation review screen.** After interactive prompts, the CLI shows a categorized summary (auth, database, ORM, deploy, other) and asks for confirmation before writing files. Conflicting selections (two auth providers, two ORMs, etc.) are flagged in the same step.
|
|
77
|
+
- **`.env.example` generation.** A checked-in `.env.example` is now derived from the env-var schemas of selected add-ons, with descriptions and a `(required)` marker. Plays nicely with add-ons that ship their own `_dot_env.example.append`.
|
|
78
|
+
- **Better add-on descriptions.** Concept-first one-liners replace generic "Add X to your application." Reads like a menu instead of a list of brand names.
|
|
79
|
+
- **Deployment quickstarts.** Each `--deployment` host (Netlify, Cloudflare, Railway, Nitro) now contributes its own README section explaining the actual steps to ship — push, dashboard URL, env var sync.
|
|
80
|
+
- **Clerk demo route parity.** Clerk's scaffold now ships a proper sign-in flow (matching Better Auth's depth) using Clerk's prebuilt components, plus a richer README with route-protection patterns and a production checklist.
|
|
81
|
+
- **Intent install passes `--map`.** The auto-invoked `intent install` now writes explicit task→skill mappings into the agent config instead of relying on runtime discovery, so agents see directly which skill matches which task.
|
|
82
|
+
- **`tanstack clean-demos` command.** A new subcommand removes leftover `demo.*` and `example.*` files (and prunes empty `routes/demo`/`routes/example` directories) so a beginner can ship without the scaffold's training wheels.
|
|
83
|
+
|
|
3
84
|
## 0.64.0
|
|
4
85
|
|
|
5
86
|
### Minor Changes
|
package/dist/create-app.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, resolve } from 'node:path';
|
|
2
|
-
import { isBase64 } from './file-helpers.js';
|
|
2
|
+
import { isBase64, isDemoFilePath } from './file-helpers.js';
|
|
3
3
|
import { formatCommand } from './utils.js';
|
|
4
4
|
import { writeConfigFileToEnvironment } from './config-file.js';
|
|
5
5
|
import { getPackageManagerScriptCommand, packageManagerInstall, translateExecuteCommand, } from './package-manager.js';
|
|
@@ -10,20 +10,6 @@ import { installShadcnComponents } from './integrations/shadcn.js';
|
|
|
10
10
|
import { setupGit } from './integrations/git.js';
|
|
11
11
|
import { setupIntent } from './integrations/intent.js';
|
|
12
12
|
import { runSpecialSteps } from './special-steps/index.js';
|
|
13
|
-
function isDemoFilePath(path) {
|
|
14
|
-
if (!path)
|
|
15
|
-
return false;
|
|
16
|
-
const normalized = path.replace(/\\/g, '/');
|
|
17
|
-
if (normalized.includes('/routes/demo/') ||
|
|
18
|
-
normalized.includes('/routes/example/')) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
const filename = normalized.split('/').pop() || '';
|
|
22
|
-
return (filename.startsWith('demo.') ||
|
|
23
|
-
filename.startsWith('demo-') ||
|
|
24
|
-
filename.startsWith('example.') ||
|
|
25
|
-
filename.startsWith('example-'));
|
|
26
|
-
}
|
|
27
13
|
function stripExamplesFromOptions(options) {
|
|
28
14
|
if (options.includeExamples !== false) {
|
|
29
15
|
return options;
|
|
@@ -240,6 +226,74 @@ async function seedEnvValues(environment, options) {
|
|
|
240
226
|
}
|
|
241
227
|
await environment.writeFile(envLocalPath, envContents);
|
|
242
228
|
}
|
|
229
|
+
async function writeEnvExample(environment, options) {
|
|
230
|
+
const envExamplePath = resolve(options.targetDir, '.env.example');
|
|
231
|
+
const existing = environment.exists(envExamplePath)
|
|
232
|
+
? await environment.readFile(envExamplePath)
|
|
233
|
+
: '';
|
|
234
|
+
const declared = new Set();
|
|
235
|
+
for (const match of existing.matchAll(/^([A-Z_][A-Z0-9_]*)=/gm)) {
|
|
236
|
+
declared.add(match[1]);
|
|
237
|
+
}
|
|
238
|
+
const sections = [];
|
|
239
|
+
for (const addOn of options.chosenAddOns) {
|
|
240
|
+
const lines = [];
|
|
241
|
+
for (const envVar of addOn.envVars || []) {
|
|
242
|
+
if (declared.has(envVar.name))
|
|
243
|
+
continue;
|
|
244
|
+
declared.add(envVar.name);
|
|
245
|
+
if (envVar.description) {
|
|
246
|
+
const required = envVar.required ? ' (required)' : '';
|
|
247
|
+
lines.push(`# ${envVar.description}${required}`);
|
|
248
|
+
}
|
|
249
|
+
lines.push(`${envVar.name}=`);
|
|
250
|
+
}
|
|
251
|
+
if (lines.length > 0) {
|
|
252
|
+
sections.push(`# ${addOn.name}\n${lines.join('\n')}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (sections.length === 0)
|
|
256
|
+
return;
|
|
257
|
+
const additions = sections.join('\n\n');
|
|
258
|
+
const newContent = existing
|
|
259
|
+
? `${existing.trimEnd()}\n\n${additions}\n`
|
|
260
|
+
: `${additions}\n`;
|
|
261
|
+
await environment.writeFile(envExamplePath, newContent);
|
|
262
|
+
}
|
|
263
|
+
const SHIPPING_CATEGORIES = new Set(['auth', 'database', 'orm', 'deploy']);
|
|
264
|
+
function buildNextSteps(options) {
|
|
265
|
+
const collectedEnv = new Set(Object.keys(options.envVarValues || {}));
|
|
266
|
+
const listedEnvVars = new Set();
|
|
267
|
+
const envVarLines = [];
|
|
268
|
+
const docLines = [];
|
|
269
|
+
for (const addOn of options.chosenAddOns) {
|
|
270
|
+
if (addOn.link && addOn.category && SHIPPING_CATEGORIES.has(addOn.category)) {
|
|
271
|
+
docLines.push(` • ${addOn.name} (${addOn.category}) — ${addOn.link}`);
|
|
272
|
+
}
|
|
273
|
+
for (const envVar of addOn.envVars || []) {
|
|
274
|
+
if (listedEnvVars.has(envVar.name))
|
|
275
|
+
continue;
|
|
276
|
+
listedEnvVars.add(envVar.name);
|
|
277
|
+
const required = envVar.required ? ' (required)' : '';
|
|
278
|
+
const status = collectedEnv.has(envVar.name)
|
|
279
|
+
? ' — already set from your input'
|
|
280
|
+
: ' — needs a value';
|
|
281
|
+
const desc = envVar.description ? ` — ${envVar.description}` : '';
|
|
282
|
+
envVarLines.push(` • ${envVar.name}${required}${desc}${status}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const sections = [];
|
|
286
|
+
if (envVarLines.length > 0) {
|
|
287
|
+
sections.push(`Environment variables (review/fill in .env.local before deploying):\n${envVarLines.join('\n')}`);
|
|
288
|
+
}
|
|
289
|
+
if (docLines.length > 0) {
|
|
290
|
+
sections.push(`Docs for the integrations you picked:\n${docLines.join('\n')}`);
|
|
291
|
+
}
|
|
292
|
+
if (options.intent) {
|
|
293
|
+
sections.push(`Working with an AI agent? Your agent config (AGENTS.md / CLAUDE.md) was wired up by TanStack Intent\nwith explicit skill mappings for the libraries you installed. Try asking your agent:\n • "migrate this Next.js page to TanStack Start"\n • "add a protected /dashboard route"\n • "show me how to use TanStack Router search params"`);
|
|
294
|
+
}
|
|
295
|
+
return sections.length > 0 ? `\nNext steps:\n\n${sections.join('\n\n')}\n` : '';
|
|
296
|
+
}
|
|
243
297
|
function report(environment, options) {
|
|
244
298
|
const warnings = [];
|
|
245
299
|
for (const addOn of options.chosenAddOns) {
|
|
@@ -268,12 +322,13 @@ ${environment.getErrors().join('\n')}`;
|
|
|
268
322
|
? ''
|
|
269
323
|
: `% cd ${options.projectName}
|
|
270
324
|
`;
|
|
325
|
+
const nextSteps = buildNextSteps(options);
|
|
271
326
|
// Use the force luke! :)
|
|
272
327
|
environment.outro(`${locationMessage}
|
|
273
328
|
|
|
274
329
|
Use the following commands to start your app:
|
|
275
330
|
${cdInstruction}% ${formatCommand(getPackageManagerScriptCommand(options.packageManager, ['dev']))}
|
|
276
|
-
|
|
331
|
+
${nextSteps}
|
|
277
332
|
Please read the README.md file for information on testing, styling, adding routes, etc.${errorStatement}`);
|
|
278
333
|
}
|
|
279
334
|
export async function createApp(environment, options) {
|
|
@@ -281,6 +336,7 @@ export async function createApp(environment, options) {
|
|
|
281
336
|
environment.startRun();
|
|
282
337
|
await writeFiles(environment, effectiveOptions);
|
|
283
338
|
await seedEnvValues(environment, effectiveOptions);
|
|
339
|
+
await writeEnvExample(environment, effectiveOptions);
|
|
284
340
|
await runCommandsAndInstallDependencies(environment, effectiveOptions);
|
|
285
341
|
environment.finishRun();
|
|
286
342
|
report(environment, effectiveOptions);
|
package/dist/file-helpers.js
CHANGED
|
@@ -90,6 +90,20 @@ export function relativePath(from, to, stripExtension = false) {
|
|
|
90
90
|
export function isDirectory(path) {
|
|
91
91
|
return statSync(path).isDirectory();
|
|
92
92
|
}
|
|
93
|
+
export function isDemoFilePath(path) {
|
|
94
|
+
if (!path)
|
|
95
|
+
return false;
|
|
96
|
+
const normalized = path.replace(/\\/g, '/');
|
|
97
|
+
if (normalized.includes('/routes/demo/') ||
|
|
98
|
+
normalized.includes('/routes/example/')) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const filename = normalized.split('/').pop() || '';
|
|
102
|
+
return (filename.startsWith('demo.') ||
|
|
103
|
+
filename.startsWith('demo-') ||
|
|
104
|
+
filename.startsWith('example.') ||
|
|
105
|
+
filename.startsWith('example-'));
|
|
106
|
+
}
|
|
93
107
|
export function findFilesRecursively(path, files) {
|
|
94
108
|
const dirFiles = readdirSync(path);
|
|
95
109
|
for (const file of dirFiles) {
|
|
@@ -1,3 +1,44 @@
|
|
|
1
1
|
## Setting up Clerk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
1. Sign up at [clerk.com](https://clerk.com) and create an application
|
|
4
|
+
2. Copy the **Publishable Key** from the Clerk dashboard
|
|
5
|
+
3. Set it in your `.env.local`:
|
|
6
|
+
```bash
|
|
7
|
+
VITE_CLERK_PUBLISHABLE_KEY=pk_test_...
|
|
8
|
+
```
|
|
9
|
+
4. Visit the demo route at `/demo/clerk` once `npm run dev` is running
|
|
10
|
+
|
|
11
|
+
### What's wired up
|
|
12
|
+
|
|
13
|
+
- **`<ClerkProvider>`** at the app root (`src/integrations/clerk/provider.tsx`) handles auth context for the whole tree
|
|
14
|
+
- **`<SignInButton>` / `<UserButton>`** in the header swap based on auth state
|
|
15
|
+
- **`/demo/clerk`** shows Clerk's prebuilt sign-in UI and a signed-in greeting
|
|
16
|
+
|
|
17
|
+
### Protecting a route
|
|
18
|
+
|
|
19
|
+
Wrap any component in `<SignedIn>` / `<SignedOut>`:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { SignedIn, SignedOut, RedirectToSignIn } from '@clerk/clerk-react'
|
|
23
|
+
|
|
24
|
+
function ProtectedPage() {
|
|
25
|
+
return (
|
|
26
|
+
<>
|
|
27
|
+
<SignedIn>
|
|
28
|
+
<YourPageContent />
|
|
29
|
+
</SignedIn>
|
|
30
|
+
<SignedOut>
|
|
31
|
+
<RedirectToSignIn />
|
|
32
|
+
</SignedOut>
|
|
33
|
+
</>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For server-side checks (route loaders, server functions), see the Clerk docs on [`auth()`](https://clerk.com/docs/references/backend/auth).
|
|
39
|
+
|
|
40
|
+
### Production checklist
|
|
41
|
+
|
|
42
|
+
- Replace the test keys with **production keys** from a dedicated production Clerk instance
|
|
43
|
+
- Configure your production domain under **Domains** in the Clerk dashboard
|
|
44
|
+
- Set up social providers (Google, GitHub, etc.) under **User & Authentication → Social Connections**
|
|
@@ -1,20 +1,103 @@
|
|
|
1
1
|
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
SignIn,
|
|
4
|
+
SignedIn,
|
|
5
|
+
SignedOut,
|
|
6
|
+
useUser,
|
|
7
|
+
} from '@clerk/clerk-react'
|
|
3
8
|
|
|
4
9
|
export const Route = createFileRoute('/demo/clerk')({
|
|
5
|
-
component:
|
|
10
|
+
component: ClerkDemo,
|
|
6
11
|
})
|
|
7
12
|
|
|
8
|
-
function
|
|
9
|
-
|
|
13
|
+
function ClerkDemo() {
|
|
14
|
+
return (
|
|
15
|
+
<div className="flex justify-center py-10 px-4">
|
|
16
|
+
<div className="w-full max-w-md p-6 space-y-6">
|
|
17
|
+
<SignedOut>
|
|
18
|
+
<div className="space-y-1.5">
|
|
19
|
+
<h1 className="text-lg font-semibold leading-none tracking-tight">
|
|
20
|
+
Sign in to continue
|
|
21
|
+
</h1>
|
|
22
|
+
<p className="text-sm text-neutral-500 dark:text-neutral-400">
|
|
23
|
+
Clerk renders the sign-in UI, manages sessions, and handles social providers for you.
|
|
24
|
+
</p>
|
|
25
|
+
</div>
|
|
26
|
+
<div className="flex justify-center pt-2">
|
|
27
|
+
<SignIn routing="hash" />
|
|
28
|
+
</div>
|
|
29
|
+
<p className="text-xs text-center text-neutral-400 dark:text-neutral-500">
|
|
30
|
+
Built with{' '}
|
|
31
|
+
<a
|
|
32
|
+
href="https://clerk.com"
|
|
33
|
+
target="_blank"
|
|
34
|
+
rel="noopener noreferrer"
|
|
35
|
+
className="font-medium hover:text-neutral-600 dark:hover:text-neutral-300"
|
|
36
|
+
>
|
|
37
|
+
CLERK
|
|
38
|
+
</a>
|
|
39
|
+
.
|
|
40
|
+
</p>
|
|
41
|
+
</SignedOut>
|
|
10
42
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
43
|
+
<SignedIn>
|
|
44
|
+
<SignedInGreeting />
|
|
45
|
+
</SignedIn>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function SignedInGreeting() {
|
|
52
|
+
const { user } = useUser()
|
|
53
|
+
if (!user) return null
|
|
54
|
+
|
|
55
|
+
const email = user.primaryEmailAddress?.emailAddress
|
|
56
|
+
const initial = (user.firstName || email || 'U').charAt(0).toUpperCase()
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div className="space-y-6">
|
|
60
|
+
<div className="space-y-1.5">
|
|
61
|
+
<h1 className="text-lg font-semibold leading-none tracking-tight">
|
|
62
|
+
Welcome back
|
|
63
|
+
</h1>
|
|
64
|
+
<p className="text-sm text-neutral-500 dark:text-neutral-400">
|
|
65
|
+
You're signed in as {email}
|
|
66
|
+
</p>
|
|
67
|
+
</div>
|
|
14
68
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
69
|
+
<div className="flex items-center gap-3">
|
|
70
|
+
{user.imageUrl ? (
|
|
71
|
+
<img src={user.imageUrl} alt="" className="h-10 w-10 rounded-full" />
|
|
72
|
+
) : (
|
|
73
|
+
<div className="h-10 w-10 bg-neutral-200 dark:bg-neutral-800 flex items-center justify-center rounded-full">
|
|
74
|
+
<span className="text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
|
75
|
+
{initial}
|
|
76
|
+
</span>
|
|
77
|
+
</div>
|
|
78
|
+
)}
|
|
79
|
+
<div className="flex-1 min-w-0">
|
|
80
|
+
<p className="text-sm font-medium truncate">
|
|
81
|
+
{user.firstName} {user.lastName}
|
|
82
|
+
</p>
|
|
83
|
+
<p className="text-xs text-neutral-500 dark:text-neutral-400 truncate">
|
|
84
|
+
{email}
|
|
85
|
+
</p>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
18
88
|
|
|
19
|
-
|
|
89
|
+
<p className="text-xs text-center text-neutral-400 dark:text-neutral-500">
|
|
90
|
+
Manage your account from the avatar in the header. Built with{' '}
|
|
91
|
+
<a
|
|
92
|
+
href="https://clerk.com"
|
|
93
|
+
target="_blank"
|
|
94
|
+
rel="noopener noreferrer"
|
|
95
|
+
className="font-medium hover:text-neutral-600 dark:hover:text-neutral-300"
|
|
96
|
+
>
|
|
97
|
+
CLERK
|
|
98
|
+
</a>
|
|
99
|
+
.
|
|
100
|
+
</p>
|
|
101
|
+
</div>
|
|
102
|
+
)
|
|
20
103
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Compiler",
|
|
3
3
|
"phase": "setup",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Auto-memoize components and hooks (fewer re-renders, no manual useMemo/useCallback).",
|
|
5
5
|
"link": "https://react.dev/learn/react-compiler",
|
|
6
6
|
"modes": ["code-router", "file-router"],
|
|
7
7
|
"type": "add-on",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "MCP",
|
|
3
3
|
"phase": "setup",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Expose your app as an MCP server so AI clients (Claude, Cursor) can call into it.",
|
|
5
5
|
"link": "https://mcp.dev",
|
|
6
6
|
"modes": ["file-router"],
|
|
7
7
|
"type": "add-on",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Prisma",
|
|
3
|
-
"description": "
|
|
3
|
+
"description": "Type-safe database client with schema migrations (Postgres, MySQL, SQLite, MongoDB).",
|
|
4
4
|
"phase": "add-on",
|
|
5
5
|
"type": "add-on",
|
|
6
6
|
"category": "orm",
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Shopify
|
|
2
|
+
|
|
3
|
+
Headless Shopify storefront for TanStack Start. Mounts `/shop/*` routes
|
|
4
|
+
alongside your existing app — your home page stays untouched.
|
|
5
|
+
|
|
6
|
+
The default `.env.local` points at Shopify's public Hydrogen demo store, so the
|
|
7
|
+
storefront renders real products on first run with zero setup.
|
|
8
|
+
|
|
9
|
+
## Routes
|
|
10
|
+
|
|
11
|
+
| Route | What it does |
|
|
12
|
+
|--------------------------------|---------------------------------------------|
|
|
13
|
+
| `/shop` | Shop landing — featured products + collections |
|
|
14
|
+
| `/shop/products/$handle` | Product detail (variants, images, options) |
|
|
15
|
+
| `/shop/collections/$handle` | Collection grid with sort + pagination |
|
|
16
|
+
| `/shop/cart` | Cart line items, discount codes, checkout |
|
|
17
|
+
| `/shop/search` | Product search |
|
|
18
|
+
| `/shop/pages/$handle` | Shopify CMS pages (about, etc.) |
|
|
19
|
+
| `/shop/policies/$handle` | Privacy, refund, terms, shipping |
|
|
20
|
+
|
|
21
|
+
If you opted into customer accounts during scaffold:
|
|
22
|
+
|
|
23
|
+
| Route | What it does |
|
|
24
|
+
|--------------------------------------|------------------------------------|
|
|
25
|
+
| `/shop/account/login` | Kick off Shopify OAuth |
|
|
26
|
+
| `/shop/account/callback` | OAuth callback handler |
|
|
27
|
+
| `/shop/account/logout` | End the customer session |
|
|
28
|
+
| `/shop/account` | Dashboard |
|
|
29
|
+
| `/shop/account/orders` | Order history |
|
|
30
|
+
| `/shop/account/orders/$id` | Order detail |
|
|
31
|
+
| `/shop/account/addresses` | Manage saved addresses |
|
|
32
|
+
|
|
33
|
+
## Connect your store
|
|
34
|
+
|
|
35
|
+
1. In Shopify admin, go to **Settings > Apps and sales channels > Develop apps**.
|
|
36
|
+
2. Create a new app, enable the **Storefront API**, and copy the public access token.
|
|
37
|
+
3. Set in `.env.local`:
|
|
38
|
+
```
|
|
39
|
+
SHOPIFY_STORE_DOMAIN=your-store.myshopify.com
|
|
40
|
+
SHOPIFY_PUBLIC_STOREFRONT_TOKEN=...
|
|
41
|
+
```
|
|
42
|
+
4. (Optional) For higher rate limits + buyer-IP forwarding, also create a private
|
|
43
|
+
token and set `SHOPIFY_PRIVATE_STOREFRONT_TOKEN`.
|
|
44
|
+
|
|
45
|
+
## Enable customer accounts
|
|
46
|
+
|
|
47
|
+
If `customerAccount=enabled` was selected during scaffold:
|
|
48
|
+
|
|
49
|
+
1. In Shopify admin, go to **Settings > Customer accounts > Headless**.
|
|
50
|
+
2. Register a public client. Add `http://localhost:3000/shop/account/callback`
|
|
51
|
+
*and* your production callback URL to the redirect URIs.
|
|
52
|
+
3. Copy the Client ID and Shop ID into `.env.local`:
|
|
53
|
+
```
|
|
54
|
+
SHOPIFY_CUSTOMER_ACCOUNT_CLIENT_ID=...
|
|
55
|
+
SHOPIFY_CUSTOMER_ACCOUNT_SHOP_ID=...
|
|
56
|
+
SHOPIFY_SESSION_SECRET=$(openssl rand -hex 32)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The Hydrogen demo store doesn't have customer accounts configured, so the
|
|
60
|
+
default demo creds won't work for `/shop/account/*` — you'll need a real store.
|
|
61
|
+
|
|
62
|
+
## Architecture
|
|
63
|
+
|
|
64
|
+
- **Storefront API client** — server-only fetch in `src/server/shopify/storefront-client.ts`.
|
|
65
|
+
All product/cart reads go through the server (private token never reaches the browser).
|
|
66
|
+
- **Cart state** — Cart ID stored in an httpOnly cookie (`tanstack_cart_id`). React
|
|
67
|
+
Query owns the cache (single key `['shopify', 'cart']`); optimistic updates with
|
|
68
|
+
a module-level mutation counter to batch invalidations.
|
|
69
|
+
- **GraphQL queries** — hand-written strings in `src/lib/shopify/queries.ts`, types
|
|
70
|
+
sliced from `@shopify/hydrogen-react/storefront-api-types` (type-only import; zero runtime).
|
|
71
|
+
- **Customer accounts** — hand-rolled OAuth 2.1 PKCE with `.well-known` discovery
|
|
72
|
+
(no usable npm client exists yet). Tokens in a signed httpOnly cookie.
|
|
73
|
+
- **Checkout** — redirects to `cart.checkoutUrl` (Shopify-hosted).
|
|
74
|
+
|
|
75
|
+
## Deployment
|
|
76
|
+
|
|
77
|
+
Works anywhere TanStack Start runs:
|
|
78
|
+
|
|
79
|
+
- **Node** — `npm run build && npm start`
|
|
80
|
+
- **Cloudflare Workers / Shopify Oxygen** — Oxygen is just Workers under the hood;
|
|
81
|
+
build with the Workers preset and deploy to either platform.
|
|
82
|
+
- **Vercel / Netlify** — set the env vars in the dashboard.
|
|
83
|
+
- **Bun, Deno** — supported via Start's adapters.
|
|
84
|
+
|
|
85
|
+
For the customer-account flow, register both your local *and* production
|
|
86
|
+
callback URLs in the Shopify admin's headless app config.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# ─── Shopify ─────────────────────────────────────────────────────────────────
|
|
2
|
+
# These defaults point to Shopify's public Hydrogen demo store so the storefront
|
|
3
|
+
# works on first run with zero config. Replace with your store's values to go live.
|
|
4
|
+
# Get tokens at: Shopify admin > Settings > Apps and sales channels > Develop apps.
|
|
5
|
+
SHOPIFY_STORE_DOMAIN=hydrogen-preview.myshopify.com
|
|
6
|
+
SHOPIFY_STOREFRONT_API_VERSION=2026-01
|
|
7
|
+
SHOPIFY_PUBLIC_STOREFRONT_TOKEN=3b580e70970c4528da70c98e097c2fa0
|
|
8
|
+
# Optional — set to a private storefront token for higher rate limits + buyer-IP forwarding.
|
|
9
|
+
SHOPIFY_PRIVATE_STOREFRONT_TOKEN=
|
|
10
|
+
|
|
11
|
+
# ─── Shopify Customer Account API ────────────────────────────────────────────
|
|
12
|
+
# Required only if you opted into customer accounts during scaffold.
|
|
13
|
+
# Register a public client in Shopify admin > Settings > Customer accounts > Headless,
|
|
14
|
+
# then paste the client ID and your numeric shop ID below.
|
|
15
|
+
SHOPIFY_CUSTOMER_ACCOUNT_CLIENT_ID=
|
|
16
|
+
SHOPIFY_CUSTOMER_ACCOUNT_SHOP_ID=
|
|
17
|
+
SHOPIFY_CUSTOMER_ACCOUNT_REDIRECT_URI=http://localhost:3000/shop/account/callback
|
|
18
|
+
# 32+ random chars, e.g. `openssl rand -hex 32`. Used to sign customer session cookies.
|
|
19
|
+
SHOPIFY_SESSION_SECRET=
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<% if (addOnOption.shopify.customerAccount !== 'enabled') { ignoreFile(); return; } %>
|
|
2
|
+
import { Link } from '@tanstack/react-router'
|
|
3
|
+
|
|
4
|
+
const ITEMS = [
|
|
5
|
+
{ to: '/shop/account', label: 'Overview', exact: true },
|
|
6
|
+
{ to: '/shop/account/orders', label: 'Orders', exact: false },
|
|
7
|
+
{ to: '/shop/account/addresses', label: 'Addresses', exact: false },
|
|
8
|
+
] as const
|
|
9
|
+
|
|
10
|
+
export function AccountNav() {
|
|
11
|
+
return (
|
|
12
|
+
<nav className="flex flex-col gap-1 text-sm">
|
|
13
|
+
{ITEMS.map((item) => (
|
|
14
|
+
<Link
|
|
15
|
+
key={item.to}
|
|
16
|
+
to={item.to}
|
|
17
|
+
activeOptions={{ exact: item.exact }}
|
|
18
|
+
className="rounded-md px-2 py-1.5 text-[var(--storefront-fg-muted)] hover:bg-[var(--storefront-line)]/40 hover:text-[var(--storefront-fg)]"
|
|
19
|
+
activeProps={{
|
|
20
|
+
className:
|
|
21
|
+
'rounded-md px-2 py-1.5 bg-[var(--storefront-line)]/60 text-[var(--storefront-fg)] font-medium',
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
{item.label}
|
|
25
|
+
</Link>
|
|
26
|
+
))}
|
|
27
|
+
<form
|
|
28
|
+
action="/shop/account/logout"
|
|
29
|
+
method="post"
|
|
30
|
+
className="mt-4 border-t border-[var(--storefront-line)] pt-4"
|
|
31
|
+
>
|
|
32
|
+
<button
|
|
33
|
+
type="submit"
|
|
34
|
+
className="rounded-md px-2 py-1.5 text-left text-sm text-[var(--storefront-fg-muted)] hover:text-[var(--storefront-fg)]"
|
|
35
|
+
>
|
|
36
|
+
Sign out
|
|
37
|
+
</button>
|
|
38
|
+
</form>
|
|
39
|
+
</nav>
|
|
40
|
+
)
|
|
41
|
+
}
|