@decocms/apps 1.12.1 → 1.14.0-next.1
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 +196 -36
- package/package.json +1 -2
- 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,207 @@ Provides VTEX and Shopify loaders, actions, hooks, and shared commerce types bas
|
|
|
13
17
|
npm install @decocms/apps
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
### Release channels
|
|
21
|
+
|
|
22
|
+
`@decocms/apps` publishes two npm dist-tags:
|
|
23
|
+
|
|
24
|
+
- **`@latest`** — default channel. `npm install @decocms/apps` and any `^X.Y.Z` range resolve here.
|
|
25
|
+
- **`@next`** — opt-in prerelease channel for validation builds (`X.Y.Z-next.N`). Carets never resolve to prereleases, so you only get these by asking:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Follow the next channel (re-resolves on each install)
|
|
29
|
+
npm install @decocms/apps@next
|
|
30
|
+
|
|
31
|
+
# Or pin an exact prerelease
|
|
32
|
+
npm install @decocms/apps@1.14.0-next.0
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Minimum wiring
|
|
17
38
|
|
|
18
39
|
### VTEX
|
|
19
40
|
|
|
20
|
-
|
|
41
|
+
A working VTEX storefront needs three things: a `deco-vtex` config block, an `initVtexFromBlocks()` call in setup, and the commerce loader registry.
|
|
42
|
+
|
|
43
|
+
#### 1. Config block (`.deco/blocks/deco-vtex.json`)
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"__resolveType": "deco-vtex",
|
|
48
|
+
"account": "my-store",
|
|
49
|
+
"publicUrl": "https://www.my-store.com.br",
|
|
50
|
+
"salesChannel": "1",
|
|
51
|
+
"appKey": { "__resolveType": "secret/key" },
|
|
52
|
+
"appToken": { "__resolveType": "secret/key" }
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### 2. Setup (`src/setup.ts`)
|
|
21
57
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
58
|
+
```ts
|
|
59
|
+
import { createSiteSetup } from "@decocms/start/setup";
|
|
60
|
+
import { createInstrumentedFetch } from "@decocms/start/sdk/instrumentedFetch";
|
|
61
|
+
import { initVtexFromBlocks, setVtexFetch } from "@decocms/apps/vtex/client";
|
|
62
|
+
import { createVtexCommerceLoaders } from "@decocms/apps/vtex/commerceLoaders";
|
|
63
|
+
|
|
64
|
+
createSiteSetup({
|
|
65
|
+
sections: import.meta.glob("./sections/**/*.tsx", { eager: true }),
|
|
66
|
+
blocks,
|
|
67
|
+
meta: () => meta,
|
|
68
|
+
initPlatform: () => initVtexFromBlocks(),
|
|
69
|
+
getCommerceLoaders: () => createVtexCommerceLoaders(),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
setVtexFetch(createInstrumentedFetch("vtex"));
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### 3. Hooks in components
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { useCart, useUser, useWishlist } from "@decocms/apps/vtex/hooks";
|
|
79
|
+
|
|
80
|
+
function AddToCartButton({ sku }: { sku: string }) {
|
|
81
|
+
const { addItems, isMutating } = useCart();
|
|
82
|
+
return (
|
|
83
|
+
<button
|
|
84
|
+
onClick={() => addItems([{ id: sku, quantity: 1 }])}
|
|
85
|
+
disabled={isMutating}
|
|
86
|
+
>
|
|
87
|
+
Add to cart
|
|
88
|
+
</button>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
That's it. Loaders are auto-registered, hooks are typed, edge cache + cookie propagation work out of the box.
|
|
33
94
|
|
|
34
95
|
### Shopify
|
|
35
96
|
|
|
36
|
-
|
|
97
|
+
```ts
|
|
98
|
+
import { createSiteSetup } from "@decocms/start/setup";
|
|
99
|
+
import { initShopifyFromBlocks } from "@decocms/apps/shopify/client";
|
|
100
|
+
import { createShopifyCommerceLoaders } from "@decocms/apps/shopify/commerceLoaders";
|
|
101
|
+
|
|
102
|
+
createSiteSetup({
|
|
103
|
+
sections: import.meta.glob("./sections/**/*.tsx", { eager: true }),
|
|
104
|
+
blocks,
|
|
105
|
+
meta: () => meta,
|
|
106
|
+
initPlatform: () => initShopifyFromBlocks(),
|
|
107
|
+
getCommerceLoaders: () => createShopifyCommerceLoaders(),
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Config block (`deco-shopify`) needs `storeName`, `storefrontAccessToken`, `languageCode`, `countryCode`.
|
|
112
|
+
|
|
113
|
+
> ⚠️ 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.
|
|
114
|
+
|
|
115
|
+
### Resend
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { initResendFromBlocks } from "@decocms/apps/resend/client";
|
|
119
|
+
import { sendEmail } from "@decocms/apps/resend/sdk";
|
|
120
|
+
|
|
121
|
+
await sendEmail({
|
|
122
|
+
to: "customer@example.com",
|
|
123
|
+
subject: "Order confirmed",
|
|
124
|
+
html: "<h1>Thanks!</h1>",
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## What's exported
|
|
131
|
+
|
|
132
|
+
### VTEX
|
|
133
|
+
|
|
134
|
+
| Subpath | Purpose |
|
|
135
|
+
|---------|---------|
|
|
136
|
+
| `@decocms/apps/vtex` | Barrel index |
|
|
137
|
+
| `@decocms/apps/vtex/client` | `vtexFetch`, `vtexFetchWithCookies`, `intelligentSearch`, `setVtexFetch`, `initVtexFromBlocks`, `configureVtex` |
|
|
138
|
+
| `@decocms/apps/vtex/commerceLoaders` | `createVtexCommerceLoaders` |
|
|
139
|
+
| `@decocms/apps/vtex/loaders/*` | Cart, user, wishlist, search, catalog, sessions, orders, autocomplete |
|
|
140
|
+
| `@decocms/apps/vtex/actions/*` | Cart mutations, auth, profile, address, wishlist, newsletter |
|
|
141
|
+
| `@decocms/apps/vtex/hooks` | `useCart`, `useUser`, `useWishlist`, `useAutocomplete`, plus `createUseCart` / `createUseUser` / `createUseWishlist` factories |
|
|
142
|
+
| `@decocms/apps/vtex/inline-loaders/*` | PDP, PLP, shelves, suggestions, minicart |
|
|
143
|
+
| `@decocms/apps/vtex/middleware` | `extractVtexContext`, `vtexCacheKeySuffix`, `propagateISCookies`, `createVtexCheckoutProxy` |
|
|
144
|
+
| `@decocms/apps/vtex/utils/*` | Transform, segment, cookies, slugCache, sortwhitelist |
|
|
37
145
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
|
43
|
-
|
|
44
|
-
| `@decocms/apps/shopify
|
|
146
|
+
> 💡 **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.
|
|
147
|
+
|
|
148
|
+
### Shopify
|
|
149
|
+
|
|
150
|
+
| Subpath | Purpose |
|
|
151
|
+
|---------|---------|
|
|
152
|
+
| `@decocms/apps/shopify` | Barrel |
|
|
153
|
+
| `@decocms/apps/shopify/client` | `setShopifyFetch`, GraphQL helpers |
|
|
154
|
+
| `@decocms/apps/shopify/loaders/*` | PDP, PLP, ProductList, RelatedProducts, Cart, Account |
|
|
155
|
+
| `@decocms/apps/shopify/actions/cart/*` | `addItems`, `updateItems`, `discountCodesUpdate` |
|
|
156
|
+
| `@decocms/apps/shopify/actions/user/*` | `signIn`, `signUp` |
|
|
45
157
|
| `@decocms/apps/shopify/utils/*` | Transform, cookies, GraphQL queries |
|
|
46
158
|
|
|
47
|
-
###
|
|
159
|
+
### Resend
|
|
48
160
|
|
|
49
|
-
|
|
161
|
+
| Subpath | Purpose |
|
|
162
|
+
|---------|---------|
|
|
163
|
+
| `@decocms/apps/resend/client` | `initResendFromBlocks` |
|
|
164
|
+
| `@decocms/apps/resend/sdk` | `sendEmail` |
|
|
165
|
+
| `@decocms/apps/resend/actions/send` | Invocable email action |
|
|
50
166
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
167
|
+
### Shared commerce
|
|
168
|
+
|
|
169
|
+
Platform-agnostic types and components.
|
|
170
|
+
|
|
171
|
+
| Subpath | Purpose |
|
|
172
|
+
|---------|---------|
|
|
173
|
+
| `@decocms/apps/commerce/types` | schema.org `Product`, `ProductDetailsPage`, `ProductListingPage`, `Offer`, `BreadcrumbList`, etc. |
|
|
174
|
+
| `@decocms/apps/commerce/components/Image` | Optimized commerce image with CDN routing |
|
|
175
|
+
| `@decocms/apps/commerce/components/Picture` | `<picture>` with responsive sources |
|
|
55
176
|
| `@decocms/apps/commerce/components/JsonLd` | Structured data for SEO |
|
|
56
|
-
| `@decocms/apps/commerce/sdk
|
|
57
|
-
| `@decocms/apps/commerce/
|
|
177
|
+
| `@decocms/apps/commerce/sdk/useOffer` | Pick the best offer per region/seller |
|
|
178
|
+
| `@decocms/apps/commerce/sdk/format` | `formatPrice`, `formatPriceRange` |
|
|
179
|
+
| `@decocms/apps/commerce/sdk/analytics` | Event types + `mapProductToAnalyticsItem` |
|
|
180
|
+
| `@decocms/apps/commerce/sdk/useVariantPossibilities` | Variant axis builder for selectors |
|
|
181
|
+
|
|
182
|
+
### Website (utility app)
|
|
58
183
|
|
|
59
|
-
|
|
184
|
+
| Subpath | Purpose |
|
|
185
|
+
|---------|---------|
|
|
186
|
+
| `@decocms/apps/website` | `configureWebsite`, `configureSeo` |
|
|
187
|
+
| `@decocms/apps/website/loaders/redirectsFromCsv` | Bulk redirects from CSV |
|
|
188
|
+
| `@decocms/apps/website/loaders/fonts/*` | Google fonts, custom CDN font loaders |
|
|
60
189
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
190
|
+
Complete export tables: [docs.deco.cx/v2/en/reference/commerce-exports](https://docs.deco.cx/v2/en/reference/commerce-exports).
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Documentation
|
|
195
|
+
|
|
196
|
+
The commerce documentation lives at **[docs.deco.cx/v2/en/commerce](https://docs.deco.cx/v2/en/commerce/overview)**:
|
|
197
|
+
|
|
198
|
+
- [VTEX overview](https://docs.deco.cx/v2/en/commerce/vtex-overview) — config block, secrets, install steps.
|
|
199
|
+
- [VTEX loaders & actions](https://docs.deco.cx/v2/en/commerce/vtex-loaders-and-actions) — input/output cookbook.
|
|
200
|
+
- [VTEX hooks](https://docs.deco.cx/v2/en/commerce/vtex-hooks) — `useCart`, `useUser`, `useWishlist`, `useAutocomplete`.
|
|
201
|
+
- [VTEX gotchas](https://docs.deco.cx/v2/en/commerce/vtex-gotchas) — cookies, sales channel, regionId, IS sort sanitization.
|
|
202
|
+
- [Shopify](https://docs.deco.cx/v2/en/commerce/shopify) — configure, loaders, actions, cart-cookie wiring.
|
|
203
|
+
- [Resend](https://docs.deco.cx/v2/en/commerce/resend) — email setup.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Peer dependencies
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"@decocms/start": ">=2.0.0",
|
|
212
|
+
"@tanstack/react-query": ">=5.0.0",
|
|
213
|
+
"react": ">=19.0.0",
|
|
214
|
+
"react-dom": ">=19.0.0"
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The published peer floor is React 18 to ease incremental migration, but the v2 stack assumes React 19 + the React Compiler.
|
|
219
|
+
|
|
220
|
+
---
|
|
65
221
|
|
|
66
222
|
## Development
|
|
67
223
|
|
|
@@ -70,6 +226,10 @@ npm run typecheck # tsc --noEmit
|
|
|
70
226
|
npm run check # typecheck + unused export detection
|
|
71
227
|
```
|
|
72
228
|
|
|
229
|
+
This is a library — there is no dev server. Consumer storefronts run their own `vite dev`.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
73
233
|
## License
|
|
74
234
|
|
|
75
235
|
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/apps",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0-next.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deco commerce apps for TanStack Start - Shopify, VTEX, commerce types, analytics utils",
|
|
6
6
|
"exports": {
|
|
@@ -118,7 +118,6 @@
|
|
|
118
118
|
"@biomejs/biome": "^2.4.7",
|
|
119
119
|
"@decocms/start": "^2.5.0",
|
|
120
120
|
"@semantic-release/exec": "^7.1.0",
|
|
121
|
-
"@semantic-release/git": "^10.0.1",
|
|
122
121
|
"@tanstack/react-query": "^5.90.21",
|
|
123
122
|
"@types/react": "^19.0.0",
|
|
124
123
|
"@vitest/coverage-v8": "^4.1.0",
|
|
@@ -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 {
|