@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.
- package/package.json +2 -2
- package/scripts/generate-invoke.ts +10 -0
- package/scripts/generate-schema.ts +46 -15
- package/scripts/generate-sections.test.ts +67 -0
- package/scripts/generate-sections.ts +16 -2
- package/scripts/lib/codegenExclusions.test.ts +16 -6
- package/scripts/lib/codegenExclusions.ts +13 -1
- package/scripts/migrate/analyzers/loader-inventory.ts +1 -1
- package/scripts/migrate/phase-analyze.ts +3 -3
- package/scripts/migrate/phase-cleanup.test.ts +70 -1
- package/scripts/migrate/phase-cleanup.ts +47 -26
- package/scripts/migrate/phase-report.ts +7 -7
- package/scripts/migrate/phase-scaffold.ts +4 -4
- package/scripts/migrate/phase-transform.ts +1 -1
- package/scripts/migrate/phase-verify.ts +6 -5
- package/scripts/migrate/post-cleanup/rules.ts +55 -44
- package/scripts/migrate/post-cleanup/runner.test.ts +58 -34
- package/scripts/migrate/templates/cache-config.ts +4 -4
- package/scripts/migrate/templates/commerce-loaders.ts +10 -10
- package/scripts/migrate/templates/cursor-rules.test.ts +6 -0
- package/scripts/migrate/templates/cursor-rules.ts +12 -11
- package/scripts/migrate/templates/hooks.test.ts +7 -7
- package/scripts/migrate/templates/hooks.ts +10 -10
- package/scripts/migrate/templates/lib-utils.test.ts +2 -2
- package/scripts/migrate/templates/lib-utils.ts +4 -4
- package/scripts/migrate/templates/no-legacy-packages.test.ts +147 -0
- package/scripts/migrate/templates/package-json.ts +30 -10
- package/scripts/migrate/templates/routes.ts +8 -10
- package/scripts/migrate/templates/sdk-gen.ts +1 -1
- package/scripts/migrate/templates/section-loaders.ts +7 -7
- package/scripts/migrate/templates/server-entry.ts +37 -37
- package/scripts/migrate/templates/setup.ts +6 -6
- package/scripts/migrate/templates/types-gen.ts +2 -2
- package/scripts/migrate/templates/ui-components.ts +2 -2
- package/scripts/migrate/templates/vite-config.ts +12 -3
- package/scripts/migrate/transforms/fresh-apis.ts +5 -5
- package/scripts/migrate/transforms/imports.test.ts +138 -0
- package/scripts/migrate/transforms/imports.ts +65 -43
- package/scripts/migrate/transforms/jsx.ts +8 -0
- package/scripts/migrate/transforms/section-conventions.ts +1 -1
- package/scripts/migrate/types.ts +1 -1
- package/scripts/migrate-post-cleanup.ts +8 -8
- 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
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
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/
|
|
128
|
+
"tsx node_modules/@decocms/blocks-cli/scripts/generate-blocks.ts",
|
|
113
129
|
"generate:routes": "tsr generate",
|
|
114
|
-
"generate:schema": `tsx node_modules/@decocms/
|
|
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/
|
|
132
|
+
"tsx node_modules/@decocms/blocks-cli/scripts/generate-invoke.ts",
|
|
117
133
|
"generate:sections":
|
|
118
|
-
"tsx node_modules/@decocms/
|
|
119
|
-
"generate:loaders": `tsx node_modules/@decocms/
|
|
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/
|
|
145
|
-
"@decocms/
|
|
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/
|
|
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,
|
|
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={
|
|
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,
|
|
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={
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
74
|
+
lines.push(`} from "@decocms/blocks/cms";`);
|
|
75
75
|
|
|
76
76
|
if (hasSearchResult) {
|
|
77
|
-
lines.push(`import { detectDevice } from "@decocms/
|
|
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
|
|
81
|
+
lines.push(`import { getVtexConfig } from "@decocms/apps-vtex";`);
|
|
82
82
|
if (hasWishlistSection && hasWishlistLoaders) {
|
|
83
|
-
lines.push(`import { getUser } from "@decocms/apps
|
|
84
|
-
lines.push(`import { getVtexCookies } from "@decocms/apps
|
|
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
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
70
|
-
import { instrumentWorker } from "@decocms/
|
|
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/
|
|
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
|
|
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/
|
|
114
|
-
import { instrumentWorker } from "@decocms/
|
|
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/
|
|
122
|
-
import { shouldProxyToVtex, createVtexCheckoutProxy } from "@decocms/apps
|
|
123
|
-
import { extractVtexContext } from "@decocms/apps
|
|
124
|
-
import { loadRedirects, matchRedirect } from "@decocms/
|
|
125
|
-
import { withABTesting } from "@decocms/
|
|
126
|
-
import { loadBlocks } from "@decocms/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
284
|
+
* Don't reimplement here — extend @decocms/blocks/sdk/invoke instead.
|
|
285
285
|
*/
|
|
286
|
-
import { invoke } from "@decocms/
|
|
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/
|
|
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
|
|
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
|
|
402
|
-
import { createSession, editSession } from "@decocms/apps
|
|
403
|
-
import { createDocument, getDocument, patchDocument, searchDocuments, uploadAttachment } from "@decocms/apps
|
|
404
|
-
import { subscribe } from "@decocms/apps
|
|
405
|
-
import { notifyMe } from "@decocms/apps
|
|
406
|
-
import type { OrderForm } from "@decocms/apps
|
|
407
|
-
import type { SimulationItem, RegionResult } from "@decocms/apps
|
|
408
|
-
import type { SessionData } from "@decocms/apps
|
|
409
|
-
import type { CreateDocumentResult, UploadAttachmentOpts } from "@decocms/apps
|
|
410
|
-
import type { SubscribeProps } from "@decocms/apps
|
|
411
|
-
import type { NotifyMeProps } from "@decocms/apps
|
|
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
|
|
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/
|
|
97
|
-
import { createSiteSetup } from "@decocms/
|
|
98
|
-
import { setInvokeLoaders } from "@decocms/
|
|
99
|
-
import { createInstrumentedFetch } from "@decocms/
|
|
100
|
-
import { initVtexFromBlocks, setVtexFetch } from "@decocms/apps
|
|
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/
|
|
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/
|
|
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
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
84
|
-
"@decocms/
|
|
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/
|
|
169
|
-
!result.includes("'@decocms/
|
|
168
|
+
!result.includes('"@decocms/blocks/sdk/useScript"') &&
|
|
169
|
+
!result.includes("'@decocms/blocks/sdk/useScript'")
|
|
170
170
|
) {
|
|
171
|
-
result = `import { useScript } from "@decocms/
|
|
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/
|
|
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/
|
|
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)
|