@decocms/apps 1.12.1 → 1.13.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/README.md +181 -36
- package/package.json +1 -1
- package/vtex/inline-loaders/productDetailsPage.ts +4 -2
package/README.md
CHANGED
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@decocms/apps)
|
|
4
4
|
[](https://github.com/decocms/apps-start/blob/main/LICENSE)
|
|
5
5
|
|
|
6
|
-
Commerce integrations for [
|
|
6
|
+
Commerce integrations for [deco.cx](https://deco.cx) storefronts on **TanStack Start + React 19 + Cloudflare Workers**.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
`@decocms/apps` provides VTEX, Shopify, and Resend integrations (loaders, actions, hooks, middleware) plus shared schema.org commerce types. It depends on [`@decocms/start`](https://www.npmjs.com/package/@decocms/start).
|
|
9
|
+
|
|
10
|
+
📖 **[Read the full documentation →](https://docs.deco.cx/v2/en/commerce/overview)**
|
|
11
|
+
|
|
12
|
+
---
|
|
9
13
|
|
|
10
14
|
## Install
|
|
11
15
|
|
|
@@ -13,55 +17,192 @@ Provides VTEX and Shopify loaders, actions, hooks, and shared commerce types bas
|
|
|
13
17
|
npm install @decocms/apps
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Minimum wiring
|
|
17
23
|
|
|
18
24
|
### VTEX
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
A working VTEX storefront needs three things: a `deco-vtex` config block, an `initVtexFromBlocks()` call in setup, and the commerce loader registry.
|
|
27
|
+
|
|
28
|
+
#### 1. Config block (`.deco/blocks/deco-vtex.json`)
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"__resolveType": "deco-vtex",
|
|
33
|
+
"account": "my-store",
|
|
34
|
+
"publicUrl": "https://www.my-store.com.br",
|
|
35
|
+
"salesChannel": "1",
|
|
36
|
+
"appKey": { "__resolveType": "secret/key" },
|
|
37
|
+
"appToken": { "__resolveType": "secret/key" }
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### 2. Setup (`src/setup.ts`)
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { createSiteSetup } from "@decocms/start/setup";
|
|
45
|
+
import { createInstrumentedFetch } from "@decocms/start/sdk/instrumentedFetch";
|
|
46
|
+
import { initVtexFromBlocks, setVtexFetch } from "@decocms/apps/vtex/client";
|
|
47
|
+
import { createVtexCommerceLoaders } from "@decocms/apps/vtex/commerceLoaders";
|
|
48
|
+
|
|
49
|
+
createSiteSetup({
|
|
50
|
+
sections: import.meta.glob("./sections/**/*.tsx", { eager: true }),
|
|
51
|
+
blocks,
|
|
52
|
+
meta: () => meta,
|
|
53
|
+
initPlatform: () => initVtexFromBlocks(),
|
|
54
|
+
getCommerceLoaders: () => createVtexCommerceLoaders(),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
setVtexFetch(createInstrumentedFetch("vtex"));
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### 3. Hooks in components
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { useCart, useUser, useWishlist } from "@decocms/apps/vtex/hooks";
|
|
64
|
+
|
|
65
|
+
function AddToCartButton({ sku }: { sku: string }) {
|
|
66
|
+
const { addItems, isMutating } = useCart();
|
|
67
|
+
return (
|
|
68
|
+
<button
|
|
69
|
+
onClick={() => addItems([{ id: sku, quantity: 1 }])}
|
|
70
|
+
disabled={isMutating}
|
|
71
|
+
>
|
|
72
|
+
Add to cart
|
|
73
|
+
</button>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
21
77
|
|
|
22
|
-
|
|
23
|
-
|--------|---------|
|
|
24
|
-
| `@decocms/apps/vtex` | Configuration and setup |
|
|
25
|
-
| `@decocms/apps/vtex/client` | VTEX API client with SWR caching |
|
|
26
|
-
| `@decocms/apps/vtex/loaders/*` | Product, cart, search, catalog, session, wishlist |
|
|
27
|
-
| `@decocms/apps/vtex/actions/*` | Checkout, auth, newsletter, profile, wishlist |
|
|
28
|
-
| `@decocms/apps/vtex/hooks` | useCart, useUser, useWishlist, useAutocomplete |
|
|
29
|
-
| `@decocms/apps/vtex/inline-loaders/*` | PDP, PLP, product list, suggestions |
|
|
30
|
-
| `@decocms/apps/vtex/middleware` | Cookie propagation and session handling |
|
|
31
|
-
| `@decocms/apps/vtex/invoke` | Server function wrappers |
|
|
32
|
-
| `@decocms/apps/vtex/utils/*` | Transform, enrichment, segment, cookies |
|
|
78
|
+
That's it. Loaders are auto-registered, hooks are typed, edge cache + cookie propagation work out of the box.
|
|
33
79
|
|
|
34
80
|
### Shopify
|
|
35
81
|
|
|
36
|
-
|
|
82
|
+
```ts
|
|
83
|
+
import { createSiteSetup } from "@decocms/start/setup";
|
|
84
|
+
import { initShopifyFromBlocks } from "@decocms/apps/shopify/client";
|
|
85
|
+
import { createShopifyCommerceLoaders } from "@decocms/apps/shopify/commerceLoaders";
|
|
86
|
+
|
|
87
|
+
createSiteSetup({
|
|
88
|
+
sections: import.meta.glob("./sections/**/*.tsx", { eager: true }),
|
|
89
|
+
blocks,
|
|
90
|
+
meta: () => meta,
|
|
91
|
+
initPlatform: () => initShopifyFromBlocks(),
|
|
92
|
+
getCommerceLoaders: () => createShopifyCommerceLoaders(),
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Config block (`deco-shopify`) needs `storeName`, `storefrontAccessToken`, `languageCode`, `countryCode`.
|
|
97
|
+
|
|
98
|
+
> ⚠️ Shopify cart loaders require **cart-cookie wiring** in your route handler. See [Shopify reference](https://docs.deco.cx/v2/en/commerce/shopify) for the canonical pattern.
|
|
99
|
+
|
|
100
|
+
### Resend
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { initResendFromBlocks } from "@decocms/apps/resend/client";
|
|
104
|
+
import { sendEmail } from "@decocms/apps/resend/sdk";
|
|
105
|
+
|
|
106
|
+
await sendEmail({
|
|
107
|
+
to: "customer@example.com",
|
|
108
|
+
subject: "Order confirmed",
|
|
109
|
+
html: "<h1>Thanks!</h1>",
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## What's exported
|
|
37
116
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
|
41
|
-
|
|
42
|
-
| `@decocms/apps/
|
|
43
|
-
| `@decocms/apps/
|
|
44
|
-
| `@decocms/apps/
|
|
117
|
+
### VTEX
|
|
118
|
+
|
|
119
|
+
| Subpath | Purpose |
|
|
120
|
+
|---------|---------|
|
|
121
|
+
| `@decocms/apps/vtex` | Barrel index |
|
|
122
|
+
| `@decocms/apps/vtex/client` | `vtexFetch`, `vtexFetchWithCookies`, `intelligentSearch`, `setVtexFetch`, `initVtexFromBlocks`, `configureVtex` |
|
|
123
|
+
| `@decocms/apps/vtex/commerceLoaders` | `createVtexCommerceLoaders` |
|
|
124
|
+
| `@decocms/apps/vtex/loaders/*` | Cart, user, wishlist, search, catalog, sessions, orders, autocomplete |
|
|
125
|
+
| `@decocms/apps/vtex/actions/*` | Cart mutations, auth, profile, address, wishlist, newsletter |
|
|
126
|
+
| `@decocms/apps/vtex/hooks` | `useCart`, `useUser`, `useWishlist`, `useAutocomplete`, plus `createUseCart` / `createUseUser` / `createUseWishlist` factories |
|
|
127
|
+
| `@decocms/apps/vtex/inline-loaders/*` | PDP, PLP, shelves, suggestions, minicart |
|
|
128
|
+
| `@decocms/apps/vtex/middleware` | `extractVtexContext`, `vtexCacheKeySuffix`, `propagateISCookies`, `createVtexCheckoutProxy` |
|
|
129
|
+
| `@decocms/apps/vtex/utils/*` | Transform, segment, cookies, slugCache, sortwhitelist |
|
|
130
|
+
|
|
131
|
+
> 💡 **Calling VTEX loaders/actions from the client.** Use the typed `invoke` client generated by `@decocms/start` — `invoke["vtex/loaders/cart.ts"](props)` — or use the React hooks above. There is **no** `@decocms/apps/vtex/invoke` subpath.
|
|
132
|
+
|
|
133
|
+
### Shopify
|
|
134
|
+
|
|
135
|
+
| Subpath | Purpose |
|
|
136
|
+
|---------|---------|
|
|
137
|
+
| `@decocms/apps/shopify` | Barrel |
|
|
138
|
+
| `@decocms/apps/shopify/client` | `setShopifyFetch`, GraphQL helpers |
|
|
139
|
+
| `@decocms/apps/shopify/loaders/*` | PDP, PLP, ProductList, RelatedProducts, Cart, Account |
|
|
140
|
+
| `@decocms/apps/shopify/actions/cart/*` | `addItems`, `updateItems`, `discountCodesUpdate` |
|
|
141
|
+
| `@decocms/apps/shopify/actions/user/*` | `signIn`, `signUp` |
|
|
45
142
|
| `@decocms/apps/shopify/utils/*` | Transform, cookies, GraphQL queries |
|
|
46
143
|
|
|
47
|
-
###
|
|
144
|
+
### Resend
|
|
48
145
|
|
|
49
|
-
|
|
146
|
+
| Subpath | Purpose |
|
|
147
|
+
|---------|---------|
|
|
148
|
+
| `@decocms/apps/resend/client` | `initResendFromBlocks` |
|
|
149
|
+
| `@decocms/apps/resend/sdk` | `sendEmail` |
|
|
150
|
+
| `@decocms/apps/resend/actions/send` | Invocable email action |
|
|
50
151
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
152
|
+
### Shared commerce
|
|
153
|
+
|
|
154
|
+
Platform-agnostic types and components.
|
|
155
|
+
|
|
156
|
+
| Subpath | Purpose |
|
|
157
|
+
|---------|---------|
|
|
158
|
+
| `@decocms/apps/commerce/types` | schema.org `Product`, `ProductDetailsPage`, `ProductListingPage`, `Offer`, `BreadcrumbList`, etc. |
|
|
159
|
+
| `@decocms/apps/commerce/components/Image` | Optimized commerce image with CDN routing |
|
|
160
|
+
| `@decocms/apps/commerce/components/Picture` | `<picture>` with responsive sources |
|
|
55
161
|
| `@decocms/apps/commerce/components/JsonLd` | Structured data for SEO |
|
|
56
|
-
| `@decocms/apps/commerce/sdk
|
|
57
|
-
| `@decocms/apps/commerce/
|
|
162
|
+
| `@decocms/apps/commerce/sdk/useOffer` | Pick the best offer per region/seller |
|
|
163
|
+
| `@decocms/apps/commerce/sdk/format` | `formatPrice`, `formatPriceRange` |
|
|
164
|
+
| `@decocms/apps/commerce/sdk/analytics` | Event types + `mapProductToAnalyticsItem` |
|
|
165
|
+
| `@decocms/apps/commerce/sdk/useVariantPossibilities` | Variant axis builder for selectors |
|
|
166
|
+
|
|
167
|
+
### Website (utility app)
|
|
168
|
+
|
|
169
|
+
| Subpath | Purpose |
|
|
170
|
+
|---------|---------|
|
|
171
|
+
| `@decocms/apps/website` | `configureWebsite`, `configureSeo` |
|
|
172
|
+
| `@decocms/apps/website/loaders/redirectsFromCsv` | Bulk redirects from CSV |
|
|
173
|
+
| `@decocms/apps/website/loaders/fonts/*` | Google fonts, custom CDN font loaders |
|
|
174
|
+
|
|
175
|
+
Complete export tables: [docs.deco.cx/v2/en/reference/commerce-exports](https://docs.deco.cx/v2/en/reference/commerce-exports).
|
|
58
176
|
|
|
59
|
-
|
|
177
|
+
---
|
|
60
178
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
179
|
+
## Documentation
|
|
180
|
+
|
|
181
|
+
The commerce documentation lives at **[docs.deco.cx/v2/en/commerce](https://docs.deco.cx/v2/en/commerce/overview)**:
|
|
182
|
+
|
|
183
|
+
- [VTEX overview](https://docs.deco.cx/v2/en/commerce/vtex-overview) — config block, secrets, install steps.
|
|
184
|
+
- [VTEX loaders & actions](https://docs.deco.cx/v2/en/commerce/vtex-loaders-and-actions) — input/output cookbook.
|
|
185
|
+
- [VTEX hooks](https://docs.deco.cx/v2/en/commerce/vtex-hooks) — `useCart`, `useUser`, `useWishlist`, `useAutocomplete`.
|
|
186
|
+
- [VTEX gotchas](https://docs.deco.cx/v2/en/commerce/vtex-gotchas) — cookies, sales channel, regionId, IS sort sanitization.
|
|
187
|
+
- [Shopify](https://docs.deco.cx/v2/en/commerce/shopify) — configure, loaders, actions, cart-cookie wiring.
|
|
188
|
+
- [Resend](https://docs.deco.cx/v2/en/commerce/resend) — email setup.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Peer dependencies
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"@decocms/start": ">=2.0.0",
|
|
197
|
+
"@tanstack/react-query": ">=5.0.0",
|
|
198
|
+
"react": ">=19.0.0",
|
|
199
|
+
"react-dom": ">=19.0.0"
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The published peer floor is React 18 to ease incremental migration, but the v2 stack assumes React 19 + the React Compiler.
|
|
204
|
+
|
|
205
|
+
---
|
|
65
206
|
|
|
66
207
|
## Development
|
|
67
208
|
|
|
@@ -70,6 +211,10 @@ npm run typecheck # tsc --noEmit
|
|
|
70
211
|
npm run check # typecheck + unused export detection
|
|
71
212
|
```
|
|
72
213
|
|
|
214
|
+
This is a library — there is no dev server. Consumer storefronts run their own `vite dev`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
73
218
|
## License
|
|
74
219
|
|
|
75
220
|
MIT
|
package/package.json
CHANGED
|
@@ -17,12 +17,14 @@ export interface PDPProps {
|
|
|
17
17
|
indexingSkus?: boolean;
|
|
18
18
|
/** Use product.description instead of metaTagDescription for SEO */
|
|
19
19
|
preferDescription?: boolean;
|
|
20
|
+
/** Use lean variant transform (no images/video) for hasVariant[]. Defaults to true. */
|
|
21
|
+
leanVariants?: boolean;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export default async function vtexProductDetailsPage(
|
|
23
25
|
props: PDPProps,
|
|
24
26
|
): Promise<ProductDetailsPage | null> {
|
|
25
|
-
const { slug, skuId, indexingSkus, preferDescription } = props;
|
|
27
|
+
const { slug, skuId, indexingSkus, preferDescription, leanVariants = true } = props;
|
|
26
28
|
if (!slug) return null;
|
|
27
29
|
|
|
28
30
|
try {
|
|
@@ -53,7 +55,7 @@ export default async function vtexProductDetailsPage(
|
|
|
53
55
|
const page = toProductPage(product, sku, kitItems, {
|
|
54
56
|
baseUrl,
|
|
55
57
|
priceCurrency: "BRL",
|
|
56
|
-
leanVariants
|
|
58
|
+
leanVariants,
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
return {
|