@decocms/start 2.14.0 → 2.16.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/references/post-migration-cleanup.md +103 -3
- package/.cursor/rules/migration-tooling-policy.mdc +111 -0
- package/CLAUDE.md +4 -0
- package/MIGRATION_TOOLING_PLAN.md +891 -0
- package/package.json +1 -1
- package/scripts/migrate/post-cleanup/rules.ts +121 -3
- package/scripts/migrate/post-cleanup/runner.test.ts +102 -0
- package/scripts/migrate/templates/lib-utils.test.ts +48 -0
- package/scripts/migrate/templates/lib-utils.ts +51 -12
|
@@ -168,16 +168,116 @@ one imported symbol is a real silent stub (returns `null` / `{}` / `[]`
|
|
|
168
168
|
alongside stubs (e.g. a `parseCookie` cookie parser, a `fetchSafe`
|
|
169
169
|
wrapper) no longer create noise.
|
|
170
170
|
|
|
171
|
-
The audit's finding names the exact stub symbols
|
|
171
|
+
The audit's finding names the exact stub symbols **and emits per-symbol
|
|
172
|
+
fix guidance**, e.g.
|
|
172
173
|
|
|
173
174
|
```
|
|
174
175
|
[WARNING] src/loaders/search/x.ts — Imports stub-only symbols from
|
|
175
176
|
vtex-transform (toProduct); vtex-segment (getSegmentFromBag) —
|
|
176
177
|
runtime is silently stubbed
|
|
177
|
-
fix:
|
|
178
|
-
|
|
178
|
+
fix: toProduct → @decocms/apps/vtex/utils/transform (1:1 import swap)
|
|
179
|
+
— canonical signature is `toProduct(product, sku, level, options)`;
|
|
180
|
+
1-arg call sites need to expand args first | getSegmentFromBag →
|
|
181
|
+
call-site refactor: read cookies via `request.headers.get('cookie')`
|
|
182
|
+
then call `buildSegmentFromCookies()` from
|
|
183
|
+
'@decocms/apps/vtex/utils/segment'.
|
|
179
184
|
```
|
|
180
185
|
|
|
186
|
+
JSON consumers can read structured guidance from `meta.fixHints`:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"rule": "vtex-shim-regression",
|
|
191
|
+
"meta": {
|
|
192
|
+
"stubsBySim": { "vtex-transform": ["toProduct"], "vtex-segment": ["getSegmentFromBag"] },
|
|
193
|
+
"fixHints": {
|
|
194
|
+
"toProduct": { "kind": "swap", "canonical": "@decocms/apps/vtex/utils/transform", "note": "..." },
|
|
195
|
+
"getSegmentFromBag": { "kind": "refactor", "note": "..." }
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Canonical replacement table
|
|
202
|
+
|
|
203
|
+
| Stub symbol | Kind | Canonical / fix |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `toProduct` | swap | `@decocms/apps/vtex/utils/transform.toProduct` — note canonical signature is `(product, sku, level, options)`; 1-arg call sites need to expand args |
|
|
206
|
+
| `withSegmentCookie` | swap | `@decocms/apps/vtex/utils/segment.withSegmentCookie` — note canonical signature is `(segment, headers?)` |
|
|
207
|
+
| `getSegmentFromBag` | refactor | read cookies via `request.headers.get('cookie')`, then `buildSegmentFromCookies()` from `@decocms/apps/vtex/utils/segment` |
|
|
208
|
+
| `getISCookiesFromBag` | refactor | extract IS cookies from `request.headers.get('cookie')` directly — no canonical helper, the bag-based mechanism doesn't exist on TanStack Start |
|
|
209
|
+
|
|
210
|
+
Symbols not in the table get the generic guidance ("repoint to
|
|
211
|
+
`@decocms/apps/vtex/...` or `apps/commerce/utils/...`") — when you find
|
|
212
|
+
a new one worth pinning down, add it to `STUB_FIX_HINTS` in
|
|
213
|
+
[`scripts/migrate/post-cleanup/rules.ts`](https://github.com/decocms/deco-start/blob/main/scripts/migrate/post-cleanup/rules.ts).
|
|
214
|
+
|
|
215
|
+
### Recipe: expanding 1-arg `toProduct(p)` call sites
|
|
216
|
+
|
|
217
|
+
Two real-world patterns surface, requiring different fixes:
|
|
218
|
+
|
|
219
|
+
**Pattern A — call site already passes 4 args under `as any`** (e.g.
|
|
220
|
+
`smartShelfForYou.ts` on casaevideo): the dev wrote the call for
|
|
221
|
+
canonical, the import pointed at the stub. Fix is **import-only**:
|
|
222
|
+
|
|
223
|
+
```diff
|
|
224
|
+
-import { toProduct } from "~/lib/vtex-transform";
|
|
225
|
+
+import { toProduct } from "@decocms/apps/vtex/utils/transform";
|
|
226
|
+
|
|
227
|
+
const normalizedProducts = rawProducts.data.map((p: VTEXProduct) =>
|
|
228
|
+
(toProduct as any)(p, p.items?.[0], 0, {
|
|
229
|
+
baseUrl: baseURL,
|
|
230
|
+
priceCurrency: "BRL",
|
|
231
|
+
}),
|
|
232
|
+
);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The `as any` cast may stay if local `~/types/vtex.Product` and
|
|
236
|
+
canonical `LegacyProductVTEX | ProductVTEX` differ structurally — that's
|
|
237
|
+
a separate refactor.
|
|
238
|
+
|
|
239
|
+
**Pattern B — call site uses true 1-arg form** (e.g.
|
|
240
|
+
`intelligenseSearch.ts` on casaevideo): the dev relied on the stub's
|
|
241
|
+
identity-cast behaviour. Fix is to **expand the call** mirroring the
|
|
242
|
+
canonical pattern in
|
|
243
|
+
[`apps-start/vtex/loaders/autocomplete.ts`](https://github.com/decocms/apps-start/blob/main/vtex/loaders/autocomplete.ts):
|
|
244
|
+
|
|
245
|
+
```diff
|
|
246
|
+
-import { toProduct } from "~/lib/vtex-transform";
|
|
247
|
+
+import { pickSku, toProduct } from "@decocms/apps/vtex/utils/transform";
|
|
248
|
+
|
|
249
|
+
const baseURL = new URL(req.url).origin;
|
|
250
|
+
return {
|
|
251
|
+
searches,
|
|
252
|
+
- products: (products ?? []).map((p) => toProduct(p)).slice(0, count),
|
|
253
|
+
+ products: (products ?? []).slice(0, count).map((p: any) => {
|
|
254
|
+
+ const sku = pickSku(p);
|
|
255
|
+
+ return toProduct(p, sku, 0, { baseUrl: baseURL, priceCurrency: "BRL" });
|
|
256
|
+
+ }),
|
|
257
|
+
};
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`pickSku` handles the IS-shape SKU selection; without it, downstream
|
|
261
|
+
fields like `productID`, `gtin`, `additionalProperty[]` come back
|
|
262
|
+
empty.
|
|
263
|
+
|
|
264
|
+
**Pattern C — keep the stub deliberately**: rare, but valid when the
|
|
265
|
+
upstream API already returns canonical `Product[]` shape and the call
|
|
266
|
+
is purely a type-narrowing cast. Replace with a typed cast at the
|
|
267
|
+
boundary instead of importing a stub:
|
|
268
|
+
|
|
269
|
+
```diff
|
|
270
|
+
-import { toProduct } from "~/lib/vtex-transform";
|
|
271
|
+
+import type { Product } from "@decocms/apps/commerce/types";
|
|
272
|
+
|
|
273
|
+
-products: (products ?? []).map((p) => toProduct(p)).slice(0, count),
|
|
274
|
+
+products: ((products ?? []) as Product[]).slice(0, count),
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
This silences the audit (the stub import is gone) without changing
|
|
278
|
+
behaviour. Only do this if you've **verified** the upstream payload is
|
|
279
|
+
already schema.org-shaped.
|
|
280
|
+
|
|
181
281
|
Manual sweep (still useful if you don't have the audit handy):
|
|
182
282
|
|
|
183
283
|
```bash
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Constitutional decisions for the deco-start migration-tooling effort (D1–D5, priorities, process). Always loaded.
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migration Tooling Policy
|
|
7
|
+
|
|
8
|
+
Decisions for `@decocms/start` + `@decocms/apps` + migration scripts/skills.
|
|
9
|
+
Authority: `MIGRATION_TOOLING_PLAN.md` in this repo. This rule is a quick-load
|
|
10
|
+
summary; always defer to the plan when they conflict.
|
|
11
|
+
|
|
12
|
+
## Constitutional principles
|
|
13
|
+
|
|
14
|
+
1. **Design for 100 sites, not 3.** When the surface of an abstraction is
|
|
15
|
+
well-understood, ship it. Don't defer waiting for "more signal" — design
|
|
16
|
+
for the projection. When the surface is *not* understood, *decide*
|
|
17
|
+
explicitly (write a D-record like D1–D5), don't ship fast.
|
|
18
|
+
2. **Strict over flexible.** No support layers, no soft drift, no
|
|
19
|
+
fork-runtime adapters. Every fork divergence becomes either a PR back to
|
|
20
|
+
canonical or visible local debt.
|
|
21
|
+
3. **Audit is the safety net.** Anything we can't auto-fix becomes a flagged
|
|
22
|
+
finding. The gap between "detect" and "fix" is the next thing to close,
|
|
23
|
+
not a permanent state.
|
|
24
|
+
4. **PR-only, no direct main, no deploys.** Every change goes through
|
|
25
|
+
review. Even policy/plan changes (this rule).
|
|
26
|
+
|
|
27
|
+
## Decisions (signed off 2026-05-01)
|
|
28
|
+
|
|
29
|
+
### D1 — Apps forks: force convergence
|
|
30
|
+
All sites consume `@decocms/apps` from canonical. Site-specific
|
|
31
|
+
customizations live in `src/apps/local/`. Forking is **not supported** by
|
|
32
|
+
the framework — sites that need framework-level changes either PR to
|
|
33
|
+
canonical, or fork independently and own the consequence.
|
|
34
|
+
|
|
35
|
+
**Agent behavior**: never write a "fork support layer". When auditing a
|
|
36
|
+
site, treat any non-canonical apps import as a finding; recommend
|
|
37
|
+
PR-to-canonical or move-to-`src/apps/local/`.
|
|
38
|
+
|
|
39
|
+
### D2 — HTMX: rewrite on migration
|
|
40
|
+
HTMX is fully rewritten to React idioms (state, effects, server functions,
|
|
41
|
+
mutations) during migration. There is **no HTMX runtime** in
|
|
42
|
+
`@decocms/start`. The migration ships codemods for the common patterns
|
|
43
|
+
and skill recipes for the long tail.
|
|
44
|
+
|
|
45
|
+
**Agent behavior**: never propose an HTMX adapter or `@decocms/start/htmx`
|
|
46
|
+
package. When facing HTMX patterns, reach for codemods first, skill
|
|
47
|
+
recipes second, pattern catalog third.
|
|
48
|
+
|
|
49
|
+
### D3 — Stub generation: throw at runtime
|
|
50
|
+
Migration-time stubs (`src/lib/vtex-*`, `src/lib/http-utils.ts`, etc.) must
|
|
51
|
+
**throw at runtime** with a clear message pointing at the canonical
|
|
52
|
+
replacement, not return identity casts or empty objects. This forces:
|
|
53
|
+
|
|
54
|
+
- The audit's `--fix` to cover swap cases (no permanent detect-only state).
|
|
55
|
+
- Skill recipes to keep up with stub generation.
|
|
56
|
+
|
|
57
|
+
**Agent behavior**: when adding or modifying a generated stub template,
|
|
58
|
+
the body must throw with a message including (a) what the stub stands in
|
|
59
|
+
for, (b) the canonical replacement, (c) a pointer to the relevant skill
|
|
60
|
+
section. Silent stubs are a regression.
|
|
61
|
+
|
|
62
|
+
### D4 — Site-local apps: local by default, promote at 3
|
|
63
|
+
Site-specific apps (extensions, custom commerce integrations) live in
|
|
64
|
+
`src/apps/local/` by default. Promotion to `@decocms/apps` happens when
|
|
65
|
+
**3 or more sites** use the same extension.
|
|
66
|
+
|
|
67
|
+
**Agent behavior**: don't preemptively promote single-consumer code.
|
|
68
|
+
Conversely, don't accept "wait for more signal" as a dodge — when you see
|
|
69
|
+
the third consumer, promote.
|
|
70
|
+
|
|
71
|
+
### D5 — Failed migrations: rm -rf and re-run
|
|
72
|
+
There is **no `--restart` mode**. A half-migrated site repo is a throwaway:
|
|
73
|
+
delete it and re-run `deco-migrate` from scratch on the latest tooling.
|
|
74
|
+
Failure modes get documented in skills, not encoded as escape hatches.
|
|
75
|
+
|
|
76
|
+
**Agent behavior**: when a migration goes sideways, propose deletion +
|
|
77
|
+
re-run, not in-place repair. Add the failure mode to the skill.
|
|
78
|
+
|
|
79
|
+
## Priority order
|
|
80
|
+
|
|
81
|
+
Work proceeds in this order. Higher priorities don't block on lower ones,
|
|
82
|
+
but lower ones don't ship before the higher ones are at least scoped:
|
|
83
|
+
|
|
84
|
+
1. **Framework changes** (`@decocms/start` + `@decocms/apps`) — fix the
|
|
85
|
+
foundation first. New factories, new audit rules, new framework
|
|
86
|
+
primitives. Without these, scripts have nothing to migrate *to*.
|
|
87
|
+
2. **Migration scripts + skills** — make migration to the latest
|
|
88
|
+
`@decocms/start` + `@decocms/apps` automated. Codemods, audit `--fix`
|
|
89
|
+
rules, skill recipes.
|
|
90
|
+
3. **Migrate als** — first real htmx-heavy site. Validates the htmx
|
|
91
|
+
sub-track end-to-end.
|
|
92
|
+
4. **Update existing TanStack sites to latest** — open PRs against
|
|
93
|
+
casaevideo, baggagio, future sites bumping `@decocms/start` and
|
|
94
|
+
`@decocms/apps`, applying audit `--fix`, cleaning up to reflect
|
|
95
|
+
current best practices.
|
|
96
|
+
|
|
97
|
+
Out-of-band work (incident response, urgent prod fixes) bypasses this
|
|
98
|
+
order — but only if explicitly identified as urgent.
|
|
99
|
+
|
|
100
|
+
## Process directives
|
|
101
|
+
|
|
102
|
+
- All work goes through PR review on a feature branch (`feat/`, `fix/`,
|
|
103
|
+
`chore/`, `docs/`). No exceptions.
|
|
104
|
+
- Conventional Commits in English for `decocms/*` repos; PT-BR for
|
|
105
|
+
storefront site repos.
|
|
106
|
+
- Plan updates (`MIGRATION_TOOLING_PLAN.md`) ship with the work they
|
|
107
|
+
describe, in the same PR or a follow-up. The plan is the single source
|
|
108
|
+
of truth; this rule is its boot loader.
|
|
109
|
+
- When reading a section of the plan or a skill, prefer the plan or skill
|
|
110
|
+
over your memory of past conversations.
|
|
111
|
+
- Do not run `deco-deploy` or any deploy command from agent flows.
|
package/CLAUDE.md
CHANGED
|
@@ -8,6 +8,10 @@ Guidance for AI assistants working with `@decocms/start`.
|
|
|
8
8
|
|
|
9
9
|
**Not a storefront itself** — this is the npm package that storefronts depend on.
|
|
10
10
|
|
|
11
|
+
## Migration tooling policy (constitutional)
|
|
12
|
+
|
|
13
|
+
This repo also hosts the migration scripts + skills that move Deco storefronts from Fresh/Deno to TanStack Start. The work is governed by signed-off architectural decisions (D1–D5) and a strict priority order — see [`.cursor/rules/migration-tooling-policy.mdc`](./.cursor/rules/migration-tooling-policy.mdc) (always-loaded) and [`MIGRATION_TOOLING_PLAN.md`](./MIGRATION_TOOLING_PLAN.md) (full record). Defer to the plan when in doubt.
|
|
14
|
+
|
|
11
15
|
## Tech Stack
|
|
12
16
|
|
|
13
17
|
- Runtime: Cloudflare Workers (Node compat)
|