@decocms/blocks-cli 7.5.1 → 7.5.3

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 (43) hide show
  1. package/package.json +2 -2
  2. package/scripts/generate-invoke.ts +10 -0
  3. package/scripts/generate-schema.ts +46 -15
  4. package/scripts/generate-sections.test.ts +67 -0
  5. package/scripts/generate-sections.ts +16 -2
  6. package/scripts/lib/codegenExclusions.test.ts +16 -6
  7. package/scripts/lib/codegenExclusions.ts +13 -1
  8. package/scripts/migrate/analyzers/loader-inventory.ts +1 -1
  9. package/scripts/migrate/phase-analyze.ts +3 -3
  10. package/scripts/migrate/phase-cleanup.test.ts +70 -1
  11. package/scripts/migrate/phase-cleanup.ts +47 -26
  12. package/scripts/migrate/phase-report.ts +7 -7
  13. package/scripts/migrate/phase-scaffold.ts +4 -4
  14. package/scripts/migrate/phase-transform.ts +1 -1
  15. package/scripts/migrate/phase-verify.ts +6 -5
  16. package/scripts/migrate/post-cleanup/rules.ts +55 -44
  17. package/scripts/migrate/post-cleanup/runner.test.ts +58 -34
  18. package/scripts/migrate/templates/cache-config.ts +4 -4
  19. package/scripts/migrate/templates/commerce-loaders.ts +10 -10
  20. package/scripts/migrate/templates/cursor-rules.test.ts +6 -0
  21. package/scripts/migrate/templates/cursor-rules.ts +12 -11
  22. package/scripts/migrate/templates/hooks.test.ts +7 -7
  23. package/scripts/migrate/templates/hooks.ts +10 -10
  24. package/scripts/migrate/templates/lib-utils.test.ts +2 -2
  25. package/scripts/migrate/templates/lib-utils.ts +4 -4
  26. package/scripts/migrate/templates/no-legacy-packages.test.ts +147 -0
  27. package/scripts/migrate/templates/package-json.ts +30 -10
  28. package/scripts/migrate/templates/routes.ts +8 -10
  29. package/scripts/migrate/templates/sdk-gen.ts +1 -1
  30. package/scripts/migrate/templates/section-loaders.ts +7 -7
  31. package/scripts/migrate/templates/server-entry.ts +37 -37
  32. package/scripts/migrate/templates/setup.ts +6 -6
  33. package/scripts/migrate/templates/types-gen.ts +2 -2
  34. package/scripts/migrate/templates/ui-components.ts +2 -2
  35. package/scripts/migrate/templates/vite-config.ts +12 -3
  36. package/scripts/migrate/transforms/fresh-apis.ts +5 -5
  37. package/scripts/migrate/transforms/imports.test.ts +138 -0
  38. package/scripts/migrate/transforms/imports.ts +65 -43
  39. package/scripts/migrate/transforms/jsx.ts +8 -0
  40. package/scripts/migrate/transforms/section-conventions.ts +1 -1
  41. package/scripts/migrate/types.ts +1 -1
  42. package/scripts/migrate-post-cleanup.ts +8 -8
  43. package/scripts/migrate.ts +11 -11
@@ -0,0 +1,147 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createContext } from "../types";
3
+ import type { MigrationContext } from "../types";
4
+ import { generateRoutes } from "./routes";
5
+ import { generateServerEntry } from "./server-entry";
6
+ import { generateSetup } from "./setup";
7
+ import { generateViteConfig } from "./vite-config";
8
+ import { generateCommerceLoaders } from "./commerce-loaders";
9
+ import { generateSectionLoaders } from "./section-loaders";
10
+ import { generateHooks } from "./hooks";
11
+ import { generateUiComponents } from "./ui-components";
12
+ import { generateTypeFiles } from "./types-gen";
13
+ import { generateCacheConfig } from "./cache-config";
14
+ import { generateSdkFiles } from "./sdk-gen";
15
+ import { generatePackageJson } from "./package-json";
16
+ import { generateMigrationPolicyPointerRule } from "./cursor-rules";
17
+
18
+ /**
19
+ * Fleet-wide regression guard: none of the scaffolder's templates may emit
20
+ * the pre-7.x-split `@decocms/start` package, or a bare `@decocms/apps/`
21
+ * monolith subpath import — neither exists for 7.x consumers, so any
22
+ * occurrence here means a freshly scaffolded site ships broken code.
23
+ *
24
+ * `@decocms/apps-<platform>` (the current split packages) are fine and
25
+ * intentionally NOT flagged by this check.
26
+ */
27
+ function assertNoLegacyPackageNames(label: string, output: string) {
28
+ expect(output, `${label} must not emit "@decocms/start"`).not.toContain(
29
+ "@decocms/start",
30
+ );
31
+ expect(
32
+ output,
33
+ `${label} must not emit the "@decocms/apps/" monolith subpath`,
34
+ ).not.toMatch(/@decocms\/apps\//);
35
+ }
36
+
37
+ function makeCtx(platform: MigrationContext["platform"]): MigrationContext {
38
+ const ctx = createContext("/tmp/no-legacy-packages-fixture-site");
39
+ ctx.siteName = "acme-storefront";
40
+ ctx.platform = platform;
41
+ ctx.vtexAccount = platform === "vtex" ? "acme" : null;
42
+ return ctx;
43
+ }
44
+
45
+ describe("scaffolder templates never emit @decocms/start or @decocms/apps/*", () => {
46
+ for (const platform of ["vtex", "custom"] as const) {
47
+ describe(`platform: ${platform}`, () => {
48
+ const ctx = makeCtx(platform);
49
+
50
+ it("routes.ts", () => {
51
+ const files = generateRoutes(ctx);
52
+ for (const [path, content] of Object.entries(files)) {
53
+ assertNoLegacyPackageNames(`routes.ts (${path})`, content);
54
+ }
55
+ });
56
+
57
+ it("server-entry.ts", () => {
58
+ const files = generateServerEntry(ctx);
59
+ for (const [path, content] of Object.entries(files)) {
60
+ assertNoLegacyPackageNames(`server-entry.ts (${path})`, content);
61
+ }
62
+ });
63
+
64
+ it("setup.ts", () => {
65
+ assertNoLegacyPackageNames("setup.ts", generateSetup(ctx));
66
+ });
67
+
68
+ it("vite-config.ts", () => {
69
+ assertNoLegacyPackageNames("vite-config.ts", generateViteConfig(ctx));
70
+ });
71
+
72
+ it("commerce-loaders.ts", () => {
73
+ assertNoLegacyPackageNames(
74
+ "commerce-loaders.ts",
75
+ generateCommerceLoaders(ctx),
76
+ );
77
+ });
78
+
79
+ it("section-loaders.ts", () => {
80
+ assertNoLegacyPackageNames(
81
+ "section-loaders.ts",
82
+ generateSectionLoaders(ctx),
83
+ );
84
+ });
85
+
86
+ it("hooks.ts", () => {
87
+ const files = generateHooks(ctx);
88
+ for (const [path, content] of Object.entries(files)) {
89
+ assertNoLegacyPackageNames(`hooks.ts (${path})`, content);
90
+ }
91
+ });
92
+
93
+ it("types-gen.ts", () => {
94
+ const files = generateTypeFiles(ctx);
95
+ for (const [path, content] of Object.entries(files)) {
96
+ assertNoLegacyPackageNames(`types-gen.ts (${path})`, content);
97
+ }
98
+ });
99
+
100
+ it("cache-config.ts", () => {
101
+ assertNoLegacyPackageNames(
102
+ "cache-config.ts",
103
+ generateCacheConfig(ctx),
104
+ );
105
+ });
106
+
107
+ it("sdk-gen.ts", () => {
108
+ const files = generateSdkFiles(ctx);
109
+ for (const [path, content] of Object.entries(files)) {
110
+ assertNoLegacyPackageNames(`sdk-gen.ts (${path})`, content);
111
+ }
112
+ });
113
+ });
114
+ }
115
+
116
+ // Platform-agnostic templates
117
+ it("ui-components.ts", () => {
118
+ const ctx = makeCtx("custom");
119
+ const files = generateUiComponents(ctx);
120
+ for (const [path, content] of Object.entries(files)) {
121
+ assertNoLegacyPackageNames(`ui-components.ts (${path})`, content);
122
+ }
123
+ });
124
+
125
+ it("cursor-rules.ts", () => {
126
+ assertNoLegacyPackageNames(
127
+ "cursor-rules.ts",
128
+ generateMigrationPolicyPointerRule("acme-storefront"),
129
+ );
130
+ });
131
+
132
+ // package-json.ts shells out to `npm view` to resolve the latest published
133
+ // version, with a hardcoded fallback if that fails (offline/CI-sandboxed).
134
+ // Either way the emitted dependency *names* must never be the retired
135
+ // @decocms/start / @decocms/apps monolith.
136
+ it("package-json.ts", () => {
137
+ const ctx = makeCtx("vtex");
138
+ const pkg = generatePackageJson(ctx);
139
+ assertNoLegacyPackageNames("package-json.ts", pkg);
140
+ const parsed = JSON.parse(pkg);
141
+ expect(parsed.dependencies).not.toHaveProperty("@decocms/start");
142
+ expect(parsed.dependencies).not.toHaveProperty("@decocms/apps");
143
+ expect(parsed.dependencies).toHaveProperty("@decocms/blocks");
144
+ expect(parsed.dependencies).toHaveProperty("@decocms/tanstack");
145
+ expect(parsed.dependencies).toHaveProperty("@decocms/apps-vtex");
146
+ }, 20000);
147
+ });
@@ -95,9 +95,25 @@ export function generatePackageJson(ctx: MigrationContext): string {
95
95
 
96
96
  const siteDeps = extractedDeps;
97
97
 
98
- // Fetch latest versions from npm registry
99
- const startVersion = getLatestVersion("@decocms/start", "0.34.0");
100
- const appsVersion = getLatestVersion("@decocms/apps", "0.27.0");
98
+ // @decocms/blocks, @decocms/blocks-admin, @decocms/blocks-cli,
99
+ // @decocms/tanstack, and the @decocms/apps-* platform packages are
100
+ // published in lockstep from the same monorepo release, so a single
101
+ // version lookup covers all of them (mirrors how consumer sites bump
102
+ // "@decocms/blocks/blocks-admin/nextjs ranges" together).
103
+ //
104
+ // If this ever stops being true (e.g. a package starts shipping
105
+ // independent version bumps), every `${frameworkVersion}` usage below
106
+ // (in `dependencies` and `devDependencies`) needs to become its own
107
+ // `getLatestVersion("<package>", "<fallback>")` call instead of sharing
108
+ // this one lookup.
109
+ const frameworkVersion = getLatestVersion("@decocms/blocks", "7.5.1");
110
+
111
+ const platformPackage: Partial<Record<typeof ctx.platform, string>> = {
112
+ vtex: "@decocms/apps-vtex",
113
+ shopify: "@decocms/apps-shopify",
114
+ magento: "@decocms/apps-magento",
115
+ };
116
+ const platformDep = platformPackage[ctx.platform];
101
117
 
102
118
  const pkg = {
103
119
  name: ctx.siteName,
@@ -109,14 +125,14 @@ export function generatePackageJson(ctx: MigrationContext): string {
109
125
  "dev:clean":
110
126
  "rm -rf node_modules/.vite .wrangler/state .tanstack && vite dev",
111
127
  "generate:blocks":
112
- "tsx node_modules/@decocms/start/scripts/generate-blocks.ts",
128
+ "tsx node_modules/@decocms/blocks-cli/scripts/generate-blocks.ts",
113
129
  "generate:routes": "tsr generate",
114
- "generate:schema": `tsx node_modules/@decocms/start/scripts/generate-schema.ts --site ${ctx.siteName}`,
130
+ "generate:schema": `tsx node_modules/@decocms/blocks-cli/scripts/generate-schema.ts --site ${ctx.siteName}`,
115
131
  "generate:invoke":
116
- "tsx node_modules/@decocms/start/scripts/generate-invoke.ts",
132
+ "tsx node_modules/@decocms/blocks-cli/scripts/generate-invoke.ts",
117
133
  "generate:sections":
118
- "tsx node_modules/@decocms/start/scripts/generate-sections.ts",
119
- "generate:loaders": `tsx node_modules/@decocms/start/scripts/generate-loaders.ts --exclude vtex/loaders,vtex/actions,loaders/vtex-auth-loader,loaders/reviews/productReviews,loaders/product/buyTogether,loaders/search/productListPageCollection,loaders/search/intelligenseSearch,loaders/Layouts/ProductCard`,
134
+ "tsx node_modules/@decocms/blocks-cli/scripts/generate-sections.ts",
135
+ "generate:loaders": `tsx node_modules/@decocms/blocks-cli/scripts/generate-loaders.ts --exclude vtex/loaders,vtex/actions,loaders/vtex-auth-loader,loaders/reviews/productReviews,loaders/product/buyTogether,loaders/search/productListPageCollection,loaders/search/intelligenseSearch,loaders/Layouts/ProductCard`,
120
136
  build:
121
137
  "npm run generate:blocks && npm run generate:sections && npm run generate:loaders && npm run generate:schema && npm run generate:invoke && tsr generate && vite build",
122
138
  preview: "vite preview",
@@ -141,8 +157,11 @@ export function generatePackageJson(ctx: MigrationContext): string {
141
157
  license: "MIT",
142
158
  packageManager: `bun@${CANONICAL_BUN_VERSION}`,
143
159
  dependencies: {
144
- "@decocms/apps": `^${appsVersion}`,
145
- "@decocms/start": `^${startVersion}`,
160
+ "@decocms/blocks": `^${frameworkVersion}`,
161
+ "@decocms/blocks-admin": `^${frameworkVersion}`,
162
+ "@decocms/tanstack": `^${frameworkVersion}`,
163
+ "@decocms/apps-commerce": `^${frameworkVersion}`,
164
+ ...(platformDep ? { [platformDep]: `^${frameworkVersion}` } : {}),
146
165
  "@tanstack/react-query": "5.90.21",
147
166
  "@tanstack/react-router": "1.166.7",
148
167
  "@tanstack/react-start": "1.166.8",
@@ -155,6 +174,7 @@ export function generatePackageJson(ctx: MigrationContext): string {
155
174
  },
156
175
  devDependencies: {
157
176
  "@cloudflare/vite-plugin": "^1.27.0",
177
+ "@decocms/blocks-cli": `^${frameworkVersion}`,
158
178
  "@tailwindcss/vite": "^4.2.1",
159
179
  "@tanstack/router-cli": "1.166.7",
160
180
  "@types/react": "^19.2.14",
@@ -63,7 +63,7 @@ function generateRoot(ctx: MigrationContext, siteTitle: string, vtexAccount: str
63
63
  }
64
64
 
65
65
  return `import { createRootRoute } from "@tanstack/react-router";
66
- import { DecoRootLayout } from "@decocms/start/hooks";
66
+ import { DecoRootLayout } from "@decocms/tanstack";
67
67
  // @ts-ignore Vite ?url import
68
68
  import appCss from "../styles/app.css?url";
69
69
 
@@ -107,8 +107,7 @@ function RootLayout() {
107
107
 
108
108
  function generateIndex(ctx: MigrationContext, siteTitle: string): string {
109
109
  return `import { createFileRoute } from "@tanstack/react-router";
110
- import { cmsHomeRouteConfig, deferredSectionLoader } from "@decocms/start/routes";
111
- import { DecoPageRenderer } from "@decocms/start/hooks";
110
+ import { cmsHomeRouteConfig, DecoPageRenderer, loadDeferredSection } from "@decocms/tanstack";
112
111
 
113
112
  // MIGRATION TODO: customize defaultTitle / defaultDescription / fallback
114
113
  // copy below for ${siteTitle}. CMS \`Site.seo\` overrides these once block
@@ -144,7 +143,7 @@ function HomePage() {
144
143
  deferredPromises={data.deferredPromises}
145
144
  pagePath={data.pagePath}
146
145
  pageUrl={data.pageUrl}
147
- loadDeferredSectionFn={deferredSectionLoader}
146
+ loadDeferredSectionFn={loadDeferredSection}
148
147
  />
149
148
  );
150
149
  }
@@ -153,8 +152,7 @@ function HomePage() {
153
152
 
154
153
  function generateCatchAll(ctx: MigrationContext, siteTitle: string): string {
155
154
  return `import { createFileRoute } from "@tanstack/react-router";
156
- import { cmsRouteConfig, deferredSectionLoader } from "@decocms/start/routes";
157
- import { DecoPageRenderer } from "@decocms/start/hooks";
155
+ import { cmsRouteConfig, DecoPageRenderer, loadDeferredSection } from "@decocms/tanstack";
158
156
 
159
157
  // MIGRATION TODO: customize defaultTitle / defaultDescription for ${siteTitle}
160
158
  // (CMS \`Site.seo\` overrides these per-page once block resolution kicks in).
@@ -182,7 +180,7 @@ function CmsPage() {
182
180
  deferredPromises={data.deferredPromises}
183
181
  pagePath={data.pagePath}
184
182
  pageUrl={data.pageUrl}
185
- loadDeferredSectionFn={deferredSectionLoader}
183
+ loadDeferredSectionFn={loadDeferredSection}
186
184
  />
187
185
  );
188
186
  }
@@ -214,7 +212,7 @@ function NotFoundPage() {
214
212
 
215
213
  function generateDecoMeta(): string {
216
214
  return `import { createFileRoute } from "@tanstack/react-router";
217
- import { decoMetaRoute } from "@decocms/start/routes";
215
+ import { decoMetaRoute } from "@decocms/tanstack";
218
216
 
219
217
  export const Route = createFileRoute("/deco/meta")(decoMetaRoute);
220
218
  `;
@@ -222,7 +220,7 @@ export const Route = createFileRoute("/deco/meta")(decoMetaRoute);
222
220
 
223
221
  function generateDecoInvoke(): string {
224
222
  return `import { createFileRoute } from "@tanstack/react-router";
225
- import { decoInvokeRoute } from "@decocms/start/routes";
223
+ import { decoInvokeRoute } from "@decocms/tanstack";
226
224
 
227
225
  export const Route = createFileRoute("/deco/invoke/$")(decoInvokeRoute);
228
226
  `;
@@ -230,7 +228,7 @@ export const Route = createFileRoute("/deco/invoke/$")(decoInvokeRoute);
230
228
 
231
229
  function generateDecoRender(): string {
232
230
  return `import { createFileRoute } from "@tanstack/react-router";
233
- import { decoRenderRoute } from "@decocms/start/routes";
231
+ import { decoRenderRoute } from "@decocms/tanstack";
234
232
 
235
233
  export const Route = createFileRoute("/deco/render")(decoRenderRoute);
236
234
  `;
@@ -12,7 +12,7 @@ export function generateSdkFiles(ctx: MigrationContext): Record<string, string>
12
12
  function generateDeviceServer(): string {
13
13
  return `import { createServerFn } from "@tanstack/react-start";
14
14
  import { getRequestHeader } from "@tanstack/react-start/server";
15
- import { detectDevice } from "@decocms/start/sdk/useDevice";
15
+ import { detectDevice } from "@decocms/blocks/sdk/useDevice";
16
16
 
17
17
  export const getDeviceFromServer = createServerFn({ method: "GET" }).handler(
18
18
  async () => {
@@ -71,22 +71,22 @@ export function generateSectionLoaders(ctx: MigrationContext): string {
71
71
  lines.push(` withSearchParam,`);
72
72
  lines.push(` withSectionLoader,`);
73
73
  lines.push(` compose,`);
74
- lines.push(`} from "@decocms/start/cms";`);
74
+ lines.push(`} from "@decocms/blocks/cms";`);
75
75
 
76
76
  if (hasSearchResult) {
77
- lines.push(`import { detectDevice } from "@decocms/start/sdk/useDevice";`);
77
+ lines.push(`import { detectDevice } from "@decocms/blocks/sdk/useDevice";`);
78
78
  }
79
79
 
80
80
  if (isVtex) {
81
- lines.push(`import { getVtexConfig } from "@decocms/apps/vtex";`);
81
+ lines.push(`import { getVtexConfig } from "@decocms/apps-vtex";`);
82
82
  if (hasWishlistSection && hasWishlistLoaders) {
83
- lines.push(`import { getUser } from "@decocms/apps/vtex/loaders/user";`);
84
- lines.push(`import { getVtexCookies } from "@decocms/apps/vtex/utils/cookies";`);
83
+ lines.push(`import { getUser } from "@decocms/apps-vtex/loaders/user";`);
84
+ lines.push(`import { getVtexCookies } from "@decocms/apps-vtex/utils/cookies";`);
85
85
  }
86
86
  }
87
87
 
88
88
  if (hasAccountSections) {
89
- lines.push(`import { vtexAccountLoaders } from "@decocms/apps/vtex/utils/accountLoaders";`);
89
+ lines.push(`import { vtexAccountLoaders } from "@decocms/apps-vtex/utils/accountLoaders";`);
90
90
  }
91
91
 
92
92
  if (hasProductReviewsLoader && (hasProductReviews || hasSearchResult)) {
@@ -338,7 +338,7 @@ export function generateSectionLoaders(ctx: MigrationContext): string {
338
338
  // ---------- Account sections ----------
339
339
  if (isVtex && hasAccountSections) {
340
340
  entries.push(``);
341
- entries.push(` // Account sections — via @decocms/apps factory`);
341
+ entries.push(` // Account sections — via @decocms/apps-vtex factory`);
342
342
 
343
343
  for (const meta of ctx.sectionMetas) {
344
344
  if (!meta.isAccountSection) continue;
@@ -43,7 +43,7 @@ function generateWorkerEntry(ctx: MigrationContext): string {
43
43
  * Cloudflare Worker entry point.
44
44
  *
45
45
  * Wraps TanStack Start with admin protocol handlers, edge caching, and
46
- * the @decocms/start observability stack (5.0+, Cloudflare-native):
46
+ * the @decocms/blocks observability stack (5.0+, Cloudflare-native):
47
47
  * - logs: console.* -> CF Workers Logs (captured by the platform
48
48
  * when wrangler.jsonc has \`observability.enabled: true\`).
49
49
  * View in the CF dashboard -> Workers & Pages -> <site> ->
@@ -57,27 +57,27 @@ function generateWorkerEntry(ctx: MigrationContext): string {
57
57
  *
58
58
  * No in-Worker OTLP exporter ships with 5.x — the CF dashboard is the
59
59
  * destination. A ClickHouse-collector adapter is scaffolded at
60
- * @decocms/start/sdk/otelAdapters/clickhouseCollector but throws if
60
+ * @decocms/blocks/sdk/otelAdapters/clickhouseCollector but throws if
61
61
  * called; it'll get a real implementation once the OTel collector
62
62
  * gateway lands.
63
63
  *
64
64
  * To wire wrangler.jsonc with the canonical observability block, run:
65
- * npx -p @decocms/start deco-cf-observability --write
65
+ * npx -p @decocms/blocks-cli deco-cf-observability --write
66
66
  */
67
67
  import "./setup";
68
68
  import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
69
- import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
70
- import { instrumentWorker } from "@decocms/start/sdk/observability";
69
+ import { createDecoWorkerEntry } from "@decocms/tanstack";
70
+ import { instrumentWorker } from "@decocms/blocks/sdk/observability";
71
71
  import {
72
72
  handleMeta,
73
73
  handleDecofileRead,
74
74
  handleDecofileReload,
75
75
  handleRender,
76
76
  corsHeaders,
77
- } from "@decocms/start/admin";
77
+ } from "@decocms/blocks-admin";
78
78
  ${isCommerce ? `
79
79
  // TODO: Uncomment and wire proxy for ${platformLabel}
80
- // import { shouldProxyTo${capitalize(platformLabel!)}, proxyTo${capitalize(platformLabel!)} } from "@decocms/apps/${platformLabel}/utils/proxy";
80
+ // import { shouldProxyTo${capitalize(platformLabel!)}, proxyTo${capitalize(platformLabel!)} } from "@decocms/apps-${platformLabel}/utils/proxy";
81
81
  ` : ""}
82
82
  const serverEntry = createServerEntry({ fetch: handler.fetch });
83
83
 
@@ -110,23 +110,23 @@ function generateVtexWorkerEntry(ctx: MigrationContext): string {
110
110
 
111
111
  return `import "./setup";
112
112
  import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
113
- import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
114
- import { instrumentWorker } from "@decocms/start/sdk/observability";
113
+ import { createDecoWorkerEntry } from "@decocms/tanstack";
114
+ import { instrumentWorker } from "@decocms/blocks/sdk/observability";
115
115
  import {
116
116
  handleMeta,
117
117
  handleDecofileRead,
118
118
  handleDecofileReload,
119
119
  handleRender,
120
120
  corsHeaders,
121
- } from "@decocms/start/admin";
122
- import { shouldProxyToVtex, createVtexCheckoutProxy } from "@decocms/apps/vtex/utils/proxy";
123
- import { extractVtexContext } from "@decocms/apps/vtex/middleware";
124
- import { loadRedirects, matchRedirect } from "@decocms/start/sdk/redirects";
125
- import { withABTesting } from "@decocms/start/sdk/abTesting";
126
- import { loadBlocks } from "@decocms/start/cms";
121
+ } from "@decocms/blocks-admin";
122
+ import { shouldProxyToVtex, createVtexCheckoutProxy } from "@decocms/apps-vtex/utils/proxy";
123
+ import { extractVtexContext } from "@decocms/apps-vtex/middleware";
124
+ import { loadRedirects, matchRedirect } from "@decocms/blocks/sdk/redirects";
125
+ import { withABTesting } from "@decocms/blocks/sdk/abTesting";
126
+ import { loadBlocks } from "@decocms/blocks/cms";
127
127
 
128
128
  // ---------------------------------------------------------------------------
129
- // VTEX checkout proxy — configured via @decocms/apps factory
129
+ // VTEX checkout proxy — configured via @decocms/apps-vtex factory
130
130
  // ---------------------------------------------------------------------------
131
131
 
132
132
  const proxyCheckout = createVtexCheckoutProxy({
@@ -226,7 +226,7 @@ const abTestedWorker = withABTesting(decoWorker, {
226
226
  // ---------------------------------------------------------------------------
227
227
  // Observability wrap (outermost layer)
228
228
  //
229
- // @decocms/start 5.0+ converged on Cloudflare-native observability:
229
+ // @decocms/blocks 5.0+ converged on Cloudflare-native observability:
230
230
  // - logs: console.* -> CF Workers Logs (dashboard captures, no
231
231
  // app-side OTLP exporter)
232
232
  // - traces: @opentelemetry/api global tracer (bridged from
@@ -236,7 +236,7 @@ const abTestedWorker = withABTesting(decoWorker, {
236
236
  // src/sdk/otelAdapters/clickhouseCollector.ts)
237
237
  //
238
238
  // Wire wrangler.jsonc with the canonical observability block via:
239
- // npx -p @decocms/start deco-cf-observability --write
239
+ // npx -p @decocms/blocks-cli deco-cf-observability --write
240
240
  // ---------------------------------------------------------------------------
241
241
  export default instrumentWorker(abTestedWorker, {
242
242
  serviceName: "${ctx.siteName}",
@@ -246,7 +246,7 @@ export default instrumentWorker(abTestedWorker, {
246
246
 
247
247
  function generateRouter(): string {
248
248
  return `import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
249
- import { createDecoRouter } from "@decocms/start/sdk/router";
249
+ import { createDecoRouter } from "@decocms/tanstack";
250
250
  import { routeTree } from "./routeTree.gen";
251
251
  import "./setup";
252
252
 
@@ -274,16 +274,16 @@ declare module "@tanstack/react-router" {
274
274
 
275
275
  function generateRuntime(): string {
276
276
  return `/**
277
- * Runtime invoke proxy — re-exports the framework canonical from @decocms/start/sdk.
277
+ * Runtime invoke proxy — re-exports the framework canonical from @decocms/blocks/sdk/invoke.
278
278
  *
279
279
  * The implementation (typed RPC over /deco/invoke, dotted-path proxy, .ts
280
- * suffix fallback) lives in @decocms/start/sdk/invoke. This file exists so
280
+ * suffix fallback) lives in @decocms/blocks/sdk/invoke. This file exists so
281
281
  * existing site code can keep \`import { invoke } from "~/runtime"\` and
282
282
  * \`Runtime.invoke\` shapes without churn.
283
283
  *
284
- * Don't reimplement here — extend @decocms/start/sdk/invoke instead.
284
+ * Don't reimplement here — extend @decocms/blocks/sdk/invoke instead.
285
285
  */
286
- import { invoke } from "@decocms/start/sdk";
286
+ import { invoke } from "@decocms/blocks/sdk/invoke";
287
287
 
288
288
  export { invoke };
289
289
 
@@ -328,14 +328,14 @@ export const invoke = {} as const;
328
328
  */
329
329
  import { createServerFn } from "@tanstack/react-start";
330
330
  import { getRequestHeader } from "@tanstack/react-start/server";
331
- import { forwardResponseCookies } from "@decocms/start/sdk/cookiePassthrough";
331
+ import { forwardResponseCookies } from "@decocms/tanstack/sdk/cookiePassthrough";
332
332
  import { vtexActions } from "./invoke.gen";
333
333
  ${hasVtexAuthLoader ? `import vtexAuthLoader from "../loaders/vtex-auth-loader";\n` : ""}import {
334
334
  extractVtexCookiesFromHeader,
335
335
  stripCookieDomain,
336
336
  performVtexLogout,
337
337
  parseVtexAuthJwt,
338
- } from "@decocms/apps/vtex/utils/authHelpers";
338
+ } from "@decocms/apps-vtex/utils/authHelpers";
339
339
 
340
340
  export type { OrderForm } from "./invoke.gen";
341
341
 
@@ -398,17 +398,17 @@ export const vtexActions = {} as const;
398
398
  // Each server function is a top-level const so TanStack Start's compiler
399
399
  // can transform createServerFn().handler() into RPC stubs on the client.
400
400
  import { createServerFn } from "@tanstack/react-start";
401
- import { getOrCreateCart, addItemsToCart, updateCartItems, addCouponToCart, simulateCart, getSellersByRegion, setShippingPostalCode, updateOrderFormAttachment } from "@decocms/apps/vtex/actions/checkout";
402
- import { createSession, editSession } from "@decocms/apps/vtex/actions/session";
403
- import { createDocument, getDocument, patchDocument, searchDocuments, uploadAttachment } from "@decocms/apps/vtex/actions/masterData";
404
- import { subscribe } from "@decocms/apps/vtex/actions/newsletter";
405
- import { notifyMe } from "@decocms/apps/vtex/actions/misc";
406
- import type { OrderForm } from "@decocms/apps/vtex/types";
407
- import type { SimulationItem, RegionResult } from "@decocms/apps/vtex/actions/checkout";
408
- import type { SessionData } from "@decocms/apps/vtex/actions/session";
409
- import type { CreateDocumentResult, UploadAttachmentOpts } from "@decocms/apps/vtex/actions/masterData";
410
- import type { SubscribeProps } from "@decocms/apps/vtex/actions/newsletter";
411
- import type { NotifyMeProps } from "@decocms/apps/vtex/actions/misc";
401
+ import { getOrCreateCart, addItemsToCart, updateCartItems, addCouponToCart, simulateCart, getSellersByRegion, setShippingPostalCode, updateOrderFormAttachment } from "@decocms/apps-vtex/actions/checkout";
402
+ import { createSession, editSession } from "@decocms/apps-vtex/actions/session";
403
+ import { createDocument, getDocument, patchDocument, searchDocuments, uploadAttachment } from "@decocms/apps-vtex/actions/masterData";
404
+ import { subscribe } from "@decocms/apps-vtex/actions/newsletter";
405
+ import { notifyMe } from "@decocms/apps-vtex/actions/misc";
406
+ import type { OrderForm } from "@decocms/apps-vtex/types";
407
+ import type { SimulationItem, RegionResult } from "@decocms/apps-vtex/actions/checkout";
408
+ import type { SessionData } from "@decocms/apps-vtex/actions/session";
409
+ import type { CreateDocumentResult, UploadAttachmentOpts } from "@decocms/apps-vtex/actions/masterData";
410
+ import type { SubscribeProps } from "@decocms/apps-vtex/actions/newsletter";
411
+ import type { NotifyMeProps } from "@decocms/apps-vtex/actions/misc";
412
412
 
413
413
  function unwrapResult<T>(result: unknown): T {
414
414
  if (result && typeof result === "object" && "data" in result) {
@@ -549,7 +549,7 @@ export const vtexActions = {
549
549
  notifyMe: $notifyMe as unknown as (ctx: { data: NotifyMeProps }) => Promise<void>,
550
550
  } as const;
551
551
 
552
- export type { OrderForm } from "@decocms/apps/vtex/types";
552
+ export type { OrderForm } from "@decocms/apps-vtex/types";
553
553
 
554
554
  export const invoke = {
555
555
  vtex: {
@@ -93,15 +93,15 @@ import "./cache-config";
93
93
  import {
94
94
  registerCommerceLoaders,
95
95
  applySectionConventions,
96
- } from "@decocms/start/cms";
97
- import { createSiteSetup } from "@decocms/start/setup";
98
- import { setInvokeLoaders } from "@decocms/start/admin";${isVtex ? `
99
- import { createInstrumentedFetch } from "@decocms/start/sdk/instrumentedFetch";
100
- import { initVtexFromBlocks, setVtexFetch } from "@decocms/apps/vtex";` : ""}${hasLocationMatcher ? `
96
+ } from "@decocms/blocks/cms";
97
+ import { createSiteSetup } from "@decocms/blocks/setup";
98
+ import { setInvokeLoaders } from "@decocms/blocks-admin";${isVtex ? `
99
+ import { createInstrumentedFetch } from "@decocms/blocks/sdk/instrumentedFetch";
100
+ import { initVtexFromBlocks, setVtexFetch } from "@decocms/apps-vtex";` : ""}${hasLocationMatcher ? `
101
101
  import { registerLocationMatcher } from "./matchers/location";` : ""}
102
102
  import { blocks as generatedBlocks } from "../.deco/blocks.gen";
103
103
  import { sectionMeta, syncComponents, loadingFallbacks } from "../.deco/sections.gen";
104
- import { PreviewProviders } from "@decocms/start/hooks";
104
+ import { PreviewProviders } from "@decocms/tanstack";
105
105
  // @ts-ignore Vite ?url import
106
106
  import appCss from "./styles/app.css?url";
107
107
 
@@ -5,7 +5,7 @@ export function generateTypeFiles(ctx: MigrationContext): Record<string, string>
5
5
 
6
6
  // src/types/widgets.ts is no longer generated — the framework owns these
7
7
  // string aliases (`ImageWidget`, `HTMLWidget`, …) at
8
- // `@decocms/start/types/widgets`, and `transforms/imports.ts` rewrites
8
+ // `@decocms/blocks/types/widgets`, and `transforms/imports.ts` rewrites
9
9
  // `apps/admin/widgets.ts` directly to that path. Schema generation
10
10
  // works the same way: the generator matches by type *text*, not module
11
11
  // identity (see scripts/generate-schema.ts:WIDGET_TYPE_FORMATS).
@@ -99,7 +99,7 @@ export type AppContext = {
99
99
  export type LegacyAppContext = AppContext;
100
100
  `;
101
101
 
102
- files["src/types/vtex-loaders.ts"] = `import type { Product, ProductListingPage } from "@decocms/apps/commerce/types";
102
+ files["src/types/vtex-loaders.ts"] = `import type { Product, ProductListingPage } from "@decocms/apps-commerce/types";
103
103
 
104
104
  export interface ProductListProps {
105
105
  page: ProductListingPage | null;
@@ -13,7 +13,7 @@ export function generateUiComponents(_ctx: MigrationContext): Record<string, str
13
13
  FACTORS,
14
14
  type ImageProps,
15
15
  type FitOptions,
16
- } from "@decocms/apps/commerce/components/Image";
16
+ } from "@decocms/blocks/hooks";
17
17
  `;
18
18
 
19
19
  files["src/components/ui/Picture.tsx"] = `import type { ReactNode } from "react";
@@ -22,7 +22,7 @@ import {
22
22
  getSrcSet,
23
23
  type FitOptions,
24
24
  type ImageProps,
25
- } from "@decocms/apps/commerce/components/Image";
25
+ } from "@decocms/blocks/hooks";
26
26
 
27
27
  export interface PictureSourceProps {
28
28
  src: string;
@@ -1,7 +1,14 @@
1
1
  import type { MigrationContext } from "../types";
2
2
 
3
+ const PLATFORM_PACKAGE: Partial<Record<MigrationContext["platform"], string>> = {
4
+ vtex: "@decocms/apps-vtex",
5
+ shopify: "@decocms/apps-shopify",
6
+ magento: "@decocms/apps-magento",
7
+ };
8
+
3
9
  export function generateViteConfig(ctx: MigrationContext): string {
4
10
  const isVtex = ctx.platform === "vtex";
11
+ const platformDep = PLATFORM_PACKAGE[ctx.platform];
5
12
 
6
13
  const vtexAccount = ctx.vtexAccount || ctx.siteName.replace(/-migrated$/, "").replace(/-storefront$/, "");
7
14
 
@@ -29,7 +36,7 @@ const VTEX_ORIGIN = \`https://\${VTEX_ACCOUNT}.\${VTEX_ENVIRONMENT}.\${VTEX_DOMA
29
36
 
30
37
  return `import { cloudflare } from "@cloudflare/vite-plugin";
31
38
  import { tanstackStart } from "@tanstack/react-start/plugin/vite";
32
- import { decoVitePlugin } from "@decocms/start/vite";
39
+ import { decoVitePlugin } from "@decocms/tanstack/vite";
33
40
  import react from "@vitejs/plugin-react";
34
41
  import tailwindcss from "@tailwindcss/vite";
35
42
  import { defineConfig } from "vite";
@@ -80,8 +87,10 @@ export default defineConfig({
80
87
  },
81
88
  resolve: {
82
89
  dedupe: [
83
- "@decocms/start",
84
- "@decocms/apps",
90
+ "@decocms/blocks",
91
+ "@decocms/blocks-admin",
92
+ "@decocms/tanstack",
93
+ "@decocms/apps-commerce",${platformDep ? `\n "${platformDep}",` : ""}
85
94
  "@tanstack/react-start",
86
95
  "@tanstack/react-router",
87
96
  "@tanstack/react-start-server",
@@ -165,10 +165,10 @@ export function transformFreshApis(content: string): TransformResult {
165
165
  if (result.includes("scriptAsDataURI")) {
166
166
  // Ensure useScript is imported
167
167
  if (
168
- !result.includes('"@decocms/start/sdk/useScript"') &&
169
- !result.includes("'@decocms/start/sdk/useScript'")
168
+ !result.includes('"@decocms/blocks/sdk/useScript"') &&
169
+ !result.includes("'@decocms/blocks/sdk/useScript'")
170
170
  ) {
171
- result = `import { useScript } from "@decocms/start/sdk/useScript";\n${result}`;
171
+ result = `import { useScript } from "@decocms/blocks/sdk/useScript";\n${result}`;
172
172
  }
173
173
 
174
174
  // Transform src={scriptAsDataURI(...)} into dangerouslySetInnerHTML={{ __html: useScript(...) }}
@@ -190,7 +190,7 @@ export function transformFreshApis(content: string): TransformResult {
190
190
  notes.push("Replaced scriptAsDataURI with useScript + dangerouslySetInnerHTML");
191
191
  }
192
192
 
193
- // allowCorsFor — not available in @decocms/start, remove usage
193
+ // allowCorsFor — not available in @decocms/blocks, remove usage
194
194
  if (result.includes("allowCorsFor")) {
195
195
  result = result.replace(
196
196
  /^import\s+\{[^}]*\ballowCorsFor\b[^}]*\}\s+from\s+["'][^"']+["'];?\s*\n?/gm,
@@ -204,7 +204,7 @@ export function transformFreshApis(content: string): TransformResult {
204
204
 
205
205
  // ctx.response.headers → not available, flag
206
206
  if (result.includes("ctx.response")) {
207
- notes.push("MANUAL: ctx.response usage found — FnContext in @decocms/start does not have response object");
207
+ notes.push("MANUAL: ctx.response usage found — FnContext in @decocms/blocks does not have response object");
208
208
  }
209
209
 
210
210
  // { crypto } from "@std/crypto" → use globalThis.crypto (Web Crypto API)