@decocms/start 0.42.0 → 0.42.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/start",
3
- "version": "0.42.0",
3
+ "version": "0.42.2",
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",
@@ -173,14 +173,14 @@ const checks: Check[] = [
173
173
  },
174
174
  },
175
175
  {
176
- name: "No site/ imports (should be ~/)",
176
+ name: "No site/ or $store/ imports (should be ~/)",
177
177
  severity: "warning",
178
178
  fn: (ctx) => {
179
179
  const srcDir = path.join(ctx.sourceDir, "src");
180
180
  if (!fs.existsSync(srcDir)) return true;
181
- const bad = findFilesWithPattern(srcDir, /from\s+["']site\//);
181
+ const bad = findFilesWithPattern(srcDir, /from\s+["'](site\/|\$store\/)/);
182
182
  if (bad.length > 0) {
183
- console.log(` Still has site/ imports: ${bad.join(", ")}`);
183
+ console.log(` Still has site/ or $store/ imports: ${bad.join(", ")}`);
184
184
  return false;
185
185
  }
186
186
  return true;
@@ -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, deferredSectionLoader } from "@decocms/start/routes";
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
- <DecoPageRenderer
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, deferredSectionLoader } from "@decocms/start/routes";
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: CmsPage,
213
+ component: CatchAllPage,
227
214
  notFoundComponent: NotFoundPage,
228
215
  staleTime: 30_000,
229
216
  });
230
217
 
231
- function CmsPage() {
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
- <DecoPageRenderer
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(_ctx: MigrationContext): string {
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
- * For a simple site without VTEX proxy or A/B testing, this is a thin wrapper
30
- * around the TanStack Start handler. Add proxy logic, security headers, or
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
- function createNestedInvokeProxy(path: string[] = []): any {
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 = createNestedInvokeProxy() as any;
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 (Resend, etc.) from CMS blocks
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
 
@@ -49,6 +49,14 @@ const IMPORT_RULES: Array<[RegExp, string | null]> = [
49
49
  [/^"site\/sdk\/useVariantPossiblities(?:\.tsx?)?.*"$/, `"@decocms/apps/commerce/sdk/useVariantPossibilities"`],
50
50
  [/^"site\/sdk\/usePlatform(?:\.tsx?)?.*"$/, null],
51
51
 
52
+ // $store/ → ~/ (common Deno import map alias for project root)
53
+ [/^"\$store\/sdk\/clx(?:\.tsx?)?.*"$/, `"@decocms/start/sdk/clx"`],
54
+ [/^"\$store\/sdk\/useId(?:\.tsx?)?.*"$/, `"react"`],
55
+ [/^"\$store\/sdk\/useOffer(?:\.tsx?)?.*"$/, `"@decocms/apps/commerce/sdk/useOffer"`],
56
+ [/^"\$store\/sdk\/useVariantPossiblities(?:\.tsx?)?.*"$/, `"@decocms/apps/commerce/sdk/useVariantPossibilities"`],
57
+ [/^"\$store\/sdk\/usePlatform(?:\.tsx?)?.*"$/, null],
58
+ [/^"\$store\/(.+)"$/, `"~/$1"`],
59
+
52
60
  // site/ → ~/
53
61
  [/^"site\/(.+)"$/, `"~/$1"`],
54
62
  ];
@@ -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
- }); // end RequestContext.run()
925
- },
926
- };
941
+ }
927
942
  }