@thorprovider/adapters 4.2.0 → 4.2.2

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.
Files changed (48) hide show
  1. package/.turbo/turbo-build.log +18 -18
  2. package/.turbo/turbo-test.log +1 -0
  3. package/.turbo/turbo-type-check.log +0 -0
  4. package/AGENTS.md +1 -1
  5. package/CHANGELOG.md +12 -0
  6. package/PROVIDER_IMPLEMENTATION_ANALYSIS.md +659 -0
  7. package/README.md +22 -3
  8. package/dist/.tsbuildinfo +1 -1
  9. package/dist/index.d.mts +140 -2
  10. package/dist/index.d.ts +140 -2
  11. package/dist/index.js +1075 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +1070 -0
  14. package/dist/index.mjs.map +1 -1
  15. package/docs/RETRY_SOLUTION_SUMMARY.md +26 -11
  16. package/docs/authentication.md +89 -62
  17. package/docs/capabilities-system.md +100 -38
  18. package/docs/category-customization.md +37 -29
  19. package/docs/fetch-reliability-solution.md +127 -278
  20. package/docs/getting-started.md +43 -29
  21. package/docs/profile-management.md +68 -38
  22. package/docs/providers-overview.md +14 -0
  23. package/docs/services-overview.md +20 -2
  24. package/docs/update-documentation.md +10 -8
  25. package/package.json +11 -6
  26. package/publish.log +93 -0
  27. package/quick-reference.md +1 -0
  28. package/src/factory/index.ts +4 -0
  29. package/src/index.ts +7 -0
  30. package/src/providers/index.ts +3 -0
  31. package/src/providers/medusa/admin.test.ts +404 -0
  32. package/src/providers/medusa/admin.ts +442 -0
  33. package/src/providers/medusa/auth.test.ts +95 -0
  34. package/src/providers/medusa/index.test.ts +392 -0
  35. package/src/providers/medusa/live-smoke.test.ts +412 -0
  36. package/src/providers/stelorder/client.test-helpers.ts +3 -0
  37. package/src/providers/stelorder/client.test.ts +58 -0
  38. package/src/providers/stelorder/client.ts +326 -0
  39. package/src/providers/stelorder/index.test.ts +48 -0
  40. package/src/providers/stelorder/index.ts +685 -0
  41. package/src/providers/stelorder/live-smoke.test.ts +54 -0
  42. package/src/providers/stelorder/transforms.test.ts +103 -0
  43. package/src/providers/stelorder/transforms.ts +631 -0
  44. package/src/resilience/README.md +70 -48
  45. package/src/types/capabilities.types.ts +51 -0
  46. package/vitest.config.ts +13 -0
  47. package/vitest.live.config.ts +18 -0
  48. package/vitest.setup.ts +6 -0
@@ -1,13 +1,24 @@
1
- # Resumen Ejecutivo - Solución a Errores de Fetch
1
+ ---
2
+ title: Retry Solution Summary
3
+ purpose: Executive summary of the fetch retry and circuit breaker resilience solution
4
+ type: reference
5
+ tags: [resilience, retry, fetch, summary]
6
+ related:
7
+ - fetch-reliability-solution.md
8
+ updated: 2026-05-03
9
+ ---
10
+
11
+ # Resumen Ejecutivo — Solución a Errores de Fetch
2
12
 
3
13
  ## ❌ Problema
4
14
  Errores frecuentes `Failed to fetch products: fetch failed` en el V0 starter al cargar productos desde el backend de Medusa.
5
15
 
6
16
  ## ✅ Solución Implementada
7
17
 
8
- ### 1. Nuevo Módulo de Retry Logic (`fetch-utils.ts`)
18
+ ### 1. Módulo de Retry Logic (`fetch-utils.ts`)
9
19
  - **Ubicación**: `packages/adapters/src/core/fetch-utils.ts`
10
- - **Funcionalidad**:
20
+ - **Importación**: utilidad interna — no está re-exportada desde `@thorprovider/adapters`. Úsala dentro del paquete como `import { fetchWithRetry } from '../core/fetch-utils'`.
21
+ - **Funcionalidad**:
11
22
  - Reintentos automáticos con exponential backoff
12
23
  - Timeout configurable (10s por defecto)
13
24
  - Detección inteligente de errores retryables
@@ -17,10 +28,14 @@ Errores frecuentes `Failed to fetch products: fetch failed` en el V0 starter al
17
28
  - **Ubicación**: `packages/adapters/src/providers/medusa/index.ts`
18
29
  - **Cambios**:
19
30
  - Nueva propiedad `retry?: RetryConfig` en `MedusaProviderConfig`
20
- - Método privado `withRetry()` que envuelve todas las llamadas al SDK
21
- - Métodos `getProduct()` y `getProducts()` actualizados para usar retry logic
31
+ - Custom fetch inyectado en el constructor del SDK
32
+
33
+ ### 3. Circuit Breaker (implementado)
34
+ - **Ubicación**: `packages/adapters/src/resilience/`
35
+ - **Estado**: ✅ Implementado y exportado desde `@thorprovider/adapters`
36
+ - **Uso**: `import { CircuitBreaker, backendCircuitBreaker } from '@thorprovider/adapters'`
22
37
 
23
- ### 3. Configuración por Defecto en V0 Starter
38
+ ### 4. Configuración por Defecto en V0 Starter
24
39
  - **Ubicación**: `packages/core/lib/commerce.ts`
25
40
  - **Configuración**:
26
41
  ```typescript
@@ -33,7 +48,7 @@ Errores frecuentes `Failed to fetch products: fetch failed` en el V0 starter al
33
48
  }
34
49
  ```
35
50
 
36
- ## 📊 Impacto Esperado
51
+ ## 📊 Impacto
37
52
  - **90-98% reducción** en errores visibles al usuario
38
53
  - Resiliencia ante problemas de red transitorios
39
54
  - Mejor experiencia de usuario sin interrupciones
@@ -41,15 +56,15 @@ Errores frecuentes `Failed to fetch products: fetch failed` en el V0 starter al
41
56
  ## 🧪 Estado
42
57
  - ✅ Código compila sin errores TypeScript
43
58
  - ✅ Build de adapters exitoso
44
- - ✅ Build de elements exitoso
45
- - ✅ Documentación completa creada
46
- - 🔄 Pendiente: Testing en dev/staging
59
+ - ✅ Tests unitarios con vitest (`yarn workspace @thorprovider/adapters test`)
60
+ - ✅ Circuit Breaker implementado
61
+ - 🔄 Pendiente: Validación en staging con métricas reales
47
62
 
48
63
  ## 📝 Documentación Completa
49
64
  Ver [fetch-reliability-solution.md](./fetch-reliability-solution.md) para análisis detallado de causas, soluciones, y configuraciones avanzadas.
50
65
 
51
66
  ## 🚀 Next Steps
52
- 1. Probar en desarrollo: `yarn dev:showcase` o `yarn workspace @thorprovider/core dev`
67
+ 1. Probar en desarrollo: `yarn workspace @thorprovider/core dev`
53
68
  2. Verificar logs en consola mostrando reintentos
54
69
  3. Confirmar reducción de errores en producción
55
70
  4. (Opcional) Ajustar configuración de retry según métricas reales
@@ -1,54 +1,61 @@
1
- # Authentication
2
-
3
1
  ---
2
+ title: Authentication
3
+ purpose: Guide for setting up and using customer authentication with Thor adapters
4
4
  type: how-to
5
5
  tags: [auth, security, login, jwt, session, registration]
6
6
  related:
7
7
  - profile-management.md
8
8
  - services-overview.md
9
9
  - getting-started.md
10
- updated: 2026-02-28
10
+ updated: 2026-05-03
11
11
  ---
12
12
 
13
+ # Authentication
14
+
13
15
  Complete guide to setting up and using authentication with Thor adapters.
14
16
 
17
+ > ⚠️ **Backend Disparity:** Authentication is only available on providers that expose an `auth` object. Check `commerce.auth` before calling any auth method. Stel Order and Mock providers do not support customer authentication.
18
+
15
19
  ## Prerequisites
16
20
 
17
- - [Thor Adapters installed](getting-started.md#installation)
21
+ - [Thor Adapters installed](getting-started.md)
18
22
  - A Medusa.js v2 backend configured with authentication providers
19
23
 
20
24
  ## Quick Example
21
25
 
22
26
  ```typescript
23
- import { commerce } from '@/lib/commerce';
27
+ import { createProvider } from '@thorprovider/adapters';
28
+
29
+ const commerce = createProvider({
30
+ provider: 'medusa',
31
+ config: {
32
+ baseUrl: process.env.NEXT_PUBLIC_COMMERCE_API_URL!,
33
+ publishableKey: process.env.NEXT_PUBLIC_COMMERCE_API_KEY!,
34
+ },
35
+ });
36
+
37
+ if (!commerce.auth) throw new Error('Auth not available for this provider');
24
38
 
25
- // Simple login
39
+ // Login
26
40
  const { customer } = await commerce.auth.login({
27
41
  email: 'user@example.com',
28
42
  password: 'SecurePassword123!',
29
43
  });
30
44
 
31
- console.log(`Welcome back, ${customer.first_name}!`);
45
+ console.log(`Welcome back, ${customer?.first_name}!`);
32
46
  ```
33
47
 
34
48
  ## Step-by-Step Instructions
35
49
 
36
- ### Step 1: Configure Auth Method
50
+ ### Step 1: Check Auth Availability
37
51
 
38
- Choose between JWT (SPAs) or Session (SSR) in your provider configuration.
52
+ Not all providers support authentication. Always guard before calling auth methods.
39
53
 
40
54
  ```typescript
41
- // lib/commerce.ts
42
- export const commerce = createProvider({
43
- provider: 'medusa',
44
- config: {
45
- // ... basic config
46
- auth: {
47
- method: 'jwt', // Recommended for SPAs
48
- storage: 'localStorage', // Where to persist tokens
49
- },
50
- },
51
- });
55
+ if (!commerce.auth) {
56
+ // Provider does not support customer auth (e.g. StelOrder, Mock)
57
+ return;
58
+ }
52
59
  ```
53
60
 
54
61
  ### Step 2: Handle Registration
@@ -66,69 +73,89 @@ const { customer } = await commerce.auth.register({
66
73
 
67
74
  ### Step 3: Implement Login Flow
68
75
 
69
- Create a login handler in your UI components.
70
-
71
76
  ```typescript
72
- async function handleLogin(credentials) {
77
+ async function handleLogin(credentials: { email: string; password: string }) {
78
+ if (!commerce.auth) throw new Error('Auth not supported');
79
+
73
80
  try {
74
- await commerce.auth.login(credentials);
75
- // Redirect on success
81
+ const { customer } = await commerce.auth.login(credentials);
82
+ return customer;
76
83
  } catch (error) {
77
- // Handle AuthError
84
+ // Handle CommerceError / invalid credentials
85
+ throw error;
78
86
  }
79
87
  }
80
88
  ```
81
89
 
82
90
  ### Step 4: Check Auth State
83
91
 
84
- Protect routes or update UI based on authentication status.
85
-
86
92
  ```typescript
87
93
  const isAuth = await commerce.auth.isAuthenticated();
88
94
  const customer = await commerce.auth.getCurrentCustomer();
89
95
  ```
90
96
 
91
- ## ✅ DO's
97
+ ### Step 5: Logout
92
98
 
93
- 1. **Use JWT for Headless SPAs:** It's more flexible and works better across different origins.
94
- 2. **Use Session for SSR:** If you use Next.js Server Components, Session cookies are more secure.
95
- 3. **Handle AuthErrors specifically:** Use `instanceof AuthError` to show user-friendly messages.
96
- 4. **Enable Auto-refresh:** Keep `autoRefresh: true` (default) to ensure seamless user sessions.
97
- 5. **Clear local state on logout:** Always call `commerce.auth.logout()` to clear stored tokens.
99
+ ```typescript
100
+ await commerce.auth.logout();
101
+ ```
98
102
 
99
- ## ❌ DONT's
103
+ ## Password Management
100
104
 
101
- 1. **Don't store sensitive data in customer object:** Only use public profile fields.
102
- 2. **Don't handle JWT tokens manually:** Let the adapter manage storage and refresh headers.
103
- 3. **Don't use Secret Keys in the browser:** Authentication should only use Publishable Keys.
104
- 4. **Don't ignore the `isAuthenticated` check:** Verify auth status before performing protected operations.
105
- 5. **Don't hardcode login URLs:** The adapter knows where to send requests based on the provider.
105
+ ### Request Password Reset
106
+
107
+ ```typescript
108
+ await commerce.auth.requestPasswordReset('user@example.com');
109
+ // Backend sends reset email
110
+ ```
106
111
 
107
- ## Common Patterns
112
+ ### Confirm Password Reset
108
113
 
109
- ### Protected Route Hook (React)
110
114
  ```typescript
111
- function useRequireAuth() {
112
- const { customer, loading } = useAuth(); // custom hook
113
- const router = useRouter();
114
-
115
- useEffect(() => {
116
- if (!loading && !customer) router.push('/login');
117
- }, [customer, loading]);
118
-
119
- return { customer, loading };
120
- }
115
+ await commerce.auth.resetPassword(tokenFromEmail, 'NewPassword123!');
121
116
  ```
122
117
 
123
- ### Server-Side Auth Check (Next.js)
118
+ ## Address Management
119
+
120
+ Auth providers also expose address operations:
121
+
124
122
  ```typescript
125
- export async function getServerSideProps() {
126
- const customer = await commerce.auth.getCurrentCustomer();
127
- if (!customer) return { redirect: { destination: '/login' } };
128
- return { props: { customer } };
129
- }
123
+ // List addresses
124
+ const addresses = await commerce.auth.getAddresses();
125
+
126
+ // Create address
127
+ const address = await commerce.auth.createAddress({
128
+ firstName: 'Jane',
129
+ lastName: 'Doe',
130
+ address1: '123 Main St',
131
+ city: 'Madrid',
132
+ postalCode: '28001',
133
+ countryCode: 'ES',
134
+ });
135
+
136
+ // Update address
137
+ await commerce.auth.updateAddress(address.id, { city: 'Barcelona' });
138
+
139
+ // Delete address
140
+ await commerce.auth.deleteAddress(address.id);
130
141
  ```
131
142
 
143
+ ## ✅ DO's
144
+
145
+ 1. **Guard with `commerce.auth`:** Always check the property exists before calling auth methods.
146
+ 2. **Use JWT for headless SPAs:** More flexible and works better across different origins.
147
+ 3. **Use Session for SSR:** Cookie-based sessions are more secure in server-rendered contexts.
148
+ 4. **Handle errors specifically:** Catch and surface meaningful messages to the user.
149
+ 5. **Clear state on logout:** Always call `commerce.auth.logout()` to clear stored tokens.
150
+
151
+ ## ❌ DONT's
152
+
153
+ 1. **Don't store sensitive data in the customer object:** Only use public profile fields.
154
+ 2. **Don't handle JWT tokens manually:** Let the adapter manage storage and refresh headers.
155
+ 3. **Don't use Secret Keys in the browser:** Authentication should only use Publishable Keys.
156
+ 4. **Don't ignore the `isAuthenticated` check:** Verify auth status before protected operations.
157
+ 5. **Don't import React or Next.js in adapter code:** Keep adapters framework-agnostic.
158
+
132
159
  ## Common Errors & Solutions
133
160
 
134
161
  ### Error: `AUTH_FAILED`
@@ -148,15 +175,15 @@ export async function getServerSideProps() {
148
175
  > ⚠️ **Pitfall 1: CORS issues with Session cookies**
149
176
  > Session-based auth requires matching domains or properly configured `cross-site` cookies in the backend.
150
177
 
151
- > ⚠️ **Pitfall 2: LocalStorage availability in SSR**
152
- > Ensure token management logic checks for `window` availability if using `localStorage`.
178
+ > ⚠️ **Pitfall 2: `commerce.auth` is undefined**
179
+ > Not all providers implement auth. Always check `if (commerce.auth)` before calling any method.
153
180
 
154
181
  ## Troubleshooting
155
182
 
156
183
  | Issue | Solution |
157
184
  |-------|----------|
158
- | Token not sent in headers | Check if `auth.method` matches backend expectation |
159
- | Login works but profile fails | Verify `storage` type is correctly configured and working |
185
+ | Token not sent in headers | Verify the provider config and that `publishableKey` is set |
186
+ | Login works but profile fails | Ensure `commerce.auth.getCurrentCustomer()` is called after login |
160
187
  | Infinite login loop | Check cookie path and domain settings on the backend |
161
188
 
162
189
  ## Next Steps
@@ -1,14 +1,16 @@
1
- # Capabilities System
2
-
3
1
  ---
2
+ title: Capabilities System
3
+ purpose: Reference for backend capability detection and matrices
4
4
  type: reference
5
5
  tags: [architecture, capabilities, backend, detection]
6
6
  related:
7
7
  - providers-overview.md
8
8
  - services-overview.md
9
- updated: 2026-02-28
9
+ updated: 2026-05-23
10
10
  ---
11
11
 
12
+ # Capabilities System
13
+
12
14
  The capabilities system exposes which operations each backend provider supports, enabling adaptive UIs across platforms.
13
15
 
14
16
  ## Quick Reference
@@ -35,27 +37,52 @@ if (commerce.capabilities.updateEmail) {
35
37
  | `changePasswordViaEmail` | `boolean` | Supports `requestPasswordReset` method. |
36
38
  | `deleteAccount` | `boolean` | Supports `deleteAccount` method. |
37
39
  | `uploadAvatar` | `boolean` | Supports native file upload for avatars. |
40
+ | `avatarViaMetadata` | `boolean` | Can store avatar URL in customer metadata/attributes. |
41
+ | `customAttributes` | `boolean` | Supports custom customer attributes/metadata. |
42
+
43
+ ### Order Management
44
+
45
+ | Capability | Type | Description |
46
+ |------------|------|-------------|
47
+ | `fetchOrders` | `boolean` | Can fetch customer order history. |
48
+ | `cancelOrder` | `boolean` | Can cancel orders before fulfillment. |
49
+
50
+ ### Address Management
51
+
52
+ | Capability | Type | Description |
53
+ |------------|------|-------------|
54
+ | `manageAddresses` | `boolean` | Can add/update/delete shipping addresses. |
55
+ | `defaultAddress` | `boolean` | Can set a default shipping address. |
56
+
57
+ ### Cart & Checkout
38
58
 
39
- ### Cart Operations
59
+ | Capability | Type | Description |
60
+ |------------|------|-------------|
61
+ | `applyDiscounts` | `boolean` | Can apply discount codes to cart. |
62
+ | `shippingCalculation` | `boolean` | Can calculate shipping rates before checkout. |
63
+ | `guestCheckout` | `boolean` | Supports checkout without an account. |
64
+ | `savedPaymentMethods` | `boolean` | Can save payment methods for future use. |
65
+ | `listPaymentProviders` | `boolean` | Can list available payment providers dynamically. |
66
+ | `regionSpecificPayments` | `boolean` | Payment providers vary by region. |
67
+
68
+ ### Discovery & Search
40
69
 
41
70
  | Capability | Type | Description |
42
71
  |------------|------|-------------|
43
- | `cartPromoCode` | `boolean` | Can apply discount/promo codes to cart. |
44
- | `cartGiftCards` | `boolean` | Supports gift card application. |
45
- | `cartNotes` | `boolean` | Supports order/cart notes. |
46
- | `cartCustomAttributes` | `boolean` | Supports metadata/attributes at cart level. |
72
+ | `advancedSearch` | `boolean` | Supports full-text / filtered product search. |
73
+ | `facetedFilters` | `boolean` | Supports faceted filtering by attributes. |
47
74
 
48
- ### Product & Discovery
75
+ ### Social & Loyalty
49
76
 
50
77
  | Capability | Type | Description |
51
78
  |------------|------|-------------|
52
- | `productVariants` | `boolean` | Backend supports multiple variants per product. |
53
- | `productCategories` | `boolean` | Supports nested categories or collections. |
54
- | `productInventory` | `boolean` | Real-time inventory tracking available. |
55
- | `productDigital` | `boolean` | Supports digital/downloadable products. |
56
- | `productReviews` | `boolean` | Native review system support. |
79
+ | `productReviews` | `boolean` | Native product reviews/ratings system. |
80
+ | `wishlist` | `boolean` | Native wishlist/favorites feature. |
81
+ | `loyaltyProgram` | `boolean` | Native loyalty/rewards program. |
82
+
83
+ ## Type Definition (source of truth)
57
84
 
58
- ## Type Definitions
85
+ > Canonical source: `packages/types/src/commerce-provider.ts` — `BackendCapabilities`
59
86
 
60
87
  ```typescript
61
88
  export interface BackendCapabilities {
@@ -66,28 +93,33 @@ export interface BackendCapabilities {
66
93
  changePasswordViaEmail: boolean;
67
94
  deleteAccount: boolean;
68
95
  uploadAvatar: boolean;
69
-
70
- // Avatar Extensions
71
96
  avatarViaMetadata: boolean;
72
-
73
- // Cart
74
- cartPromoCode: boolean;
75
- cartGiftCards: boolean;
76
- cartNotes: boolean;
77
- cartCustomAttributes: boolean;
78
-
79
- // Products
80
- productVariants: boolean;
81
- productCategories: boolean;
82
- productInventory: boolean;
83
- productDigital: boolean;
97
+ customAttributes: boolean;
98
+
99
+ // Orders
100
+ fetchOrders: boolean;
101
+ cancelOrder: boolean;
102
+
103
+ // Addresses
104
+ manageAddresses: boolean;
105
+ defaultAddress: boolean;
106
+
107
+ // Cart / Checkout
108
+ applyDiscounts: boolean;
109
+ shippingCalculation: boolean;
110
+ guestCheckout: boolean;
111
+ savedPaymentMethods: boolean;
112
+ listPaymentProviders: boolean;
113
+ regionSpecificPayments: boolean;
114
+
115
+ // Discovery
116
+ advancedSearch: boolean;
117
+ facetedFilters: boolean;
118
+
119
+ // Social / Loyalty
84
120
  productReviews: boolean;
85
-
86
- // Auth Integration
87
- authJWT: boolean;
88
- authSession: boolean;
89
- authOAuth: boolean;
90
- authPasswordless: boolean;
121
+ wishlist: boolean;
122
+ loyaltyProgram: boolean;
91
123
  }
92
124
  ```
93
125
 
@@ -109,15 +141,15 @@ return (
109
141
  async function handleAvatarUpdate(file: File) {
110
142
  if (caps.uploadAvatar) {
111
143
  return await commerce.auth.uploadAvatar(file);
112
- }
113
-
144
+ }
145
+
114
146
  if (caps.avatarViaMetadata) {
115
147
  const url = await externalUpload(file);
116
148
  return await commerce.auth.updateCustomer({
117
149
  metadata: { avatar_url: url }
118
150
  });
119
151
  }
120
-
152
+
121
153
  throw new Error('Avatar updates not supported on this backend');
122
154
  }
123
155
  ```
@@ -141,3 +173,33 @@ Capabilities are calculated once during provider initialization. Accessing `comm
141
173
 
142
174
  - [Providers Overview](providers-overview.md)
143
175
  - [Services Overview](services-overview.md)
176
+
177
+ ## Per-Provider Capability Matrix
178
+
179
+ ### Stel Order (ERP Adapter)
180
+
181
+ | Capability | Value | Notes |
182
+ |------------|-------|-------|
183
+ | `fetchOrders` | ✅ true | Read sales orders via `/salesOrders` |
184
+ | `listPaymentProviders` | ✅ true | List STEL payment options via `/paymentOptions` |
185
+ | `manageAddresses` | ✅ true | Via client main-address (PUT /clients) |
186
+ | `updateProfile` | ❌ false | No customer self-service (ERP admin only) |
187
+ | `updateEmail` | ❌ false | — |
188
+ | `changePasswordDirect` | ❌ false | No auth system |
189
+ | `changePasswordViaEmail` | ❌ false | No auth system |
190
+ | `deleteAccount` | ❌ false | — |
191
+ | `uploadAvatar` | ❌ false | — |
192
+ | `avatarViaMetadata` | ❌ false | — |
193
+ | `customAttributes` | ❌ false | — |
194
+ | `cancelOrder` | ❌ false | ERP orders are read-only from adapter |
195
+ | `defaultAddress` | ❌ false | — |
196
+ | `applyDiscounts` | ❌ false | No cart/checkout |
197
+ | `shippingCalculation` | ❌ false | No cart/checkout |
198
+ | `guestCheckout` | ❌ false | No cart/checkout |
199
+ | `savedPaymentMethods` | ❌ false | — |
200
+ | `regionSpecificPayments` | ❌ false | Single-company ERP |
201
+ | `wishlist` | ❌ false | — |
202
+ | `advancedSearch` | ❌ false | Client-side text filter only |
203
+ | `facetedFilters` | ❌ false | — |
204
+ | `productReviews` | ❌ false | — |
205
+ | `loyaltyProgram` | ❌ false | — |
@@ -1,3 +1,15 @@
1
+ ---
2
+ title: Category Customization & Inheritance
3
+ purpose: Explains the 5-phase system for hiding, renaming, and adding custom categories on top of backend-provided ones
4
+ type: guide
5
+ tags: [categories, customization, metadata, multi-tenant, architecture]
6
+ related:
7
+ - providers-overview.md
8
+ - services-overview.md
9
+ - multi-tenant-channel-scoping.md
10
+ updated: 2026-05-03
11
+ ---
12
+
1
13
  # Category Customization & Inheritance
2
14
 
3
15
  ## The Problem (Simple Version)
@@ -58,7 +70,7 @@ Your store sells **only shoes**. But the backend (Medusa) gives you 10 categorie
58
70
  "hidden": ["sandalias"],
59
71
  "renamed": { "accesorios": "Extras" },
60
72
  "custom": [
61
- { "id": "bestsellers", "name": "Bestsellers", ... }
73
+ { "id": "bestsellers", "name": "Bestsellers" }
62
74
  ]
63
75
  }
64
76
  }
@@ -74,7 +86,9 @@ What is a customization?
74
86
  → { hidden: ["id1", "id2"], renamed: {id: "newname"}, custom: [{...}] }
75
87
  ```
76
88
 
77
- We define this **once** in `@thorprovider/types` so every layer speaks the same language.
89
+ Defined once in `@thorprovider/types` so every layer speaks the same language.
90
+
91
+ > ⚠️ **Implementation status**: Category customization types are planned but not yet merged into `@thorprovider/types`. This document describes the intended architecture.
78
92
 
79
93
  ---
80
94
 
@@ -87,12 +101,12 @@ BackendMetadataAdapter
87
101
  Your customizations
88
102
  ```
89
103
 
90
- **Key principle**: We use the backend's native **metadata storage**, not a separate database.
104
+ **Key principle**: Uses the backend's native **metadata storage**, not a separate database.
91
105
 
92
106
  Why?
93
107
  - **Simple**: No external SQLite/Supabase
94
108
  - **Multi-tenant ready**: Each sales channel has its own metadata
95
- - **Agnóstic**: Medusa, Shopify, WordPress — same interface
109
+ - **Agnostic**: Medusa, Shopify, WordPress — same interface
96
110
 
97
111
  ---
98
112
 
@@ -114,6 +128,8 @@ Output:
114
128
 
115
129
  **Why L2?** This is business logic (not UI, not type definition). It belongs with the adapter.
116
130
 
131
+ > ⚠️ **Implementation status**: `mergeCategories()` service is planned. Not yet implemented in `packages/adapters/src/`.
132
+
117
133
  ---
118
134
 
119
135
  ### Phase 4: Expose via API (L5 — Route Handler)
@@ -123,13 +139,12 @@ GET /api/admin/categories
123
139
 
124
140
  POST /api/admin/categories
125
141
  → Dashboard sends new customizations, backend saves them
126
-
127
- PUT /api/admin/categories
128
- → (Optional) Update a single category (hide/rename)
129
142
  ```
130
143
 
131
144
  **Why L5?** Only the app knows HTTP. Only the app can validate requests.
132
145
 
146
+ > ⚠️ **Implementation status**: API route is planned. Not yet implemented in `packages/core/`.
147
+
133
148
  ---
134
149
 
135
150
  ### Phase 5: Dashboard UI (L4 — Component)
@@ -149,18 +164,17 @@ PUT /api/admin/categories
149
164
  │ ✨ Bestsellers │
150
165
  │ [Edit] [Delete] │
151
166
  ├─────────────────────────────────┤
152
- │ │
153
167
  │ [+ Add Custom] [Save] │
154
168
  └─────────────────────────────────┘
155
169
  ```
156
170
 
157
- **Why L4?** Reusable component (could work in different apps). Doesn't know about HTTP/databases.
171
+ > ⚠️ **Implementation status**: Dashboard component is planned. Not yet implemented in `packages/components/`.
158
172
 
159
173
  ---
160
174
 
161
- ## Why This Architecture Is "Agnóstic"
175
+ ## Why This Architecture Is "Agnostic"
162
176
 
163
- **Agnóstic** = "Works with any backend, no vendor lock-in."
177
+ **Agnostic** = "Works with any backend, no vendor lock-in."
164
178
 
165
179
  ### Data Flow
166
180
 
@@ -176,7 +190,6 @@ PUT /api/admin/categories
176
190
  │ BackendMetadataAdapter (Interface)│
177
191
  │ - getMetadata() │
178
192
  │ - setMetadata() │
179
- │ (Same methods for all backends) │
180
193
  └──────────┬───────────────────────────┘
181
194
  │ (Phase 3: mergeCategories)
182
195
  ↓
@@ -210,8 +223,6 @@ PUT /api/admin/categories
210
223
  - Phase 4 (API route)
211
224
  - Phase 5 (UI component)
212
225
 
213
- **Why?** All non-Phase-2 code depends on the **interface**, not the **implementation**.
214
-
215
226
  ---
216
227
 
217
228
  ## Key Concepts
@@ -243,21 +254,17 @@ Medusa: sales_channel.metadata = { category_customizations: {...} }
243
254
  Shopify: custom field or app data store (same interface)
244
255
  ```
245
256
 
246
- Result: One less database to maintain.
247
-
248
257
  ---
249
258
 
250
259
  ## Implementation Order (For Next Agent)
251
260
 
252
- See `.development-guides/category-customization-implementation.md` for detailed step-by-step.
253
-
254
261
  **TL;DR:**
255
- 1. Add types in L1
256
- 2. Extend metadata adapter in L2
262
+ 1. Add types in L1 (`@thorprovider/types`)
263
+ 2. Extend metadata adapter in L2 (`BackendMetadataAdapter`)
257
264
  3. Create `mergeCategories()` service in L2
258
265
  4. Integrate into `CommerceProvider.getCategories()` in L2
259
- 5. Create API route in L5
260
- 6. Create UI component in L4
266
+ 5. Create API route in L5 (`packages/core/app/api/admin/categories/route.ts`)
267
+ 6. Create UI component in L4 (`packages/components/`)
261
268
  7. Integrate into dashboard in L5
262
269
 
263
270
  ---
@@ -299,11 +306,12 @@ Storefront should render it like base categories.
299
306
 
300
307
  ## Related Files
301
308
 
302
- - **Implementation plan**: `.development-guides/category-customization-implementation.md`
303
- - **Types**: `packages/types/src/admin/category-customizations.ts`
304
- - **Metadata adapter**: `packages/adapters/src/backend/BackendMetadataAdapter.ts`
305
- - **Service**: `packages/adapters/src/services/category-service.ts`
306
- - **Provider integration**: `packages/adapters/src/providers/medusa/index.ts` (getCategories)
307
- - **API route**: `packages/core/app/api/admin/categories/route.ts`
308
- - **Component**: `packages/components/src/patterns/modules/dashboard/CategoryCustomization.tsx`
309
+ > ⚠️ The following files are **planned** and do not yet exist in the codebase:
309
310
 
311
+ | File | Status |
312
+ |------|--------|
313
+ | `packages/types/src/admin/category-customizations.ts` | 🗓️ Planned |
314
+ | `packages/adapters/src/backend/BackendMetadataAdapter.ts` | ✅ Exists (extend for categories) |
315
+ | `packages/adapters/src/services/category-service.ts` | 🗓️ Planned |
316
+ | `packages/core/app/api/admin/categories/route.ts` | 🗓️ Planned |
317
+ | `packages/components/src/patterns/modules/dashboard/CategoryCustomization.tsx` | 🗓️ Planned |