create-brainerce-store 1.58.0 → 1.61.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/dist/index.js CHANGED
@@ -31,7 +31,7 @@ var require_package = __commonJS({
31
31
  "package.json"(exports2, module2) {
32
32
  module2.exports = {
33
33
  name: "create-brainerce-store",
34
- version: "1.58.0",
34
+ version: "1.61.0",
35
35
  description: "Scaffold a production-ready e-commerce storefront connected to Brainerce",
36
36
  bin: {
37
37
  "create-brainerce-store": "dist/index.js"
@@ -43,6 +43,7 @@ var require_package = __commonJS({
43
43
  ],
44
44
  scripts: {
45
45
  build: "tsup",
46
+ "type-check": "tsc --noEmit",
46
47
  dev: "tsup --watch",
47
48
  clean: "rimraf dist",
48
49
  release: "pnpm build && node ../../scripts/publish-workspace-package.js .",
@@ -182,7 +183,11 @@ var BRAINERCE_RUNTIME_DEPS = Object.freeze({
182
183
  // SetCheckoutCustomerDto — the scaffolded checkout form types depend on it.
183
184
  // 1.46 adds getAddressSuggestions/getAddressDetails — the scaffolded
184
185
  // checkout form's address-autocomplete typeahead calls these directly.
185
- brainerce: "^1.46.0",
186
+ // 1.52 adds ShippingRate.speedTier — the scaffolded shipping step reads it to
187
+ // label live carrier rates, so an older SDK fails type-check at scaffold time
188
+ // — plus getBusinessHoursForDate(), which the scaffolded DATETIME checkout
189
+ // field uses to tell "day closed" from "field isn't slot-based".
190
+ brainerce: "^1.52.0",
186
191
  "isomorphic-dompurify": "^3.8.0"
187
192
  });
188
193
 
package/messages/en.json CHANGED
@@ -189,6 +189,9 @@
189
189
  "noShippingOptions": "No shipping options available for this address.",
190
190
  "noShippingOptionsHint": "Please try a different address or contact support.",
191
191
  "estimatedDelivery": "Estimated delivery:",
192
+ "shippingTierCheapest": "Standard delivery",
193
+ "shippingTierBalanced": "Express delivery",
194
+ "shippingTierFastest": "Priority delivery",
192
195
  "pickupLocation": "Pickup Location",
193
196
  "selectPickupLocation": "Select pickup location",
194
197
  "pickupLocationRequired": "Please select a pickup location",
@@ -245,6 +248,13 @@
245
248
  "customFieldsImageRemove": "Remove",
246
249
  "customFieldsImageUploading": "Uploading...",
247
250
  "customFieldsImageTooLarge": "File must be under 5MB",
251
+ "customFieldsDatePlaceholder": "Select a date",
252
+ "customFieldsDateToday": "Today",
253
+ "customFieldsDateClear": "Clear",
254
+ "customFieldsDatePrevMonth": "Previous month",
255
+ "customFieldsDateNextMonth": "Next month",
256
+ "customFieldsTimeLabel": "Time",
257
+ "customFieldsTimeClosed": "No delivery times are available on this date.",
248
258
  "changeOptions": "Change options",
249
259
  "surcharges": "Additional charges"
250
260
  },
@@ -335,6 +345,10 @@
335
345
  "goToRegister": "Go to Register",
336
346
  "authFailed": "Authentication failed",
337
347
  "authFailedDesc": "Missing authentication parameters. Please try again.",
348
+ "oauthErrorGeneric": "Sign-in could not be completed. Please try again.",
349
+ "oauthErrorCancelled": "Sign-in was cancelled.",
350
+ "oauthErrorExpired": "That sign-in attempt expired. Please try again.",
351
+ "oauthErrorVerifyEmailFirst": "This email address needs to be verified before you can sign in with a social account. Check your inbox for the verification email.",
338
352
  "backToLogin": "Back to Login",
339
353
  "completingSignIn": "Completing sign in...",
340
354
  "forgotPassword": "Forgot password?",
@@ -445,6 +459,14 @@
445
459
  "yourDownloads": "Your Downloads",
446
460
  "download": "Download"
447
461
  },
462
+ "orderStatus": {
463
+ "pageTitle": "Order Status",
464
+ "loading": "Loading your order...",
465
+ "errorTitle": "Order not found",
466
+ "notFound": "We couldn't find an order matching this link.",
467
+ "missingCheckoutInfo": "Missing order information.",
468
+ "returnHome": "Return Home"
469
+ },
448
470
  "reservation": {
449
471
  "expired": "Reservation expired. Items may no longer be available.",
450
472
  "hurry": "Hurry!",
package/messages/he.json CHANGED
@@ -189,6 +189,9 @@
189
189
  "noShippingOptions": "אין אפשרויות משלוח זמינות לכתובת זו.",
190
190
  "noShippingOptionsHint": "נסו כתובת אחרת או פנו לתמיכה.",
191
191
  "estimatedDelivery": "זמן משלוח משוער:",
192
+ "shippingTierCheapest": "משלוח רגיל",
193
+ "shippingTierBalanced": "משלוח מהיר",
194
+ "shippingTierFastest": "משלוח אקספרס",
192
195
  "pickupLocation": "נקודת איסוף",
193
196
  "selectPickupLocation": "בחרו נקודת איסוף",
194
197
  "pickupLocationRequired": "יש לבחור נקודת איסוף",
@@ -245,6 +248,13 @@
245
248
  "customFieldsImageRemove": "הסר",
246
249
  "customFieldsImageUploading": "...מעלה",
247
250
  "customFieldsImageTooLarge": "הקובץ חייב להיות מתחת ל-5MB",
251
+ "customFieldsDatePlaceholder": "בחרו תאריך",
252
+ "customFieldsDateToday": "היום",
253
+ "customFieldsDateClear": "נקה",
254
+ "customFieldsDatePrevMonth": "חודש קודם",
255
+ "customFieldsDateNextMonth": "חודש הבא",
256
+ "customFieldsTimeLabel": "שעה",
257
+ "customFieldsTimeClosed": "אין שעות משלוח זמינות בתאריך הזה.",
248
258
  "changeOptions": "שנה אפשרויות",
249
259
  "surcharges": "תוספות"
250
260
  },
@@ -335,6 +345,10 @@
335
345
  "goToRegister": "מעבר להרשמה",
336
346
  "authFailed": "ההתחברות נכשלה",
337
347
  "authFailedDesc": "חסרים פרמטרי התחברות. אנא נסו שוב.",
348
+ "oauthErrorGeneric": "לא הצלחנו להשלים את ההתחברות. אנא נסו שוב.",
349
+ "oauthErrorCancelled": "ההתחברות בוטלה.",
350
+ "oauthErrorExpired": "ניסיון ההתחברות פג. אנא נסו שוב.",
351
+ "oauthErrorVerifyEmailFirst": "יש לאמת את כתובת המייל הזו לפני התחברות עם חשבון חברתי. בדקו את תיבת הדואר שלכם עבור מייל האימות.",
338
352
  "backToLogin": "חזרה להתחברות",
339
353
  "completingSignIn": "משלים התחברות...",
340
354
  "forgotPassword": "שכחת סיסמא?",
@@ -445,6 +459,14 @@
445
459
  "yourDownloads": "ההורדות שלך",
446
460
  "download": "הורדה"
447
461
  },
462
+ "orderStatus": {
463
+ "pageTitle": "סטטוס הזמנה",
464
+ "loading": "טוען את ההזמנה שלך...",
465
+ "errorTitle": "ההזמנה לא נמצאה",
466
+ "notFound": "לא הצלחנו למצוא הזמנה שתואמת לקישור הזה.",
467
+ "missingCheckoutInfo": "חסר מידע הזמנה.",
468
+ "returnHome": "חזרה לדף הבית"
469
+ },
448
470
  "reservation": {
449
471
  "expired": "השריון פג. ייתכן שהמוצרים כבר לא זמינים.",
450
472
  "hurry": "מהרו!",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-brainerce-store",
3
- "version": "1.58.0",
3
+ "version": "1.61.0",
4
4
  "description": "Scaffold a production-ready e-commerce storefront connected to Brainerce",
5
5
  "bin": {
6
6
  "create-brainerce-store": "dist/index.js"
@@ -12,6 +12,7 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "build": "tsup",
15
+ "type-check": "tsc --noEmit",
15
16
  "dev": "tsup --watch",
16
17
  "clean": "rimraf dist",
17
18
  "release": "pnpm build && node ../../scripts/publish-workspace-package.js .",
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "brainerce-docs": {
4
+ "type": "http",
5
+ "url": "https://mcp-docs.brainerce.com/mcp"
6
+ }
7
+ }
8
+ }
@@ -1,65 +1,81 @@
1
- # AGENTS.md — this is a LIVE Brainerce storefront
2
-
3
- **Store: "<%- storeName %>" · sales channel `<%- connectionId %>` — already
4
- connected.** Products, cart, checkout, coupons, discounts, orders and content
5
- flow in real time from the Brainerce dashboard. There is nothing to hook up.
6
-
7
- - **NEVER suggest connecting this store to Shopify, WooCommerce, or "a real
8
- system"** — Brainerce IS the commerce backend, and this store is wired to
9
- it end-to-end.
10
- - **NEVER build standalone HTML mockups or demo pages** — design THIS Next.js
11
- app. Run `pnpm dev` and you are working against live data.
12
- - **NEVER hardcode products, prices, or currency** — the catalog is live.
13
- - **No server side is needed** — the backend is Brainerce's cloud. This repo
14
- is a frontend (plus thin, already-included API proxy routes under
15
- `src/app/api/`). Do not scaffold databases, auth servers, or admin panels —
16
- the merchant manages everything in the Brainerce dashboard.
17
-
18
- Platform docs (endpoints, SDK, integration recipes): https://brainerce.com/docs
19
- — AI-readable index: https://brainerce.com/llms.txt
20
-
21
- **Before building any feature the merchant asks for** (loyalty points,
22
- shipping zones, subscriptions, gift cards, multi-currency, reviews,
23
- abandoned-cart recovery, etc.) check the docs first. Brainerce likely
24
- already has it as a platform capability (dashboard toggle + hook/SDK
25
- method) that only needs a UI in `src/ui/`, not a feature built from scratch.
26
-
27
- Your job here is almost always **design**.
28
-
29
- ## The one rule
30
-
31
- **`src/core/` is the platform's. `src/ui/` is yours.**
32
-
33
- The shipped `src/ui/` is a working reference, not a design to preserve
34
- full delete-and-rebuild of ui files is encouraged and expected.
35
- Rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
36
- like — the store keeps working. Never modify `src/core/`, `src/app/api/`, or
37
- the checkout/auth/account components. Data and behavior come exclusively from
38
- `@/core/hooks/*` and `@/core/providers/store-provider` hooks return state
39
- and handlers, never JSX. Never hardcode catalog content.
40
-
41
- **Read `AI-GUIDE.md` before any redesign** it has the full file map, hook
42
- contracts, motion language, and hard-won RTL/i18n gotchas that will save you
43
- real debugging time.
44
-
45
- ## Redesigning?
46
-
47
- Follow the process documented in AI-GUIDE.md: commit to one art direction,
48
- rewrite tokens first, then surfaces in order (header, home, card, product
49
- page, cart), then verify.
50
-
51
- ## Verify before declaring done
52
-
53
- 1. `pnpm exec tsc --noEmit` 0 errors
54
- 2. `pnpm dev` drive the changed flow in a real browser (home → product →
55
- add to cart cart)
56
- 3. Screenshot desktop (1440px) and mobile (390px)
57
- 4. RTL stores: check anchoring and arrow directions
58
-
59
- ## i18n
60
-
61
- Every user-facing string goes through `useTranslations()` with keys in **all**
62
- files under `messages/`. The shipped copy is example boutique content — a
63
- starting point meant to be rewritten in the store's real voice. Hebrew: no
64
- uppercase transforms, no wide letter-spacing on headings, logical CSS
65
- properties only (`ms-/me-`, `ps-/pe-`, `start-/end-`).
1
+ # AGENTS.md — this is a LIVE Brainerce storefront
2
+
3
+ **Store: "<%- storeName %>" · sales channel `<%- connectionId %>` — already
4
+ connected.** Products, cart, checkout, coupons, discounts, orders and content
5
+ flow in real time from the Brainerce dashboard. There is nothing to hook up.
6
+
7
+ - **NEVER suggest connecting this store to Shopify, WooCommerce, or "a real
8
+ system"** — Brainerce IS the commerce backend, and this store is wired to
9
+ it end-to-end.
10
+ - **NEVER build standalone HTML mockups or demo pages** — design THIS Next.js
11
+ app. Run `pnpm dev` and you are working against live data.
12
+ - **NEVER hardcode products, prices, or currency** — the catalog is live.
13
+ - **No server side is needed** — the backend is Brainerce's cloud. This repo
14
+ is a frontend (plus thin, already-included API proxy routes under
15
+ `src/app/api/`). Do not scaffold databases, auth servers, or admin panels —
16
+ the merchant manages everything in the Brainerce dashboard.
17
+
18
+ Platform docs (endpoints, SDK, integration recipes): https://brainerce.com/docs
19
+ — AI-readable index: https://brainerce.com/llms.txt
20
+
21
+ ## MCP servers
22
+
23
+ - **`brainerce-docs`**already connected via `.mcp.json`, no auth needed.
24
+ A live SDK/docs oracle: current SDK method shapes, type definitions, code
25
+ examples, and this store's actual capabilities/config. Prefer it over
26
+ guessing or relying on training data — it reflects what's actually toggled
27
+ on for `<%- connectionId %>` right now.
28
+ - **Brainerce Admin MCP** — opt-in, not wired up by default. Lets an agent
29
+ directly manage this store's *live* data (products, orders, discounts,
30
+ shipping, …) instead of just reading docs. Only add it if the merchant
31
+ wants that: connect `https://api.brainerce.com/api/mcp` as a remote HTTP
32
+ MCP server (e.g. `claude mcp add --transport http brainerce-admin
33
+ https://api.brainerce.com/api/mcp`) it opens a browser to log into the
34
+ Brainerce dashboard, pick this store, and grant scoped OAuth permissions.
35
+ Treat it like handing the agent write access to production commerce data.
36
+
37
+ **Before building any feature the merchant asks for** (loyalty points,
38
+ shipping zones, subscriptions, gift cards, multi-currency, reviews,
39
+ abandoned-cart recovery, etc.) check the docs first. Brainerce likely
40
+ already has it as a platform capability (dashboard toggle + hook/SDK
41
+ method) that only needs a UI in `src/ui/`, not a feature built from scratch.
42
+
43
+ Your job here is almost always **design**.
44
+
45
+ ## The one rule
46
+
47
+ **`src/core/` is the platform's. `src/ui/` is yours.**
48
+
49
+ The shipped `src/ui/` is a working reference, not a design to preserve —
50
+ full delete-and-rebuild of ui files is encouraged and expected.
51
+ Rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
52
+ like — the store keeps working. Never modify `src/core/`, `src/app/api/`, or
53
+ the checkout/auth/account components. Data and behavior come exclusively from
54
+ `@/core/hooks/*` and `@/core/providers/store-provider` hooks return state
55
+ and handlers, never JSX. Never hardcode catalog content.
56
+
57
+ **Read `AI-GUIDE.md` before any redesign** it has the full file map, hook
58
+ contracts, motion language, and hard-won RTL/i18n gotchas that will save you
59
+ real debugging time.
60
+
61
+ ## Redesigning?
62
+
63
+ Follow the process documented in AI-GUIDE.md: commit to one art direction,
64
+ rewrite tokens first, then surfaces in order (header, home, card, product
65
+ page, cart), then verify.
66
+
67
+ ## Verify before declaring done
68
+
69
+ 1. `pnpm exec tsc --noEmit` → 0 errors
70
+ 2. `pnpm dev` → drive the changed flow in a real browser (home → product →
71
+ add to cart → cart)
72
+ 3. Screenshot desktop (1440px) and mobile (390px)
73
+ 4. RTL stores: check anchoring and arrow directions
74
+
75
+ ## i18n
76
+
77
+ Every user-facing string goes through `useTranslations()` with keys in **all**
78
+ files under `messages/`. The shipped copy is example boutique content — a
79
+ starting point meant to be rewritten in the store's real voice. Hebrew: no
80
+ uppercase transforms, no wide letter-spacing on headings, logical CSS
81
+ properties only (`ms-/me-`, `ps-/pe-`, `start-/end-`).
@@ -1,76 +1,92 @@
1
- # CLAUDE.md — this is a LIVE Brainerce storefront
2
-
3
- **Store: "<%- storeName %>" · sales channel `<%- connectionId %>` — already
4
- connected.** Products, cart, checkout, coupons, discounts, orders and content
5
- flow in real time from the Brainerce dashboard. There is nothing to hook up.
6
-
7
- - **NEVER suggest connecting this store to Shopify, WooCommerce, or "a real
8
- system"** — Brainerce IS the commerce backend, and this store is wired to
9
- it end-to-end.
10
- - **NEVER build standalone HTML mockups or demo pages** — design THIS Next.js
11
- app. Run `pnpm dev` and you are working against live data.
12
- - **NEVER hardcode products, prices, or currency** — the catalog is live.
13
- - **No server side is needed** — the backend is Brainerce's cloud. This repo
14
- is a frontend (plus thin, already-included API proxy routes under
15
- `src/app/api/`). Do not scaffold databases, auth servers, or admin panels —
16
- the merchant manages everything in the Brainerce dashboard.
17
-
18
- Platform docs (endpoints, SDK, integration recipes): https://brainerce.com/docs
19
- — AI-readable index: https://brainerce.com/llms.txt
20
-
21
- **Before building any feature the merchant asks for** (loyalty points,
22
- shipping zones, subscriptions, gift cards, multi-currency, reviews,
23
- abandoned-cart recovery, etc.) check the docs first. Brainerce likely
24
- already has it as a platform capability (dashboard toggle + hook/SDK
25
- method) that only needs a UI in `src/ui/`, not a feature built from scratch.
26
-
27
- Your job here is almost always **design**.
28
-
29
- ## The one rule
30
-
31
- **`src/core/` is the platform's. `src/ui/` is yours.**
32
-
33
- The shipped `src/ui/` is a working reference, not a design to preserve
34
- full delete-and-rebuild of ui files is encouraged and expected. (Stores
35
- scaffolded with `--canvas` ship `src/ui/` as bare unstyled skeletons
36
- there is no reference look at all; the design is entirely yours to create.)
37
- Rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
38
- like the store keeps working. Never modify `src/core/`, `src/app/api/`, or
39
- the checkout/auth/account components. Data and behavior come exclusively from
40
- `@/core/hooks/*` and `@/core/providers/store-provider` hooks return state
41
- and handlers, never JSX. Never hardcode catalog content.
42
-
43
- **Read `AI-GUIDE.md` before any redesign** it has the full file map, hook
44
- contracts, motion language, and hard-won RTL/i18n gotchas that will save you
45
- real debugging time.
46
-
47
- ## The dialect
48
-
49
- - `src/components/ui/` = official **shadcn/ui primitives** (Button, Card,
50
- Badge, Input, Select, Accordion, Dialog, Sheet, Skeleton, …). Compose them;
51
- extend looks via CVA **variants**, never repeated inline overrides.
52
- - Icons: **lucide-react only** no inline `<svg>`, no emoji-as-icons.
53
- - Class merging: **`cn()`** from `@/core/lib/utils`.
54
- - Colors/radius come from the semantic HSL tokens in `globals.css`
55
- (`--primary`, `--card`, `--ring`, `--radius`, …) restyle via tokens.
56
-
57
- ## Redesigning? Use the ready-made flow
58
-
59
- Run `/design <your art-direction brief>` — it walks the whole process:
60
- concept implementation in `ui/` verification.
61
-
62
- ## Verify before declaring done
63
-
64
- 1. `pnpm exec tsc --noEmit` → 0 errors
65
- 2. `pnpm dev` drive the changed flow in a real browser (home → product →
66
- add to cart cart)
67
- 3. Screenshot desktop (1440px) and mobile (390px)
68
- 4. RTL stores: check anchoring and arrow directions
69
-
70
- ## i18n
71
-
72
- Every user-facing string goes through `useTranslations()` with keys in **all**
73
- files under `messages/`. The shipped copy is example boutique content — a
74
- starting point meant to be rewritten in the store's real voice. Hebrew: no
75
- uppercase transforms, no wide letter-spacing on headings, logical CSS
76
- properties only (`ms-/me-`, `ps-/pe-`, `start-/end-`).
1
+ # CLAUDE.md — this is a LIVE Brainerce storefront
2
+
3
+ **Store: "<%- storeName %>" · sales channel `<%- connectionId %>` — already
4
+ connected.** Products, cart, checkout, coupons, discounts, orders and content
5
+ flow in real time from the Brainerce dashboard. There is nothing to hook up.
6
+
7
+ - **NEVER suggest connecting this store to Shopify, WooCommerce, or "a real
8
+ system"** — Brainerce IS the commerce backend, and this store is wired to
9
+ it end-to-end.
10
+ - **NEVER build standalone HTML mockups or demo pages** — design THIS Next.js
11
+ app. Run `pnpm dev` and you are working against live data.
12
+ - **NEVER hardcode products, prices, or currency** — the catalog is live.
13
+ - **No server side is needed** — the backend is Brainerce's cloud. This repo
14
+ is a frontend (plus thin, already-included API proxy routes under
15
+ `src/app/api/`). Do not scaffold databases, auth servers, or admin panels —
16
+ the merchant manages everything in the Brainerce dashboard.
17
+
18
+ Platform docs (endpoints, SDK, integration recipes): https://brainerce.com/docs
19
+ — AI-readable index: https://brainerce.com/llms.txt
20
+
21
+ ## MCP servers
22
+
23
+ - **`brainerce-docs`**already connected via `.mcp.json`, no auth needed.
24
+ A live SDK/docs oracle: current SDK method shapes, type definitions, code
25
+ examples, and this store's actual capabilities/config. Prefer it over
26
+ guessing or relying on training data — it reflects what's actually toggled
27
+ on for `<%- connectionId %>` right now.
28
+ - **Brainerce Admin MCP** — opt-in, not wired up by default. Lets an agent
29
+ directly manage this store's *live* data (products, orders, discounts,
30
+ shipping, …) instead of just reading docs. Only add it if the merchant
31
+ wants that: connect `https://api.brainerce.com/api/mcp` as a remote HTTP
32
+ MCP server (e.g. `claude mcp add --transport http brainerce-admin
33
+ https://api.brainerce.com/api/mcp`) it opens a browser to log into the
34
+ Brainerce dashboard, pick this store, and grant scoped OAuth permissions.
35
+ Treat it like handing the agent write access to production commerce data.
36
+
37
+ **Before building any feature the merchant asks for** (loyalty points,
38
+ shipping zones, subscriptions, gift cards, multi-currency, reviews,
39
+ abandoned-cart recovery, etc.) check the docs first. Brainerce likely
40
+ already has it as a platform capability (dashboard toggle + hook/SDK
41
+ method) that only needs a UI in `src/ui/`, not a feature built from scratch.
42
+
43
+ Your job here is almost always **design**.
44
+
45
+ ## The one rule
46
+
47
+ **`src/core/` is the platform's. `src/ui/` is yours.**
48
+
49
+ The shipped `src/ui/` is a working reference, not a design to preserve —
50
+ full delete-and-rebuild of ui files is encouraged and expected. (Stores
51
+ scaffolded with `--canvas` ship `src/ui/` as bare unstyled skeletons —
52
+ there is no reference look at all; the design is entirely yours to create.)
53
+ Rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
54
+ like the store keeps working. Never modify `src/core/`, `src/app/api/`, or
55
+ the checkout/auth/account components. Data and behavior come exclusively from
56
+ `@/core/hooks/*` and `@/core/providers/store-provider` — hooks return state
57
+ and handlers, never JSX. Never hardcode catalog content.
58
+
59
+ **Read `AI-GUIDE.md` before any redesign** — it has the full file map, hook
60
+ contracts, motion language, and hard-won RTL/i18n gotchas that will save you
61
+ real debugging time.
62
+
63
+ ## The dialect
64
+
65
+ - `src/components/ui/` = official **shadcn/ui primitives** (Button, Card,
66
+ Badge, Input, Select, Accordion, Dialog, Sheet, Skeleton, …). Compose them;
67
+ extend looks via CVA **variants**, never repeated inline overrides.
68
+ - Icons: **lucide-react only** no inline `<svg>`, no emoji-as-icons.
69
+ - Class merging: **`cn()`** from `@/core/lib/utils`.
70
+ - Colors/radius come from the semantic HSL tokens in `globals.css`
71
+ (`--primary`, `--card`, `--ring`, `--radius`, …) — restyle via tokens.
72
+
73
+ ## Redesigning? Use the ready-made flow
74
+
75
+ Run `/design <your art-direction brief>` it walks the whole process:
76
+ concept implementation in `ui/` → verification.
77
+
78
+ ## Verify before declaring done
79
+
80
+ 1. `pnpm exec tsc --noEmit` → 0 errors
81
+ 2. `pnpm dev` → drive the changed flow in a real browser (home → product →
82
+ add to cart → cart)
83
+ 3. Screenshot desktop (1440px) and mobile (390px)
84
+ 4. RTL stores: check anchoring and arrow directions
85
+
86
+ ## i18n
87
+
88
+ Every user-facing string goes through `useTranslations()` with keys in **all**
89
+ files under `messages/`. The shipped copy is example boutique content — a
90
+ starting point meant to be rewritten in the store's real voice. Hebrew: no
91
+ uppercase transforms, no wide letter-spacing on headings, logical CSS
92
+ properties only (`ms-/me-`, `ps-/pe-`, `start-/end-`).
@@ -13,8 +13,16 @@ function isSecure(): boolean {
13
13
  return process.env.NODE_ENV === 'production';
14
14
  }
15
15
 
16
- function errorRedirect(base: URL, message: string): NextResponse {
17
- base.searchParams.set('oauth_error', message);
16
+ /**
17
+ * Forward a failure to the client callback page as a stable snake_case code.
18
+ *
19
+ * The backend uses the RFC 6749 §4.1.2.1 shape (`oauth_error` = code,
20
+ * `error_description` = English developer detail), so codes are what the page
21
+ * switches on to pick localized copy. The description is deliberately NOT
22
+ * forwarded — it is not shopper-facing copy.
23
+ */
24
+ function errorRedirect(base: URL, code: string): NextResponse {
25
+ base.searchParams.set('oauth_error', code);
18
26
  const response = NextResponse.redirect(base);
19
27
  response.headers.set('Referrer-Policy', 'no-referrer');
20
28
  return response;
@@ -41,7 +49,7 @@ export async function GET(request: NextRequest) {
41
49
  }
42
50
 
43
51
  if (oauthSuccess !== 'true' || !authCode) {
44
- return errorRedirect(redirectUrl, 'Authentication failed');
52
+ return errorRedirect(redirectUrl, 'invalid_request');
45
53
  }
46
54
 
47
55
  // Exchange the one-time auth_code for the real JWT.
@@ -61,7 +69,7 @@ export async function GET(request: NextRequest) {
61
69
  token = data.token;
62
70
  } catch (err) {
63
71
  console.error('[oauth-callback] auth_code exchange failed:', err);
64
- return errorRedirect(redirectUrl, 'Authentication failed');
72
+ return errorRedirect(redirectUrl, 'server_error');
65
73
  }
66
74
 
67
75
  redirectUrl.searchParams.set('oauth_success', 'true');
@@ -7,6 +7,21 @@ import { useAuth } from '@/core/providers/store-provider';
7
7
  import { LoadingSpinner } from '@/ui/shared/loading-spinner';
8
8
  import { useTranslations } from '@/core/lib/translations';
9
9
 
10
+ /**
11
+ * `oauth_error` is a stable snake_case code, not a message — the backend sends
12
+ * the RFC 6749 §4.1.2.1 pair (`oauth_error` + an English `error_description`
13
+ * meant for developers). Map codes to translated copy here; anything unknown,
14
+ * including provider-specific codes, falls through to the generic message.
15
+ */
16
+ const OAUTH_ERROR_MESSAGE_KEYS: Record<string, string> = {
17
+ access_denied: 'oauthErrorCancelled',
18
+ invalid_request: 'oauthErrorExpired',
19
+ invalid_state: 'oauthErrorExpired',
20
+ state_already_used: 'oauthErrorExpired',
21
+ state_expired: 'oauthErrorExpired',
22
+ link_blocked_unverified_password_account: 'oauthErrorVerifyEmailFirst',
23
+ };
24
+
10
25
  function OAuthCallbackContent() {
11
26
  const router = useRouter();
12
27
  const searchParams = useSearchParams();
@@ -25,7 +40,7 @@ function OAuthCallbackContent() {
25
40
  processedRef.current = true;
26
41
 
27
42
  if (oauthError) {
28
- setError(oauthError);
43
+ setError(t(OAUTH_ERROR_MESSAGE_KEYS[oauthError] ?? 'oauthErrorGeneric'));
29
44
  return;
30
45
  }
31
46