@decocms/start 2.22.0 → 2.24.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/.agents/skills/deco-to-tanstack-migration/SKILL.md +12 -7
- package/.agents/skills/deco-to-tanstack-migration/references/platform-hooks/README.md +57 -47
- package/.agents/skills/deco-to-tanstack-migration/references/platform-hooks-factories.md +186 -0
- package/.agents/skills/deco-to-tanstack-migration/references/post-migration-cleanup.md +64 -9
- package/MIGRATION_TOOLING_PLAN.md +235 -0
- package/package.json +1 -1
- package/scripts/migrate/post-cleanup/rules.ts +239 -7
- package/scripts/migrate/post-cleanup/runner.test.ts +268 -1
- package/scripts/migrate/templates/commerce-loaders.ts +2 -1
- package/scripts/migrate/templates/routes.ts +15 -10
- package/scripts/migrate/templates/server-entry.ts +13 -55
- package/scripts/migrate/templates/vite-config.ts +0 -35
- package/scripts/migrate-post-cleanup.ts +4 -2
|
@@ -43,7 +43,7 @@ Each phase has entry/exit criteria. Follow in order. Automation % indicates how
|
|
|
43
43
|
| [2](#phase-2--signals--state) | Signals & State | ~50% | `references/signals/` |
|
|
44
44
|
| [3](#phase-3--deco-framework) | Deco Framework Elimination | ~80% | `references/deco-framework/` |
|
|
45
45
|
| [4](#phase-4--commerce--types) | Commerce Types & UI | ~70% | `references/commerce/` |
|
|
46
|
-
| [5](#phase-5--platform-hooks) | Platform Hooks |
|
|
46
|
+
| [5](#phase-5--platform-hooks) | Platform Hooks (factories, W12+) | template | `references/platform-hooks-factories.md` |
|
|
47
47
|
| [6](#phase-6--islands-elimination) | Islands Elimination | ~60% | `references/islands.md` |
|
|
48
48
|
| [7](#phase-7--section-registry) | Section Registry & Setup | 0% | `references/async-rendering.md` |
|
|
49
49
|
| [8](#phase-8--routes--cms) | Routes & CMS | template | `references/navigation.md` |
|
|
@@ -152,14 +152,18 @@ See: `references/commerce/README.md`, `references/vtex-commerce.md`
|
|
|
152
152
|
|
|
153
153
|
**Entry**: Phase 4 complete
|
|
154
154
|
|
|
155
|
-
**Actions
|
|
156
|
-
1.
|
|
157
|
-
2.
|
|
158
|
-
3.
|
|
155
|
+
**Actions (Wave 12+ factory-based — current)**:
|
|
156
|
+
1. `src/hooks/useCart.ts` — 5-line shim around `createUseCart` from `@decocms/apps/vtex/hooks/createUseCart`
|
|
157
|
+
2. `src/hooks/useUser.ts` — 5-line shim around `createUseUser`
|
|
158
|
+
3. `src/hooks/useWishlist.ts` — 5-line shim around `createUseWishlist`
|
|
159
|
+
4. The migration template (`scripts/migrate/templates/hooks.ts`) emits all three for VTEX sites automatically.
|
|
160
|
+
|
|
161
|
+
For non-VTEX platforms, scaffold no-op stubs using `@decocms/start/sdk/signal` (see factories doc § "Non-VTEX platforms").
|
|
159
162
|
|
|
160
163
|
**Exit**: Cart add/remove works, no `apps/{platform}/hooks` imports
|
|
161
164
|
|
|
162
|
-
See: `references/platform-hooks
|
|
165
|
+
See: `references/platform-hooks-factories.md` (canonical, Wave 12+).
|
|
166
|
+
Pre-W12 manual approach is preserved at `references/platform-hooks/README.md` for sites that haven't migrated to factories yet.
|
|
163
167
|
|
|
164
168
|
---
|
|
165
169
|
|
|
@@ -356,7 +360,8 @@ For sites with 100+ sections:
|
|
|
356
360
|
| Signals → TanStack Store | `references/signals/` |
|
|
357
361
|
| Deco framework elimination | `references/deco-framework/` |
|
|
358
362
|
| Commerce & widget types | `references/commerce/` |
|
|
359
|
-
| Platform hooks (VTEX) | `references/platform-hooks
|
|
363
|
+
| Platform hooks (VTEX, factories — Wave 12+) | `references/platform-hooks-factories.md` |
|
|
364
|
+
| Platform hooks (manual, legacy pre-W12) | `references/platform-hooks/README.md` |
|
|
360
365
|
| Vite configuration | `references/vite-config/` |
|
|
361
366
|
| Automation commands | `references/codemod-commands.md` |
|
|
362
367
|
| Islands elimination | `references/islands.md` |
|
|
@@ -1,16 +1,29 @@
|
|
|
1
|
-
# Platform Hooks Migration
|
|
1
|
+
# Platform Hooks Migration (legacy reference)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **This document describes the pre-Wave-12 manual approach.** New
|
|
4
|
+
> migrations should follow
|
|
5
|
+
> [`platform-hooks-factories.md`](../platform-hooks-factories.md), which
|
|
6
|
+
> covers the `createUseCart` / `createUseUser` / `createUseWishlist`
|
|
7
|
+
> factories from `@decocms/apps/vtex/hooks`. The factories collapse
|
|
8
|
+
> everything below into a 5-line site shim per hook.
|
|
9
|
+
>
|
|
10
|
+
> This file is kept for sites that scaffolded before the factories
|
|
11
|
+
> existed — typically sites with `src/lib/vtex-cart-server.ts` or
|
|
12
|
+
> hand-rolled `createServerFn` calls to VTEX endpoints inside
|
|
13
|
+
> `src/hooks/useCart.ts`. See the **"Migrating off the manual approach"**
|
|
14
|
+
> section in the new doc for the cleanup playbook.
|
|
4
15
|
|
|
5
|
-
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Strategy (legacy)
|
|
6
19
|
|
|
7
20
|
All hooks are **site-local**. No Vite alias tricks. No compat layers.
|
|
8
21
|
|
|
9
|
-
- Active platform hooks (VTEX for this store)
|
|
10
|
-
- Inactive platform hooks (Wake, Shopify, etc.)
|
|
11
|
-
- Auth hooks
|
|
22
|
+
- Active platform hooks (VTEX for this store) → `~/hooks/useCart.ts` with real implementation
|
|
23
|
+
- Inactive platform hooks (Wake, Shopify, etc.) → `~/hooks/platform/{name}.ts` with no-op stubs
|
|
24
|
+
- Auth hooks → `~/hooks/useUser.ts`, `~/hooks/useWishlist.ts`
|
|
12
25
|
|
|
13
|
-
## VTEX useCart (
|
|
26
|
+
## VTEX useCart (Manual Implementation)
|
|
14
27
|
|
|
15
28
|
### Why Server Functions Are Required
|
|
16
29
|
|
|
@@ -18,7 +31,7 @@ The storefront domain (e.g., `my-store.deco.site`) differs from the VTEX checkou
|
|
|
18
31
|
|
|
19
32
|
Use TanStack Start `createServerFn` to create server-side proxy functions that the client hook calls transparently.
|
|
20
33
|
|
|
21
|
-
### Server Functions (
|
|
34
|
+
### Server Functions (`~/lib/vtex-cart-server.ts`)
|
|
22
35
|
|
|
23
36
|
```typescript
|
|
24
37
|
import { createServerFn } from "@tanstack/react-start";
|
|
@@ -40,50 +53,46 @@ export const getOrCreateCart = createServerFn({ method: "GET" })
|
|
|
40
53
|
"X-VTEX-API-AppKey": API_KEY,
|
|
41
54
|
"X-VTEX-API-AppToken": API_TOKEN,
|
|
42
55
|
},
|
|
43
|
-
body: JSON.stringify({
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
expectedOrderFormSections: [
|
|
58
|
+
"items",
|
|
59
|
+
"totalizers",
|
|
60
|
+
"shippingData",
|
|
61
|
+
"clientPreferencesData",
|
|
62
|
+
"storePreferencesData",
|
|
63
|
+
"marketingData",
|
|
64
|
+
],
|
|
65
|
+
}),
|
|
44
66
|
});
|
|
45
67
|
return res.json();
|
|
46
68
|
});
|
|
47
|
-
|
|
48
|
-
export const addItemsToCart = createServerFn({ method: "POST" })
|
|
49
|
-
.validator((data: { orderFormId: string; items: any[] }) => data)
|
|
50
|
-
.handler(async ({ data }) => {
|
|
51
|
-
const res = await fetch(
|
|
52
|
-
`https://${ACCOUNT}.vtexcommercestable.com.br/api/checkout/pub/orderForm/${data.orderFormId}/items`,
|
|
53
|
-
{
|
|
54
|
-
method: "POST",
|
|
55
|
-
headers: { "Content-Type": "application/json", "X-VTEX-API-AppKey": API_KEY, "X-VTEX-API-AppToken": API_TOKEN },
|
|
56
|
-
body: JSON.stringify({ orderItems: data.items }),
|
|
57
|
-
},
|
|
58
|
-
);
|
|
59
|
-
return res.json();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
export const updateCartItems = createServerFn({ method: "POST" })
|
|
63
|
-
.validator((data: { orderFormId: string; items: any[] }) => data)
|
|
64
|
-
.handler(async ({ data }) => {
|
|
65
|
-
const res = await fetch(
|
|
66
|
-
`https://${ACCOUNT}.vtexcommercestable.com.br/api/checkout/pub/orderForm/${data.orderFormId}/items/update`,
|
|
67
|
-
{
|
|
68
|
-
method: "POST",
|
|
69
|
-
headers: { "Content-Type": "application/json", "X-VTEX-API-AppKey": API_KEY, "X-VTEX-API-AppToken": API_TOKEN },
|
|
70
|
-
body: JSON.stringify({ orderItems: data.items }),
|
|
71
|
-
},
|
|
72
|
-
);
|
|
73
|
-
return res.json();
|
|
74
|
-
});
|
|
75
69
|
```
|
|
76
70
|
|
|
77
|
-
|
|
71
|
+
> **Don't write code like this in new sites.** The factories already wrap
|
|
72
|
+
> all canonical VTEX action endpoints (cart, session, masterdata,
|
|
73
|
+
> newsletter, checkout) in `@decocms/apps/vtex/actions/*`. The migration
|
|
74
|
+
> template scaffolds `src/server/invoke.gen.ts` which exposes them as
|
|
75
|
+
> typed server functions; `~/server/invoke.ts` then re-exports them
|
|
76
|
+
> under `invoke.vtex.actions.*`. The factory consumes that surface and
|
|
77
|
+
> returns the legacy hook shape.
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
### Hook (`~/hooks/useCart.ts`)
|
|
80
|
+
|
|
81
|
+
Key design decisions of the legacy manual hook:
|
|
80
82
|
- **Module-level singleton state** shared across all component instances
|
|
81
83
|
- **Pub/sub pattern** (`_listeners` Set) for notifying React components of changes
|
|
82
|
-
- **Cookie-based session**: reads/writes `checkout.vtex.com__orderFormId` on the **client** side
|
|
84
|
+
- **Cookie-based session**: reads/writes `checkout.vtex.com__orderFormId` on the **client** side
|
|
83
85
|
- Returns `cart` and `loading` with `.value` getter/setter for backward compat with Preact-era components
|
|
84
86
|
- Lazy initialization: cart is fetched on first component mount, not on module load
|
|
85
87
|
- Exports `itemToAnalyticsItem` for cart-specific analytics mapping
|
|
86
88
|
|
|
89
|
+
The factory in `@decocms/apps/vtex/hooks/createUseCart` ships *exactly*
|
|
90
|
+
these semantics — that's the implementation behind the new shim. If your
|
|
91
|
+
site needs to extend behaviour (e.g. extra analytics events, custom
|
|
92
|
+
post-add hooks), prefer wrapping the factory's exports rather than
|
|
93
|
+
forking back to a manual hook; the factory leaves space for that
|
|
94
|
+
without giving up the upgrade path.
|
|
95
|
+
|
|
87
96
|
### Cross-Domain Checkout
|
|
88
97
|
|
|
89
98
|
The minicart's "Finalizar Compra" button must link to the VTEX checkout domain with the `orderFormId` as a query parameter — the VTEX domain can't read the storefront's cookies:
|
|
@@ -92,10 +101,8 @@ The minicart's "Finalizar Compra" button must link to the VTEX checkout domain w
|
|
|
92
101
|
const checkoutUrl = `https://secure.${STORE_DOMAIN}/checkout/?orderFormId=${orderFormId}`;
|
|
93
102
|
```
|
|
94
103
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
Site-local types for VTEX-specific structures:
|
|
98
|
-
- `OrderFormItem`, `SimulationOrderForm`, `Sla`, `SKU`, `VtexProduct`
|
|
104
|
+
This pattern is unchanged by the factory — it's a UI concern, not a hook
|
|
105
|
+
concern. Implement it in your minicart component as before.
|
|
99
106
|
|
|
100
107
|
## Inactive Platform Stubs
|
|
101
108
|
|
|
@@ -130,9 +137,13 @@ export function useWishlist() {
|
|
|
130
137
|
}
|
|
131
138
|
```
|
|
132
139
|
|
|
133
|
-
Create similar stubs for: `shopify.ts`, `linx.ts`, `vnda.ts`, `nuvemshop.ts`.
|
|
140
|
+
Create similar stubs for: `shopify.ts`, `linx.ts`, `vnda.ts`, `nuvemshop.ts`. Match the return shape to what each platform's AddToCartButton expects (some use `addItem`, others `addItems`).
|
|
134
141
|
|
|
135
|
-
|
|
142
|
+
The factory equivalent for non-VTEX sites is documented in
|
|
143
|
+
[`platform-hooks-factories.md` § "Non-VTEX platforms"](../platform-hooks-factories.md#non-vtex-platforms).
|
|
144
|
+
Until each platform has its own factory in `@decocms/apps`, the stub
|
|
145
|
+
shape above is still correct — but use `@decocms/start/sdk/signal`
|
|
146
|
+
instead of hand-rolled `{ value: ... }` objects.
|
|
136
147
|
|
|
137
148
|
## Import Rewrites
|
|
138
149
|
|
|
@@ -143,7 +154,6 @@ sed -i '' 's|from "apps/vtex/hooks/useWishlist.ts"|from "~/hooks/useWishlist"|g'
|
|
|
143
154
|
sed -i '' 's|from "apps/vtex/utils/types.ts"|from "~/types/vtex"|g'
|
|
144
155
|
sed -i '' 's|from "apps/shopify/hooks/useCart.ts"|from "~/hooks/platform/shopify"|g'
|
|
145
156
|
sed -i '' 's|from "apps/wake/hooks/useCart.ts"|from "~/hooks/platform/wake"|g'
|
|
146
|
-
# etc. for all platforms
|
|
147
157
|
```
|
|
148
158
|
|
|
149
159
|
## Verification
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Platform Hooks — Factory Pattern
|
|
2
|
+
|
|
3
|
+
> **Canonical reference for `createUseCart` / `createUseUser` /
|
|
4
|
+
> `createUseWishlist` from `@decocms/apps/vtex/hooks`.** These factories
|
|
5
|
+
> ship the legacy invoke-based hook semantics that migrated Fresh sites
|
|
6
|
+
> depend on — module-level singleton state, listener-based re-render,
|
|
7
|
+
> awaitable async actions, signal-shaped accessors. Sites consume them
|
|
8
|
+
> as 5-line shims.
|
|
9
|
+
|
|
10
|
+
This doc replaces the pre-W12 "manual `createServerFn` per VTEX endpoint"
|
|
11
|
+
approach in
|
|
12
|
+
[`platform-hooks/README.md`](./platform-hooks/README.md). If you scaffolded
|
|
13
|
+
a site before Wave 12 (≤ `@decocms/apps@2.x` / `@decocms/start@2.18`), see
|
|
14
|
+
"Migrating off the manual approach" at the bottom.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## What the factories own
|
|
19
|
+
|
|
20
|
+
| Concern | Where it lives |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Module-level singleton state (`cart`, `user`, `wishlist`) | Inside the factory closure |
|
|
23
|
+
| `useEffect` + `forceRender(c => c + 1)` re-render pattern | Factory |
|
|
24
|
+
| Signal-shaped accessors (`cart.value`, `user.value`) | Factory |
|
|
25
|
+
| Awaitable mutations (`await addItem(...)`) | Factory |
|
|
26
|
+
| `itemToAnalyticsItem` helper (cart) | Factory |
|
|
27
|
+
| Wishlist arg swap (`productId` ↔ `productGroupId`) | Factory |
|
|
28
|
+
| **VTEX HTTP calls** | NOT in the factory — provided by the `invoke` proxy you pass in |
|
|
29
|
+
|
|
30
|
+
The factory only wires state + listeners. The site provides an `invoke`
|
|
31
|
+
object whose shape is structurally typed against
|
|
32
|
+
`CreateUseCartInvoke` / `CreateUseUserInvoke` / `CreateUseWishlistInvoke`
|
|
33
|
+
(exported next to each factory). The migration template generates an
|
|
34
|
+
`invoke` proxy in `src/server/invoke.ts` that meets all three shapes
|
|
35
|
+
without any extra wiring.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Site-local shim (the entire file)
|
|
40
|
+
|
|
41
|
+
### `src/hooks/useCart.ts`
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { createUseCart } from "@decocms/apps/vtex/hooks/createUseCart";
|
|
45
|
+
import { invoke } from "~/server/invoke";
|
|
46
|
+
|
|
47
|
+
export type { OrderForm, OrderFormItem } from "@decocms/apps/vtex/types";
|
|
48
|
+
|
|
49
|
+
export const { useCart, resetCart, itemToAnalyticsItem } = createUseCart({
|
|
50
|
+
invoke,
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `src/hooks/useUser.ts`
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { createUseUser } from "@decocms/apps/vtex/hooks/createUseUser";
|
|
58
|
+
import { invoke } from "~/server/invoke";
|
|
59
|
+
|
|
60
|
+
export type { Person } from "@decocms/apps/vtex/loaders/user";
|
|
61
|
+
|
|
62
|
+
export const { useUser, resetUser } = createUseUser({ invoke });
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `src/hooks/useWishlist.ts`
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { createUseWishlist } from "@decocms/apps/vtex/hooks/createUseWishlist";
|
|
69
|
+
import { invoke } from "~/server/invoke";
|
|
70
|
+
|
|
71
|
+
export type { WishlistItem } from "@decocms/apps/vtex/loaders/wishlist";
|
|
72
|
+
|
|
73
|
+
export const { useWishlist, resetWishlist } = createUseWishlist({ invoke });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
That's the whole hook — no `createServerFn`, no VTEX URLs, no `AppKey`
|
|
77
|
+
plumbing. `npm run migrate` scaffolds these three files automatically
|
|
78
|
+
when `--platform vtex` is set; if you regenerate, the migration template
|
|
79
|
+
in `scripts/migrate/templates/hooks.ts` is the source of truth.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Why a factory and not a single hook?
|
|
84
|
+
|
|
85
|
+
> Two reasons that come up repeatedly when reviewing migration PRs.
|
|
86
|
+
|
|
87
|
+
1. **`useCart` already exists in apps.** The canonical `vtex/hooks/useCart.ts`
|
|
88
|
+
is built on TanStack Query and exposes the `Minicart` shape — that is
|
|
89
|
+
the shape new code should target. The factory exists strictly so
|
|
90
|
+
already-migrated UIs keep working without a rewrite. Both can coexist
|
|
91
|
+
in one site.
|
|
92
|
+
2. **Singletons can't live in a shared package without leaking across
|
|
93
|
+
sites.** The factory call instantiates a fresh module-level state per
|
|
94
|
+
site. Importing `useCart` directly from apps would share state across
|
|
95
|
+
any sites that ran in the same Worker (matters less in practice, but
|
|
96
|
+
it's the architectural reason the factory exists).
|
|
97
|
+
|
|
98
|
+
The factory boundary is also the seam where we'd later wire
|
|
99
|
+
`@tanstack/store` if we wanted to — the API shape is signal-compatible
|
|
100
|
+
already.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Non-VTEX platforms
|
|
105
|
+
|
|
106
|
+
Sites that target Wake / Shopify / VNDA / Linx / Nuvemshop still need a
|
|
107
|
+
hook surface that AddToCartButtons can consume. Until each platform has
|
|
108
|
+
its own factory in `@decocms/apps`, scaffold a no-op shim:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// src/hooks/useCart.ts (custom platform)
|
|
112
|
+
import { signal } from "@decocms/start/sdk/signal";
|
|
113
|
+
|
|
114
|
+
const cart = signal<unknown>(null);
|
|
115
|
+
const loading = signal(false);
|
|
116
|
+
|
|
117
|
+
export function useCart() {
|
|
118
|
+
return {
|
|
119
|
+
cart,
|
|
120
|
+
loading,
|
|
121
|
+
async getCart() {
|
|
122
|
+
// TODO: call your platform's cart API via ~/server/invoke
|
|
123
|
+
return null;
|
|
124
|
+
},
|
|
125
|
+
async addItems(_items: unknown[]) {
|
|
126
|
+
// TODO
|
|
127
|
+
},
|
|
128
|
+
async updateItems(_items: unknown[]) {
|
|
129
|
+
// TODO
|
|
130
|
+
},
|
|
131
|
+
setCart(next: unknown) {
|
|
132
|
+
cart.value = next;
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default useCart;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`@decocms/start/sdk/signal` (re-exported via `~/sdk/signal` after
|
|
141
|
+
migration) gives you the same `.value` getter/setter the factory uses,
|
|
142
|
+
so AddToCart UI components don't need to know which platform is wired.
|
|
143
|
+
|
|
144
|
+
The migration template's `generateGenericUseCart()` emits this stub when
|
|
145
|
+
`--platform` is `custom` (or any non-VTEX value).
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Migrating off the manual approach (pre-W12 sites)
|
|
150
|
+
|
|
151
|
+
If your site contains files like `src/lib/vtex-cart-server.ts` or hand-rolled `createServerFn` blocks for VTEX endpoints in `src/hooks/useCart.ts`, the post-cleanup audit will not auto-fix them — the manual code accumulated 6+ months of site-specific edits and the per-site judgment call about "what's still needed?" is real. The mechanical part:
|
|
152
|
+
|
|
153
|
+
1. Replace the entire body of `src/hooks/useCart.ts` with the 5-line factory shim above.
|
|
154
|
+
2. Delete `src/lib/vtex-cart-server.ts` (the migration template's `src/server/invoke.gen.ts` provides equivalent server functions wrapping `@decocms/apps/vtex/actions/checkout`).
|
|
155
|
+
3. Verify `src/server/invoke.ts` exports the proxy shape the factory needs (cart actions under `invoke.vtex.actions`). The migration template scaffolds this; older sites may need to add the missing entries by hand.
|
|
156
|
+
4. Run `npm run typecheck` — TypeScript will surface any callsites that referenced removed helpers (e.g. local `getOrCreateCart` shims).
|
|
157
|
+
5. Repeat for `useUser` / `useWishlist`.
|
|
158
|
+
|
|
159
|
+
For `useUser`, the analog of step 2 is removing any local `currentUser` /
|
|
160
|
+
`getUser` server functions in favor of `@decocms/apps/vtex/loaders/user`
|
|
161
|
+
exposed via `invoke.vtex.loaders.user()`. For `useWishlist`, the
|
|
162
|
+
canonical surface is `@decocms/apps/vtex/{actions,loaders}/wishlist`.
|
|
163
|
+
|
|
164
|
+
If you find yourself wanting to add behaviour to a factory (extra cart
|
|
165
|
+
actions, custom analytics events) rather than ripping out the factory and going back to a manual hook:
|
|
166
|
+
|
|
167
|
+
- **Extra read paths** → expose a new loader from
|
|
168
|
+
`@decocms/apps/vtex/loaders/*`, register it in `~/server/invoke.ts`,
|
|
169
|
+
call from your component (the factory doesn't need to know).
|
|
170
|
+
- **Extra write paths** → ditto for `@decocms/apps/vtex/actions/*`.
|
|
171
|
+
- **Cross-cutting business logic** (e.g. PIX-specific offer pricing) →
|
|
172
|
+
this is the kind of seam that justifies a parallel `useOffer` factory.
|
|
173
|
+
Talk to the apps maintainers; opening up a factory's plugin slots is a
|
|
174
|
+
one-PR change in apps, not a per-site rewrite.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Related
|
|
179
|
+
|
|
180
|
+
- `scripts/migrate/templates/hooks.ts` — the template that emits the
|
|
181
|
+
shims above.
|
|
182
|
+
- `apps-start/vtex/hooks/createUseCart.ts` /
|
|
183
|
+
`createUseUser.ts` / `createUseWishlist.ts` — the factories
|
|
184
|
+
themselves; each docstring is the authoritative API reference.
|
|
185
|
+
- `references/platform-hooks/README.md` — historical reference for the
|
|
186
|
+
pre-W12 manual approach (kept for sites that haven't migrated yet).
|
|
@@ -18,8 +18,10 @@ npx -p @decocms/start deco-post-cleanup
|
|
|
18
18
|
|
|
19
19
|
# Auto-apply mechanical fixes for the safe rules, then report what's left.
|
|
20
20
|
# Safe rules: dead-lib-shims, dead-runtime-shim, local-widgets-types,
|
|
21
|
-
# vtex-shim-regression (swap subset), obsolete-vite-plugins
|
|
22
|
-
#
|
|
21
|
+
# vtex-shim-regression (swap subset), obsolete-vite-plugins,
|
|
22
|
+
# local-framework-duplicate (auto-fixable subset of the registry).
|
|
23
|
+
# Other rules — and the warn-only entries of local-framework-duplicate —
|
|
24
|
+
# stay detect-only. They require human judgment.
|
|
23
25
|
npx -p @decocms/start deco-post-cleanup --fix
|
|
24
26
|
|
|
25
27
|
# Combine for CI: auto-fix safe rules, fail (exit 2) if warnings remain.
|
|
@@ -29,14 +31,16 @@ npx -p @decocms/start deco-post-cleanup --fix --strict
|
|
|
29
31
|
npx -p @decocms/start deco-post-cleanup --json
|
|
30
32
|
```
|
|
31
33
|
|
|
32
|
-
The audit covers all
|
|
34
|
+
The audit covers all 9 rules below and prints the exact file path +
|
|
33
35
|
suggested fix for each finding. With `--fix`, the safe rules
|
|
34
36
|
auto-apply: `rm` for dead files, regex-anchored import rewrites for
|
|
35
37
|
shadowed shims (`local-widgets-types`, `dead-runtime-shim`), the swap
|
|
36
|
-
subset of `vtex-shim-regression`,
|
|
37
|
-
inline plugin literals from `vite.config.ts
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
subset of `vtex-shim-regression`, JS-aware removal of obsolete
|
|
39
|
+
inline plugin literals from `vite.config.ts`, and rewrite-imports +
|
|
40
|
+
delete for the auto-fixable subset of `local-framework-duplicate`
|
|
41
|
+
(see § 8). The output explicitly tags rules that require manual work
|
|
42
|
+
as `(0 fixed, manual)`, so you always know what's left after auto-fix
|
|
43
|
+
runs.
|
|
40
44
|
|
|
41
45
|
Real-world signal: on baggagio, `--fix` produced a byte-identical
|
|
42
46
|
diff to the manual cleanup PR a human had just made (45 files,
|
|
@@ -398,7 +402,58 @@ In `--strict` mode any residue exits 2 — wire that into CI once a
|
|
|
398
402
|
site has finished its HTMX rewrite to prevent regressions sneaking
|
|
399
403
|
back in via copy-paste from a Fresh source.
|
|
400
404
|
|
|
401
|
-
## 8.
|
|
405
|
+
## 8. Drop site-local copies of framework code (`local-framework-duplicate`)
|
|
406
|
+
|
|
407
|
+
The audit's `local-framework-duplicate` rule encodes a registry of
|
|
408
|
+
files we expect sites to NOT carry locally because the canonical
|
|
409
|
+
implementation already ships in `@decocms/start`. New entries go in
|
|
410
|
+
`scripts/migrate/post-cleanup/rules.ts → FRAMEWORK_DUPLICATES`.
|
|
411
|
+
|
|
412
|
+
Two kinds of finding:
|
|
413
|
+
|
|
414
|
+
| Kind | Auto-fix | Example | What you do |
|
|
415
|
+
|---|---|---|---|
|
|
416
|
+
| **Pure dup** (`safeToAutoFix: true`) | YES | `src/sdk/clx.ts` matches `@decocms/start/sdk/clx` byte-for-byte | `--fix` rewrites every `from "~/sdk/clx"` to `from "@decocms/start/sdk/clx"` and deletes the file. Zero behavior change. |
|
|
417
|
+
| **Partial overlap** (`safeToAutoFix: false`) | NO | `src/sdk/useSendEvent.ts` (typed) overlaps `@decocms/start/sdk/analytics → useSendEvent` (permissive) | The rule emits a `warning` with a `reason` explaining the manual judgement: widen the framework export, accept type loss, or fork on purpose. Human picks. |
|
|
418
|
+
|
|
419
|
+
### How the rule fires
|
|
420
|
+
|
|
421
|
+
The site file must match every regex in `contentSignature` before
|
|
422
|
+
the rule treats it as the framework dup. This is conservative on
|
|
423
|
+
purpose — sites that genuinely forked the helper (added platform
|
|
424
|
+
logic, wrapped in something else) are skipped automatically.
|
|
425
|
+
|
|
426
|
+
### Current registry
|
|
427
|
+
|
|
428
|
+
| Site path | Canonical | Auto-fix? | Reason / status |
|
|
429
|
+
|---|---|---|---|
|
|
430
|
+
| `src/sdk/clx.ts` | `@decocms/start/sdk/clx` | yes | Identical implementation; baggagio's extra `clsx` alias has zero callers. |
|
|
431
|
+
| `src/sdk/useSendEvent.ts` | `@decocms/start/sdk/analytics` | no | Site copy uses `<E extends AnalyticsEvent>` generic; framework export is permissive. Replace 1:1 = type-safety loss. Either widen the framework first or accept the loss. |
|
|
432
|
+
| `src/matchers/location.ts` | `@decocms/start/matchers/builtins` | no | Framework's `registerBuiltinMatchers()` ships a richer location matcher (`request.cf` first, geo cookies fallback, headers fallback) plus 10 sibling matchers. Adopting changes behaviour — verify country-name lookup parity, swap `setup.ts`'s `customMatchers` entry. |
|
|
433
|
+
|
|
434
|
+
### Adding a new entry
|
|
435
|
+
|
|
436
|
+
When you spot a site carrying its own copy of code that lives in
|
|
437
|
+
`@decocms/start`, add an entry to `FRAMEWORK_DUPLICATES`:
|
|
438
|
+
|
|
439
|
+
```ts
|
|
440
|
+
{
|
|
441
|
+
id: "<short-stable-id>",
|
|
442
|
+
sitePath: "src/<path>.ts",
|
|
443
|
+
canonicalImport: "@decocms/start/<path>",
|
|
444
|
+
contentSignature: [/<regex 1>/, /<regex 2>/],
|
|
445
|
+
safeToAutoFix: true | false,
|
|
446
|
+
reason: "<required when not safeToAutoFix>",
|
|
447
|
+
description: "<one-liner used in finding message>",
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Per **D4** in the migration tooling policy, the framework promotion
|
|
452
|
+
itself happens at 3+ sites. This registry is the *enforcement* layer
|
|
453
|
+
once promoted: every other site picks up the convergence
|
|
454
|
+
automatically the next time `deco-post-cleanup --fix` runs.
|
|
455
|
+
|
|
456
|
+
## 9. Search for orphan `TODO: move into framework` comments
|
|
402
457
|
|
|
403
458
|
Real sites accumulate `TODO` comments like `// TODO: move into decoVitePlugin
|
|
404
459
|
in next @decocms/start release`. These are roadmap items the framework
|
|
@@ -415,7 +470,7 @@ For each hit, decide:
|
|
|
415
470
|
|
|
416
471
|
## Verification checklist
|
|
417
472
|
|
|
418
|
-
After completing 1-
|
|
473
|
+
After completing 1-9:
|
|
419
474
|
|
|
420
475
|
- [ ] `npm run typecheck` baseline matches pre-cleanup count (no new errors)
|
|
421
476
|
- [ ] `npm run dev` starts and `/`, `/some-pdp/p`, `/s?q=foo` all render
|