@decocms/start 0.41.0 → 0.42.1
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/README.md
CHANGED
|
@@ -79,13 +79,19 @@ The skill handles compatibility checking, import rewrites, config generation, se
|
|
|
79
79
|
### Or run the script manually
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
# From
|
|
83
|
-
npx
|
|
84
|
-
|
|
85
|
-
# Preview first without writing:
|
|
86
|
-
npx tsx node_modules/@decocms/start/scripts/migrate.ts --source /path/to/fresh-site --dry-run --verbose
|
|
82
|
+
# From your Fresh site directory (nothing to install beforehand):
|
|
83
|
+
npx -p @decocms/start deco-migrate
|
|
87
84
|
```
|
|
88
85
|
|
|
86
|
+
**Options:**
|
|
87
|
+
|
|
88
|
+
| Flag | Description |
|
|
89
|
+
|------|-------------|
|
|
90
|
+
| `--source <dir>` | Source directory (default: current directory) |
|
|
91
|
+
| `--dry-run` | Preview changes without writing files |
|
|
92
|
+
| `--verbose` | Show detailed output |
|
|
93
|
+
| `--help`, `-h` | Show help message |
|
|
94
|
+
|
|
89
95
|
The script runs 7 phases automatically:
|
|
90
96
|
|
|
91
97
|
1. **Analyze** — scan source, detect Preact/Fresh/Deco patterns
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/start",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deco framework for TanStack Start - CMS bridge, admin protocol, hooks, schema generation",
|
|
6
6
|
"main": "./src/index.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"deco-migrate": "./scripts/migrate.ts"
|
|
9
|
+
},
|
|
7
10
|
"exports": {
|
|
8
11
|
".": "./src/index.ts",
|
|
9
12
|
"./cms": "./src/cms/index.ts",
|
|
@@ -80,6 +83,9 @@
|
|
|
80
83
|
"registry": "https://registry.npmjs.org",
|
|
81
84
|
"access": "public"
|
|
82
85
|
},
|
|
86
|
+
"dependencies": {
|
|
87
|
+
"tsx": "^4.19.0"
|
|
88
|
+
},
|
|
83
89
|
"peerDependencies": {
|
|
84
90
|
"@tanstack/react-start": ">=1.0.0",
|
|
85
91
|
"@tanstack/store": ">=0.7.0",
|
|
@@ -172,8 +172,7 @@ ${gtmScript}
|
|
|
172
172
|
|
|
173
173
|
function generateIndex(siteTitle: string): string {
|
|
174
174
|
return `import { createFileRoute } from "@tanstack/react-router";
|
|
175
|
-
import { cmsHomeRouteConfig,
|
|
176
|
-
import { DecoPageRenderer } from "@decocms/start/hooks";
|
|
175
|
+
import { cmsHomeRouteConfig, CmsPage, NotFoundPage } from "@decocms/start/routes";
|
|
177
176
|
|
|
178
177
|
export const Route = createFileRoute("/")({
|
|
179
178
|
...cmsHomeRouteConfig({
|
|
@@ -185,26 +184,15 @@ export const Route = createFileRoute("/")({
|
|
|
185
184
|
|
|
186
185
|
function HomePage() {
|
|
187
186
|
const data = Route.useLoaderData() as Record<string, any> | null;
|
|
188
|
-
|
|
189
|
-
if (!data) {
|
|
190
|
-
return (
|
|
191
|
-
<div className="min-h-screen flex items-center justify-center">
|
|
192
|
-
<div className="text-center">
|
|
193
|
-
<h1 className="text-4xl font-bold mb-4">${siteTitle}</h1>
|
|
194
|
-
<p className="text-sm text-base-content/40 mt-2">Nenhuma pagina CMS encontrada para /</p>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
);
|
|
198
|
-
}
|
|
187
|
+
if (!data) return <NotFoundPage />;
|
|
199
188
|
|
|
200
189
|
return (
|
|
201
|
-
<
|
|
190
|
+
<CmsPage
|
|
202
191
|
sections={data.resolvedSections ?? []}
|
|
203
192
|
deferredSections={data.deferredSections ?? []}
|
|
204
193
|
deferredPromises={data.deferredPromises}
|
|
205
194
|
pagePath={data.pagePath}
|
|
206
195
|
pageUrl={data.pageUrl}
|
|
207
|
-
loadDeferredSectionFn={deferredSectionLoader}
|
|
208
196
|
/>
|
|
209
197
|
);
|
|
210
198
|
}
|
|
@@ -213,8 +201,7 @@ function HomePage() {
|
|
|
213
201
|
|
|
214
202
|
function generateCatchAll(siteTitle: string): string {
|
|
215
203
|
return `import { createFileRoute } from "@tanstack/react-router";
|
|
216
|
-
import { cmsRouteConfig,
|
|
217
|
-
import { DecoPageRenderer } from "@decocms/start/hooks";
|
|
204
|
+
import { cmsRouteConfig, CmsPage, NotFoundPage } from "@decocms/start/routes";
|
|
218
205
|
|
|
219
206
|
const routeConfig = cmsRouteConfig({
|
|
220
207
|
siteName: "${siteTitle}",
|
|
@@ -223,38 +210,25 @@ const routeConfig = cmsRouteConfig({
|
|
|
223
210
|
|
|
224
211
|
export const Route = createFileRoute("/$")({
|
|
225
212
|
...routeConfig,
|
|
226
|
-
component:
|
|
213
|
+
component: CatchAllPage,
|
|
227
214
|
notFoundComponent: NotFoundPage,
|
|
228
215
|
staleTime: 30_000,
|
|
229
216
|
});
|
|
230
217
|
|
|
231
|
-
function
|
|
218
|
+
function CatchAllPage() {
|
|
232
219
|
const data = Route.useLoaderData() as Record<string, any> | null;
|
|
233
220
|
if (!data) return <NotFoundPage />;
|
|
234
221
|
|
|
235
222
|
return (
|
|
236
|
-
<
|
|
223
|
+
<CmsPage
|
|
237
224
|
sections={data.resolvedSections ?? []}
|
|
238
225
|
deferredSections={data.deferredSections ?? []}
|
|
239
226
|
deferredPromises={data.deferredPromises}
|
|
240
227
|
pagePath={data.pagePath}
|
|
241
228
|
pageUrl={data.pageUrl}
|
|
242
|
-
loadDeferredSectionFn={deferredSectionLoader}
|
|
243
229
|
/>
|
|
244
230
|
);
|
|
245
231
|
}
|
|
246
|
-
|
|
247
|
-
function NotFoundPage() {
|
|
248
|
-
return (
|
|
249
|
-
<div className="min-h-screen flex items-center justify-center">
|
|
250
|
-
<div className="text-center">
|
|
251
|
-
<h1 className="text-6xl font-bold text-base-content/20 mb-4">404</h1>
|
|
252
|
-
<h2 className="text-2xl font-bold mb-2">Pagina nao encontrada</h2>
|
|
253
|
-
<a href="/" className="btn btn-primary">Voltar para Home</a>
|
|
254
|
-
</div>
|
|
255
|
-
</div>
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
232
|
`;
|
|
259
233
|
}
|
|
260
234
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { MigrationContext } from "../types.ts";
|
|
2
2
|
|
|
3
|
+
function capitalize(s: string): string {
|
|
4
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
export function generateServerEntry(
|
|
4
8
|
ctx: MigrationContext,
|
|
5
9
|
): Record<string, string> {
|
|
@@ -22,13 +26,41 @@ export default createStartHandler(defaultStreamHandler);
|
|
|
22
26
|
`;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
function generateWorkerEntry(
|
|
29
|
+
function generateWorkerEntry(ctx: MigrationContext): string {
|
|
30
|
+
const isCommerce = ctx.platform !== "custom";
|
|
31
|
+
const proxyImport = isCommerce
|
|
32
|
+
? `\n// Uncomment to enable checkout/API proxy for ${ctx.platform}:
|
|
33
|
+
// import { shouldProxyTo${ctx.platform === "vtex" ? "Vtex" : capitalize(ctx.platform)}, proxyTo${ctx.platform === "vtex" ? "Vtex" : capitalize(ctx.platform)} } from "@decocms/apps/${ctx.platform}/utils/proxy";\n`
|
|
34
|
+
: "";
|
|
35
|
+
|
|
36
|
+
const proxyOption = isCommerce
|
|
37
|
+
? `
|
|
38
|
+
// Uncomment to enable checkout/API proxy for ${ctx.platform}:
|
|
39
|
+
// proxyHandler: (request, url) => {
|
|
40
|
+
// if (shouldProxyTo${ctx.platform === "vtex" ? "Vtex" : capitalize(ctx.platform)}(url.pathname)) {
|
|
41
|
+
// return proxyTo${ctx.platform === "vtex" ? "Vtex" : capitalize(ctx.platform)}(request);
|
|
42
|
+
// }
|
|
43
|
+
// return null;
|
|
44
|
+
// },`
|
|
45
|
+
: "";
|
|
46
|
+
|
|
47
|
+
const segmentOption = ctx.platform === "vtex"
|
|
48
|
+
? `
|
|
49
|
+
// Uncomment for per-sales-channel/region cache segmentation:
|
|
50
|
+
// buildSegment: (request) => {
|
|
51
|
+
// const ua = request.headers.get("user-agent") ?? "";
|
|
52
|
+
// return {
|
|
53
|
+
// device: /mobile|android|iphone/i.test(ua) ? "mobile" : "desktop",
|
|
54
|
+
// // loggedIn: true bypasses cache automatically
|
|
55
|
+
// };
|
|
56
|
+
// },`
|
|
57
|
+
: "";
|
|
58
|
+
|
|
26
59
|
return `/**
|
|
27
60
|
* Cloudflare Worker entry point.
|
|
28
61
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* A/B testing as needed.
|
|
62
|
+
* Wraps TanStack Start with admin protocol handlers and edge caching.
|
|
63
|
+
* For commerce sites, uncomment proxyHandler and buildSegment options.
|
|
32
64
|
*/
|
|
33
65
|
import "./setup";
|
|
34
66
|
import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
|
|
@@ -40,7 +72,7 @@ import {
|
|
|
40
72
|
handleRender,
|
|
41
73
|
corsHeaders,
|
|
42
74
|
} from "@decocms/start/admin";
|
|
43
|
-
|
|
75
|
+
${proxyImport}
|
|
44
76
|
const serverEntry = createServerEntry({ fetch: handler.fetch });
|
|
45
77
|
|
|
46
78
|
export default createDecoWorkerEntry(serverEntry, {
|
|
@@ -50,7 +82,7 @@ export default createDecoWorkerEntry(serverEntry, {
|
|
|
50
82
|
handleDecofileReload,
|
|
51
83
|
handleRender,
|
|
52
84
|
corsHeaders,
|
|
53
|
-
}
|
|
85
|
+
},${proxyOption}${segmentOption}
|
|
54
86
|
});
|
|
55
87
|
`;
|
|
56
88
|
}
|
|
@@ -113,36 +145,9 @@ function generateRuntime(): string {
|
|
|
113
145
|
* invoke.vtex.loaders.productList(props)
|
|
114
146
|
* → POST /deco/invoke/vtex/loaders/productList
|
|
115
147
|
*/
|
|
116
|
-
|
|
117
|
-
return new Proxy(
|
|
118
|
-
Object.assign(async (props: any) => {
|
|
119
|
-
const key = path.join("/");
|
|
120
|
-
for (const k of [key, \`\${key}.ts\`]) {
|
|
121
|
-
const response = await fetch(\`/deco/invoke/\${k}\`, {
|
|
122
|
-
method: "POST",
|
|
123
|
-
headers: { "Content-Type": "application/json" },
|
|
124
|
-
body: JSON.stringify(props ?? {}),
|
|
125
|
-
});
|
|
126
|
-
if (response.status === 404) continue;
|
|
127
|
-
if (!response.ok) {
|
|
128
|
-
throw new Error(\`invoke(\${k}) failed: \${response.status}\`);
|
|
129
|
-
}
|
|
130
|
-
return response.json();
|
|
131
|
-
}
|
|
132
|
-
throw new Error(\`invoke(\${key}) failed: handler not found\`);
|
|
133
|
-
}, {}),
|
|
134
|
-
{
|
|
135
|
-
get(_target: any, prop: string) {
|
|
136
|
-
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
return createNestedInvokeProxy([...path, prop]);
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
);
|
|
143
|
-
}
|
|
148
|
+
import { createAppInvoke } from "@decocms/start/sdk/invoke";
|
|
144
149
|
|
|
145
|
-
export const invoke =
|
|
150
|
+
export const invoke = createAppInvoke();
|
|
146
151
|
export const Runtime = { invoke };
|
|
147
152
|
`;
|
|
148
153
|
}
|
|
@@ -34,7 +34,7 @@ ${layoutSections.map((s) => ` "${s}",`).join("\n")}
|
|
|
34
34
|
return `/**
|
|
35
35
|
* Site setup — registers all sections, loaders and matchers with the CMS.
|
|
36
36
|
*
|
|
37
|
-
* This file is imported by router.tsx at startup.
|
|
37
|
+
* This file is imported by router.tsx and worker-entry.ts at startup.
|
|
38
38
|
* It uses import.meta.glob to lazily discover all section components.
|
|
39
39
|
*/
|
|
40
40
|
import { blocks as generatedBlocks } from "./server/cms/blocks.gen";
|
|
@@ -49,7 +49,8 @@ import { autoconfigApps } from "@decocms/start/apps/autoconfig";
|
|
|
49
49
|
// The Vite plugin intercepts the blocks.gen import and injects .deco/blocks/ data.
|
|
50
50
|
if (typeof document === "undefined") {
|
|
51
51
|
setBlocks(generatedBlocks);
|
|
52
|
-
// Auto-configure apps
|
|
52
|
+
// Auto-configure apps from CMS blocks — registers invoke handlers,
|
|
53
|
+
// app state, and middleware (cookie forwarding, etc.)
|
|
53
54
|
autoconfigApps(generatedBlocks);
|
|
54
55
|
}
|
|
55
56
|
|
package/scripts/migrate.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Converts a Deco storefront from the old Fresh/Deno stack to the new TanStack Start stack.
|
|
6
6
|
* Part of the @decocms/start framework — run from a site's root directory.
|
|
7
7
|
*
|
|
8
|
-
* Usage (from site
|
|
9
|
-
* npx
|
|
8
|
+
* Usage (from your Fresh site directory):
|
|
9
|
+
* npx -p @decocms/start deco-migrate [options]
|
|
10
10
|
*
|
|
11
11
|
* Options:
|
|
12
12
|
* --source <dir> Source directory (default: current directory)
|
|
@@ -71,7 +71,7 @@ function showHelp() {
|
|
|
71
71
|
@decocms/start — Migration Script: Fresh/Deno → TanStack Start
|
|
72
72
|
|
|
73
73
|
Usage:
|
|
74
|
-
npx
|
|
74
|
+
npx -p @decocms/start deco-migrate [options]
|
|
75
75
|
|
|
76
76
|
Options:
|
|
77
77
|
--source <dir> Source directory (default: .)
|
|
@@ -80,9 +80,9 @@ function showHelp() {
|
|
|
80
80
|
--help, -h Show this help message
|
|
81
81
|
|
|
82
82
|
Examples:
|
|
83
|
-
npx
|
|
84
|
-
npx
|
|
85
|
-
npx
|
|
83
|
+
npx -p @decocms/start deco-migrate --dry-run --verbose
|
|
84
|
+
npx -p @decocms/start deco-migrate --source ./my-site
|
|
85
|
+
npx -p @decocms/start deco-migrate
|
|
86
86
|
`);
|
|
87
87
|
}
|
|
88
88
|
|
package/src/sdk/workerEntry.ts
CHANGED
|
@@ -37,6 +37,7 @@ import { cleanPathForCacheKey } from "./urlUtils";
|
|
|
37
37
|
import { isMobileUA } from "./useDevice";
|
|
38
38
|
import { getRenderShellConfig } from "../admin/setup";
|
|
39
39
|
import { RequestContext } from "./requestContext";
|
|
40
|
+
import { getAppMiddleware } from "./setupApps";
|
|
40
41
|
import type { MatcherContext } from "../cms/resolve";
|
|
41
42
|
import { resolveDecoPage } from "../cms/resolve";
|
|
42
43
|
import { runSectionLoaders } from "../cms/sectionLoaders";
|
|
@@ -661,6 +662,22 @@ export function createDecoWorkerEntry(
|
|
|
661
662
|
// in the call stack (loaders, invoke handlers, vtexFetchWithCookies)
|
|
662
663
|
// can access the request and write response headers.
|
|
663
664
|
return RequestContext.run(request, async () => {
|
|
665
|
+
// Run app middleware (injects app state into RequestContext.bag,
|
|
666
|
+
// runs registered middleware like VTEX cookie forwarding).
|
|
667
|
+
const appMw = getAppMiddleware();
|
|
668
|
+
if (appMw) {
|
|
669
|
+
return appMw(request, () => handleRequest(request, env, ctx));
|
|
670
|
+
}
|
|
671
|
+
return handleRequest(request, env, ctx);
|
|
672
|
+
});
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
async function handleRequest(
|
|
677
|
+
request: Request,
|
|
678
|
+
env: Record<string, unknown>,
|
|
679
|
+
ctx: WorkerExecutionContext,
|
|
680
|
+
): Promise<Response> {
|
|
664
681
|
const url = new URL(request.url);
|
|
665
682
|
|
|
666
683
|
// Admin routes (/_meta, /.decofile, /live/previews) — always handled first
|
|
@@ -921,7 +938,5 @@ export function createDecoWorkerEntry(
|
|
|
921
938
|
// the stream in Workers runtime, causing Error 1101.
|
|
922
939
|
storeInCache(origin);
|
|
923
940
|
return dressResponse(origin, "MISS");
|
|
924
|
-
|
|
925
|
-
},
|
|
926
|
-
};
|
|
941
|
+
}
|
|
927
942
|
}
|