@decocms/blocks-cli 7.5.0 → 7.5.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 (37) hide show
  1. package/package.json +3 -3
  2. package/scripts/generate-invoke.ts +10 -0
  3. package/scripts/generate-schema.test.ts +4 -4
  4. package/scripts/generate-sections.test.ts +6 -6
  5. package/scripts/migrate/analyzers/loader-inventory.ts +1 -1
  6. package/scripts/migrate/phase-analyze.ts +3 -3
  7. package/scripts/migrate/phase-cleanup.ts +29 -23
  8. package/scripts/migrate/phase-report.ts +7 -7
  9. package/scripts/migrate/phase-scaffold.ts +4 -4
  10. package/scripts/migrate/phase-transform.ts +1 -1
  11. package/scripts/migrate/phase-verify.ts +6 -5
  12. package/scripts/migrate/post-cleanup/rules.ts +55 -44
  13. package/scripts/migrate/post-cleanup/runner.test.ts +58 -34
  14. package/scripts/migrate/templates/cache-config.ts +4 -4
  15. package/scripts/migrate/templates/commerce-loaders.ts +10 -10
  16. package/scripts/migrate/templates/cursor-rules.test.ts +6 -0
  17. package/scripts/migrate/templates/cursor-rules.ts +12 -11
  18. package/scripts/migrate/templates/hooks.test.ts +7 -7
  19. package/scripts/migrate/templates/hooks.ts +10 -10
  20. package/scripts/migrate/templates/lib-utils.test.ts +2 -2
  21. package/scripts/migrate/templates/lib-utils.ts +4 -4
  22. package/scripts/migrate/templates/no-legacy-packages.test.ts +147 -0
  23. package/scripts/migrate/templates/package-json.ts +24 -10
  24. package/scripts/migrate/templates/routes.ts +8 -10
  25. package/scripts/migrate/templates/sdk-gen.ts +1 -1
  26. package/scripts/migrate/templates/section-loaders.ts +7 -7
  27. package/scripts/migrate/templates/server-entry.ts +37 -37
  28. package/scripts/migrate/templates/setup.ts +6 -6
  29. package/scripts/migrate/templates/types-gen.ts +2 -2
  30. package/scripts/migrate/templates/ui-components.ts +2 -2
  31. package/scripts/migrate/templates/vite-config.ts +12 -3
  32. package/scripts/migrate/transforms/fresh-apis.ts +5 -5
  33. package/scripts/migrate/transforms/imports.ts +49 -43
  34. package/scripts/migrate/transforms/section-conventions.ts +1 -1
  35. package/scripts/migrate/types.ts +1 -1
  36. package/scripts/migrate-post-cleanup.ts +8 -8
  37. package/scripts/migrate.ts +11 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/blocks-cli",
3
- "version": "7.5.0",
3
+ "version": "7.5.2",
4
4
  "type": "module",
5
5
  "description": "Deco codegen (generate-blocks, generate-schema, generate-invoke) and Fresh-to-TanStack migration tooling",
6
6
  "repository": {
@@ -34,9 +34,9 @@
34
34
  "lint:unused": "knip"
35
35
  },
36
36
  "dependencies": {
37
- "@decocms/blocks": "7.5.0",
37
+ "@decocms/blocks": "7.5.2",
38
38
  "ts-morph": "^27.0.0",
39
- "tsx": "^4.19.0"
39
+ "tsx": "^4.22.5"
40
40
  },
41
41
  "devDependencies": {
42
42
  "knip": "^5.86.0",
@@ -21,6 +21,16 @@
21
21
  * compiled and shipped as part of the site's application code, so it lives
22
22
  * in `src/` alongside the code it's compiled with, not in `.deco/`.
23
23
  *
24
+ * This is empirically load-bearing, not taste (tested 2026-07-08 on a real
25
+ * site): with the file moved to `.deco/invoke.gen.ts`, the CLIENT half of
26
+ * the Start compiler works fine (stubs generated, IDs re-derived from the
27
+ * new path), but the SERVER half cannot resolve the split module back to an
28
+ * executable handler — every `/_serverFn/...` call returns an unhandled 500
29
+ * with no logged stack, i.e. every cart/session/MasterData action dies.
30
+ * Same site, file back under `src/`: identical RPC probe returns 200 with a
31
+ * real VTEX orderForm. Do not move this default without re-running that
32
+ * round-trip test end to end.
33
+ *
24
34
  * Usage (from site root):
25
35
  * npx tsx node_modules/@decocms/blocks-cli/scripts/generate-invoke.ts
26
36
  *
@@ -97,7 +97,7 @@ describe("typeToJsonSchema with an unresolvable widget alias import", () => {
97
97
  type: "string",
98
98
  format: "color",
99
99
  });
100
- });
100
+ }, 30_000);
101
101
  });
102
102
 
103
103
  // ---------------------------------------------------------------------------
@@ -160,7 +160,7 @@ describe("generate-schema default output path (.deco/)", () => {
160
160
  expect(fs.existsSync(newDefault)).toBe(true);
161
161
  const meta = JSON.parse(fs.readFileSync(newDefault, "utf-8"));
162
162
  expect(meta.manifest.blocks.sections).toHaveProperty("site/sections/Hero.tsx");
163
- });
163
+ }, 30_000);
164
164
 
165
165
  it("warns once to stderr naming both paths when the OLD default file exists and no --out is passed, but still writes the NEW default", () => {
166
166
  const oldDefaultDir = path.join(tmpDir, "src", "server", "admin");
@@ -176,7 +176,7 @@ describe("generate-schema default output path (.deco/)", () => {
176
176
 
177
177
  const newDefault = path.join(tmpDir, ".deco", "meta.gen.json");
178
178
  expect(fs.existsSync(newDefault)).toBe(true);
179
- });
179
+ }, 30_000);
180
180
 
181
181
  it("does not warn when an explicit --out is passed, even if the OLD default file exists", () => {
182
182
  const oldDefaultDir = path.join(tmpDir, "src", "server", "admin");
@@ -189,5 +189,5 @@ describe("generate-schema default output path (.deco/)", () => {
189
189
 
190
190
  expect(stderr).not.toContain("Generator default output moved");
191
191
  expect(fs.existsSync(explicitOut)).toBe(true);
192
- });
192
+ }, 30_000);
193
193
  });
@@ -71,7 +71,7 @@ describe("generate-sections walkDir exclusions", () => {
71
71
  expect(generated).not.toContain("Hero.test.tsx");
72
72
  expect(generated).not.toContain("Hero.stories.tsx");
73
73
  expect(generated).not.toContain("sections.gen.ts");
74
- });
74
+ }, 30_000);
75
75
  });
76
76
 
77
77
  describe("generate-sections default output path (.deco/)", () => {
@@ -101,7 +101,7 @@ describe("generate-sections default output path (.deco/)", () => {
101
101
  expect(fs.readFileSync(newDefault, "utf-8")).toContain("site/sections/Hero.tsx");
102
102
  // No legacy file present, so no warning is expected.
103
103
  expect(stderr).not.toContain("Generator default output moved");
104
- });
104
+ }, 30_000);
105
105
 
106
106
  it("warns once to stderr naming both paths when the OLD default file exists and no --out-file is passed, but still writes the NEW default", () => {
107
107
  const oldDefaultDir = path.join(tmpDir, "src", "server", "cms");
@@ -118,7 +118,7 @@ describe("generate-sections default output path (.deco/)", () => {
118
118
  const newDefault = path.join(tmpDir, ".deco", "sections.gen.ts");
119
119
  expect(fs.existsSync(newDefault)).toBe(true);
120
120
  expect(fs.readFileSync(newDefault, "utf-8")).toContain("site/sections/Hero.tsx");
121
- });
121
+ }, 30_000);
122
122
 
123
123
  it("does not warn when an explicit --out-file is passed, even if the OLD default file exists", () => {
124
124
  const oldDefaultDir = path.join(tmpDir, "src", "server", "cms");
@@ -131,7 +131,7 @@ describe("generate-sections default output path (.deco/)", () => {
131
131
 
132
132
  expect(stderr).not.toContain("Generator default output moved");
133
133
  expect(fs.existsSync(explicitOut)).toBe(true);
134
- });
134
+ }, 30_000);
135
135
  });
136
136
 
137
137
  describe("generate-sections --registry", () => {
@@ -186,7 +186,7 @@ describe("generate-sections --registry", () => {
186
186
  expect(generated).toContain(
187
187
  `"./sections/Nested/Promo.tsx": () => import("${expectedImportPath(promoPath)}")`,
188
188
  );
189
- });
189
+ }, 30_000);
190
190
 
191
191
  it("does not emit sectionImports without the --registry flag", () => {
192
192
  fs.writeFileSync(
@@ -203,7 +203,7 @@ describe("generate-sections --registry", () => {
203
203
 
204
204
  const generated = fs.readFileSync(outFile, "utf-8");
205
205
  expect(generated).not.toContain("sectionImports");
206
- });
206
+ }, 30_000);
207
207
 
208
208
  it("emits a doc comment that does not self-terminate early, and the resulting file is importable (regression: a literal `**/` inside the emitted /** */ comment used to close it prematurely, leaving prose as bare statements and making every --registry output invalid TypeScript)", () => {
209
209
  const heroPath = path.join(sectionsDir, "Hero.tsx");
@@ -3,7 +3,7 @@ import * as path from "node:path";
3
3
  import type { MigrationContext, LoaderInfo, Platform } from "../types";
4
4
  import { log } from "../types";
5
5
 
6
- /** Well-known loaders that map directly to @decocms/apps equivalents */
6
+ /** Well-known loaders that map directly to @decocms/apps-* equivalents */
7
7
  const APPS_EQUIVALENTS: Record<string, string> = {
8
8
  "loaders/availableIcons.ts": "", // deleted
9
9
  "loaders/icons.ts": "", // deleted
@@ -255,7 +255,7 @@ function decideAction(
255
255
  if (SDK_DELETE.has(relPath)) {
256
256
  return {
257
257
  action: "delete",
258
- notes: "Use framework equivalent from @decocms/start or @decocms/apps",
258
+ notes: "Use framework equivalent from @decocms/blocks or @decocms/apps-vtex",
259
259
  };
260
260
  }
261
261
 
@@ -263,13 +263,13 @@ function decideAction(
263
263
  if (COMPONENT_DELETE.has(relPath)) {
264
264
  return {
265
265
  action: "delete",
266
- notes: "Scaffolded fresh from @decocms/apps re-exports",
266
+ notes: "Scaffolded fresh from @decocms/blocks re-exports",
267
267
  };
268
268
  }
269
269
 
270
270
  // cart/ directory → delete
271
271
  if (relPath.startsWith("sdk/cart/")) {
272
- return { action: "delete", notes: "Use @decocms/apps cart hooks" };
272
+ return { action: "delete", notes: "Use @decocms/apps-vtex cart hooks" };
273
273
  }
274
274
 
275
275
  // Non-platform cleanup is done in analyze() post-processing (needs ctx.platform)
@@ -971,12 +971,15 @@ function upgradeSectionRenderer(ctx: MigrationContext) {
971
971
  let changed = false;
972
972
 
973
973
  // 1. Replace `import { SectionRenderer } from "@decocms/start/hooks"`
974
- // with `import { RenderSection } from "@decocms/start/hooks"`
974
+ // with `import { RenderSection } from "@decocms/blocks/hooks"`
975
+ // (RenderSection is a distinct component from tanstack's
976
+ // SectionRenderer — it lives in @decocms/blocks/hooks, not
977
+ // @decocms/tanstack.)
975
978
  const sectionRendererImport =
976
979
  /import\s*\{([^}]*)\bSectionRenderer\b([^}]*)\}\s*from\s*["']@decocms\/start\/hooks["']/g;
977
980
  const newContent = result.replace(sectionRendererImport, (_m, before, after) => {
978
981
  changed = true;
979
- return `import {${before}RenderSection${after}} from "@decocms/start/hooks"`;
982
+ return `import {${before}RenderSection${after}} from "@decocms/blocks/hooks"`;
980
983
  });
981
984
  if (newContent !== result) {
982
985
  result = newContent;
@@ -1000,7 +1003,7 @@ function upgradeSectionRenderer(ctx: MigrationContext) {
1000
1003
 
1001
1004
  // 4. Add RenderSection import if we introduced usages but no import exists
1002
1005
  if (changed && result.includes("<RenderSection") && !result.includes("RenderSection")) {
1003
- result = `import { RenderSection } from "@decocms/start/hooks";\n` + result;
1006
+ result = `import { RenderSection } from "@decocms/blocks/hooks";\n` + result;
1004
1007
  }
1005
1008
 
1006
1009
  if (!changed) return null;
@@ -1013,16 +1016,18 @@ function upgradeSectionRenderer(ctx: MigrationContext) {
1013
1016
  *
1014
1017
  * Historical context:
1015
1018
  * Earlier versions of this script rewrote `@decocms/apps/vtex/utils/*` imports
1016
- * to local `~/lib/vtex-*` shims because those modules did not exist yet in
1017
- * `@decocms/apps`. They now do (apps-start exports `./vtex/utils/*` and
1018
- * `./vtex/client` directly), so any further rewrite would actively REGRESS
1019
- * working direct imports back into NO-OP shims and silently break runtime
1020
- * behavior on every migrated site.
1019
+ * (the pre-split Fresh/Deno site's original import shape) to local
1020
+ * `~/lib/vtex-*` shims because those modules did not exist yet as
1021
+ * directly-importable subpaths. They now do the post-7.x split
1022
+ * `@decocms/apps-vtex` package exports `./utils/*` and `./client`
1023
+ * directly so any further rewrite would actively REGRESS working direct
1024
+ * imports back into NO-OP shims and silently break runtime behavior on
1025
+ * every migrated site.
1021
1026
  *
1022
1027
  * Scope kept here:
1023
1028
  * - `@decocms/apps/vtex/loaders/intelligentSearch/*` → inline stubs
1024
- * (loaders moved under `inline-loaders/` in apps-start; this is still a
1025
- * real path-mismatch fixup)
1029
+ * (loaders moved under `inline-loaders/` in `@decocms/apps-vtex`; this
1030
+ * is still a real path-mismatch fixup)
1026
1031
  * - `LabelledFuzzy` type + `mapLabelledFuzzyToFuzzy` helper inlined when
1027
1032
  * `intelligentSearch/productListingPage` is imported
1028
1033
  * - `createHttpClient<Type>(...)` → `createHttpClient(...)` (Proxy handles types)
@@ -1034,12 +1039,13 @@ function upgradeSectionRenderer(ctx: MigrationContext) {
1034
1039
  * What was removed:
1035
1040
  * The four `@decocms/apps/vtex/utils/* → ~/lib/vtex-*` rewrites that the
1036
1041
  * first-pass `transforms/imports.ts` (lines 50-52) already produces in the
1037
- * correct, direct form. See discovery notes in MIGRATION_TOOLING_PLAN.md.
1042
+ * correct, direct `@decocms/apps-vtex/utils/*` form. See discovery notes
1043
+ * in MIGRATION_TOOLING_PLAN.md.
1038
1044
  */
1039
1045
  function rewriteVtexUtilImports(ctx: MigrationContext) {
1040
1046
  // Intentionally empty — see docstring. First-pass `transforms/imports.ts`
1041
1047
  // already maps `apps/vtex/utils/*` and `apps/vtex/client` directly to the
1042
- // `@decocms/apps` equivalents; rewriting them again here would dead-shim them.
1048
+ // `@decocms/apps-vtex` equivalents; rewriting them again here would dead-shim them.
1043
1049
  const importRewrites: Array<{ pattern: RegExp; replacement: string; desc: string }> = [];
1044
1050
 
1045
1051
  rewriteFilesRecursive(ctx, path.join(ctx.sourceDir, "src"), (content, relPath) => {
@@ -1117,12 +1123,12 @@ function rewriteVtexUtilImports(ctx: MigrationContext) {
1117
1123
  log(ctx, ` Replaced inline getISCookiesFromBag stub → ~/lib/vtex-intelligent-search: src/${relPath}`);
1118
1124
  }
1119
1125
 
1120
- // Rewrite ~/utils/retry → @decocms/start/sdk/retry
1126
+ // Rewrite ~/utils/retry → @decocms/blocks/sdk/retry
1121
1127
  const retryImport = /from\s+["']~\/utils\/retry["']/g;
1122
1128
  if (retryImport.test(result)) {
1123
- result = result.replace(retryImport, 'from "@decocms/start/sdk/retry"');
1129
+ result = result.replace(retryImport, 'from "@decocms/blocks/sdk/retry"');
1124
1130
  changed = true;
1125
- log(ctx, ` Rewrote retry import → @decocms/start/sdk/retry: src/${relPath}`);
1131
+ log(ctx, ` Rewrote retry import → @decocms/blocks/sdk/retry: src/${relPath}`);
1126
1132
  }
1127
1133
 
1128
1134
  // Rewrite type-only imports from productListingPage (Props type)
@@ -1301,7 +1307,7 @@ function moveRootConstantsToSrc(ctx: MigrationContext) {
1301
1307
  * with broken imports.
1302
1308
  *
1303
1309
  * New stack: the canonical Minicart contract + VTEX transform live in
1304
- * `@decocms/apps/vtex/inline-loaders/minicart`. We replace the loader with a
1310
+ * `@decocms/apps-vtex/inline-loaders/minicart`. We replace the loader with a
1305
1311
  * thin VTEX-only re-export. Sites on Shopify/VNDA/Wake/Linx/Nuvemshop are
1306
1312
  * not currently in production on the new stack — when one is, swap this for
1307
1313
  * a runtime dispatcher again or add a platform-flagged rewrite.
@@ -1325,19 +1331,19 @@ function rewriteMinicartLoader(ctx: MigrationContext) {
1325
1331
  //
1326
1332
  // The legacy site shipped per-platform loaders behind a \`usePlatform()\`
1327
1333
  // switch (vnda, wake, linx, shopify, nuvemshop). The canonical minicart
1328
- // contract now lives in \`@decocms/apps\`. Until a non-VTEX customer comes
1334
+ // contract now lives in \`@decocms/apps-vtex\`. Until a non-VTEX customer comes
1329
1335
  // online on the new stack, we re-export the framework loader directly.
1330
1336
  // TODO: when adding another platform, replace this with a runtime
1331
1337
  // dispatcher and import the matching framework loader.
1332
- export { default } from "@decocms/apps/vtex/inline-loaders/minicart";
1333
- export type { MinicartProps } from "@decocms/apps/vtex/inline-loaders/minicart";
1338
+ export { default } from "@decocms/apps-vtex/inline-loaders/minicart";
1339
+ export type { MinicartProps } from "@decocms/apps-vtex/inline-loaders/minicart";
1334
1340
  `;
1335
1341
 
1336
1342
  if (ctx.dryRun) {
1337
1343
  log(ctx, `[DRY] Would rewrite: ${path.relative(ctx.sourceDir, filePath)} (VTEX-only re-export)`);
1338
1344
  } else {
1339
1345
  fs.writeFileSync(filePath, newContent);
1340
- log(ctx, `Rewrote: ${path.relative(ctx.sourceDir, filePath)} (VTEX-only re-export of @decocms/apps/vtex/inline-loaders/minicart)`);
1346
+ log(ctx, `Rewrote: ${path.relative(ctx.sourceDir, filePath)} (VTEX-only re-export of @decocms/apps-vtex/inline-loaders/minicart)`);
1341
1347
  }
1342
1348
  }
1343
1349
  }
@@ -1422,7 +1428,7 @@ export function cleanup(ctx: MigrationContext): void {
1422
1428
 
1423
1429
  // 5. Override contexts/device.tsx with SSR-safe useSyncExternalStore version.
1424
1430
  // The transform phase copies and transforms the source file (createContext-based),
1425
- // but @decocms/start shell-renders sections without a Device.Provider, so we
1431
+ // but @decocms/tanstack shell-renders sections without a Device.Provider, so we
1426
1432
  // must replace it with a standalone implementation.
1427
1433
  console.log(" Overriding contexts/device.tsx...");
1428
1434
  overrideDeviceContext(ctx);
@@ -1452,7 +1458,7 @@ export function cleanup(ctx: MigrationContext): void {
1452
1458
 
1453
1459
  // 11. Rewrite VTEX utility imports to use ~/lib/ wrappers
1454
1460
  // The old stack imports from apps/vtex/utils/* which get rewritten to
1455
- // @decocms/apps/vtex/utils/* — but the signatures are incompatible
1461
+ // @decocms/apps-vtex/utils/* — but the signatures are incompatible
1456
1462
  // and some types (VTEXCommerceStable) don't exist. Replace with
1457
1463
  // simplified ~/lib/ wrappers generated during scaffold.
1458
1464
  console.log(" Rewriting VTEX utility imports → ~/lib/ wrappers...");
@@ -1467,7 +1473,7 @@ export function cleanup(ctx: MigrationContext): void {
1467
1473
  // 11b. Rewrite legacy multi-platform minicart loader → VTEX-only re-export.
1468
1474
  // `sdk/cart/` is deleted by DIRS_TO_DELETE, leaving loaders/minicart.ts
1469
1475
  // with broken imports. Replace it with a thin re-export of the
1470
- // framework's @decocms/apps/vtex/inline-loaders/minicart loader.
1476
+ // framework's @decocms/apps-vtex/inline-loaders/minicart loader.
1471
1477
  console.log(" Rewriting loaders/minicart.ts → VTEX-only re-export...");
1472
1478
  rewriteMinicartLoader(ctx);
1473
1479
 
@@ -5,11 +5,11 @@ import { logPhase } from "./types";
5
5
 
6
6
  const FRAMEWORK_FINDINGS = [
7
7
  "Session/analytics SDK is boilerplate duplicated across all sites — should be a single framework function",
8
- "GTM event system (useGTMEvent, data-gtm-* listeners) is universal pattern — should be in @decocms/start",
8
+ "GTM event system (useGTMEvent, data-gtm-* listeners) is universal pattern — should be in @decocms/blocks",
9
9
  "Route files (__root.tsx, index.tsx, $.tsx, deco/*) are near-identical across sites — should be generated by framework",
10
10
  "server.ts, worker-entry.ts, router.tsx are pure boilerplate — should be a single createSite() call",
11
11
  "setup.ts section registration via import.meta.glob is 100% boilerplate — framework should handle this",
12
- "runtime.ts invoke proxy is identical across sites — already in @decocms/start but sites still have local copies",
12
+ "runtime.ts invoke proxy is identical across sites — already in @decocms/blocks/sdk/invoke but sites still have local copies",
13
13
  "apps/site.ts is mostly empty after migration — platform config should be in a config file, not code",
14
14
  ];
15
15
 
@@ -124,7 +124,7 @@ export function report(ctx: MigrationContext): void {
124
124
  lines.push("## Loader Inventory");
125
125
  lines.push("");
126
126
  lines.push(`- **${ctx.loaderInventory.length}** loaders inventoried`);
127
- lines.push(`- **${mapped}** mapped to \`@decocms/apps\` equivalents`);
127
+ lines.push(`- **${mapped}** mapped to \`@decocms/apps-*\` equivalents`);
128
128
  lines.push(`- **${custom}** custom (included in \`setup/commerce-loaders.ts\`)`);
129
129
  lines.push("");
130
130
  }
@@ -175,7 +175,7 @@ export function report(ctx: MigrationContext): void {
175
175
  lines.push("## Framework Findings");
176
176
  lines.push("");
177
177
  lines.push(
178
- "> These are patterns found during migration that should eventually be handled by `@decocms/start` instead of being duplicated in every site.",
178
+ "> These are patterns found during migration that should eventually be handled by `@decocms/blocks` instead of being duplicated in every site.",
179
179
  );
180
180
  lines.push("");
181
181
  for (const finding of ctx.frameworkFindings) {
@@ -215,11 +215,11 @@ export function report(ctx: MigrationContext): void {
215
215
  lines.push("#");
216
216
  lines.push("# Forwarding to a future ClickHouse-backed OTel collector is on the");
217
217
  lines.push("# roadmap (placeholder lives at");
218
- lines.push("# @decocms/start/sdk/otelAdapters/clickhouseCollector); when it");
218
+ lines.push("# @decocms/blocks/sdk/otelAdapters/clickhouseCollector); when it");
219
219
  lines.push("# ships, the codemod gains a `--destination-logs` /");
220
220
  lines.push("# `--destination-traces` flag to point at it.");
221
- lines.push("npx -p @decocms/start deco-cf-observability # dry-run");
222
- lines.push("npx -p @decocms/start deco-cf-observability --write # apply");
221
+ lines.push("npx -p @decocms/blocks-cli deco-cf-observability # dry-run");
222
+ lines.push("npx -p @decocms/blocks-cli deco-cf-observability --write # apply");
223
223
  lines.push("```");
224
224
  lines.push("");
225
225
 
@@ -135,7 +135,7 @@ export function scaffold(ctx: MigrationContext): void {
135
135
  // some file actually imports. See `writeImportedLibShims` in phase-cleanup.
136
136
 
137
137
  // Replace Context-based useDevice with SSR-safe useSyncExternalStore version.
138
- // @decocms/start shell-renders sections in a separate React root without
138
+ // @decocms/tanstack shell-renders sections in a separate React root without
139
139
  // Device.Provider, so the old createContext pattern throws during SSR.
140
140
  writeFile(ctx, "src/contexts/device.tsx", generateDeviceContext());
141
141
 
@@ -312,7 +312,7 @@ export default debounce;
312
312
 
313
313
  function generateSignalShim(): string {
314
314
  return `import { useState, useRef, useEffect, useMemo, useCallback } from "react";
315
- export { signal, type ReactiveSignal } from "@decocms/start/sdk/signal";
315
+ export { signal, type ReactiveSignal } from "@decocms/blocks/sdk/signal";
316
316
 
317
317
  /** Run a function immediately. Kept for legacy module-level side effects. */
318
318
  export function effect(fn: () => void | (() => void)): () => void {
@@ -535,8 +535,8 @@ function generateLocationMatcher(): string {
535
535
  * rules server-side.
536
536
  */
537
537
 
538
- import { registerMatcher } from "@decocms/start/cms";
539
- import type { MatcherContext } from "@decocms/start/cms";
538
+ import { registerMatcher } from "@decocms/blocks/cms";
539
+ import type { MatcherContext } from "@decocms/blocks/cms";
540
540
 
541
541
  const COUNTRY_NAME_TO_CODE: Record<string, string> = {
542
542
  Brasil: "BR",
@@ -155,7 +155,7 @@ export function transform(ctx: MigrationContext): void {
155
155
  // This file uses Deno-specific APIs (toFileUrl, import.meta.resolve)
156
156
  // and the HTMX-driven `useComponent(component, props)` pattern, which
157
157
  // do not run on Cloudflare Workers and have no equivalent in
158
- // @decocms/start. The whole file must be deleted.
158
+ // @decocms/blocks. The whole file must be deleted.
159
159
  if (
160
160
  /sections\/Component\.tsx?$/.test(record.path) ||
161
161
  /sections\/Component\.tsx?$/.test(targetPath)
@@ -35,7 +35,7 @@ const REQUIRED_FILES = [
35
35
  "src/hooks/useUser.ts",
36
36
  "src/hooks/useWishlist.ts",
37
37
  // src/types/widgets.ts intentionally omitted — provided by the
38
- // framework at `@decocms/start/types/widgets`; sites no longer
38
+ // framework at `@decocms/blocks/types/widgets`; sites no longer
39
39
  // shadow the file locally.
40
40
  "src/types/deco.ts",
41
41
  "src/types/commerce-app.ts",
@@ -173,8 +173,9 @@ export const checks: Check[] = [
173
173
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
174
174
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
175
175
  const required = [
176
- "@decocms/start",
177
- "@decocms/apps",
176
+ "@decocms/blocks",
177
+ "@decocms/tanstack",
178
+ "@decocms/apps-commerce",
178
179
  "react",
179
180
  "react-dom",
180
181
  "@tanstack/react-start",
@@ -382,7 +383,7 @@ export const checks: Check[] = [
382
383
  },
383
384
  },
384
385
  {
385
- name: "No apps/ imports in src/ (should be @decocms/apps or ~/)",
386
+ name: "No apps/ imports in src/ (should be @decocms/apps-* or ~/)",
386
387
  severity: "error",
387
388
  fn: (ctx) => {
388
389
  const srcDir = path.join(ctx.sourceDir, "src");
@@ -457,7 +458,7 @@ export const checks: Check[] = [
457
458
  severity: "warning",
458
459
  fn: (ctx) => {
459
460
  const typeFiles = [
460
- // widgets.ts is provided by @decocms/start/types/widgets, not
461
+ // widgets.ts is provided by @decocms/blocks/types/widgets, not
461
462
  // scaffolded locally.
462
463
  "src/types/deco.ts",
463
464
  "src/types/commerce-app.ts",