@decocms/start 1.4.1 → 1.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/start",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
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",
package/src/cms/loader.ts CHANGED
@@ -196,13 +196,13 @@ export function getSiteSeo(): {
196
196
 
197
197
  export function findPageByPath(
198
198
  targetPath: string,
199
- ): { page: DecoPage; params: Record<string, string> } | null {
199
+ ): { page: DecoPage; params: Record<string, string>; blockKey: string } | null {
200
200
  const allPages = getAllPages();
201
201
 
202
- for (const { page } of allPages) {
202
+ for (const { key, page } of allPages) {
203
203
  if (!page.path) continue;
204
204
  const params = matchPath(page.path, targetPath);
205
- if (params !== null) return { page, params };
205
+ if (params !== null) return { page, params, blockKey: key };
206
206
  }
207
207
 
208
208
  return null;
@@ -1262,6 +1262,8 @@ export interface DecoPageResult {
1262
1262
  name: string;
1263
1263
  path: string;
1264
1264
  params: Record<string, string>;
1265
+ /** CMS block key, e.g. "pages-Lista de cupons [APP]-397629" */
1266
+ blockKey?: string;
1265
1267
  resolvedSections: ResolvedSection[];
1266
1268
  deferredSections: DeferredSection[];
1267
1269
  /**
@@ -1285,7 +1287,7 @@ export async function resolveDecoPage(
1285
1287
  return null;
1286
1288
  }
1287
1289
 
1288
- const { page, params } = match;
1290
+ const { page, params, blockKey } = match;
1289
1291
  const ctx: MatcherContext = { ...matcherCtx, path: targetPath };
1290
1292
  const rctx: ResolveContext = { routeParams: params, matcherCtx: ctx, memo: new Map(), depth: 0 };
1291
1293
 
@@ -1403,6 +1405,7 @@ export async function resolveDecoPage(
1403
1405
  name: page.name,
1404
1406
  path: page.path || targetPath,
1405
1407
  params,
1408
+ blockKey,
1406
1409
  resolvedSections: allResults.flat(),
1407
1410
  deferredSections,
1408
1411
  seoSection,
@@ -38,9 +38,10 @@ import { isMobileUA } from "./useDevice";
38
38
  import { getRenderShellConfig } from "../admin/setup";
39
39
  import { RequestContext } from "./requestContext";
40
40
  import { getAppMiddleware } from "./setupApps";
41
- import type { MatcherContext } from "../cms/resolve";
41
+ import type { MatcherContext, ResolvedSection } from "../cms/resolve";
42
42
  import { resolveDecoPage } from "../cms/resolve";
43
- import { runSectionLoaders } from "../cms/sectionLoaders";
43
+ import { runSectionLoaders, runSingleSectionLoader } from "../cms/sectionLoaders";
44
+ import { loadBlocks } from "../cms/loader";
44
45
 
45
46
  /**
46
47
  * Append Link preload headers for CSS and fonts so the browser starts
@@ -978,10 +979,84 @@ export function createDecoWorkerEntry(
978
979
  return Response.json(null, { status: 404, headers: { "Access-Control-Allow-Origin": "*" } });
979
980
  }
980
981
  const enrichedSections = await runSectionLoaders(page.resolvedSections, request);
981
- const { seoSection: _seo, ...pageData } = page;
982
+
983
+ // Run SEO section loader if registered
984
+ let seoResult = page.seoSection;
985
+ if (seoResult) {
986
+ try {
987
+ seoResult = await runSingleSectionLoader(seoResult, request);
988
+ } catch {
989
+ // use unloaded seoSection
990
+ }
991
+ }
992
+
993
+ // Merge site-wide SEO defaults into seo props
994
+ const blocks = loadBlocks();
995
+ const site = blocks["Site"] as Record<string, unknown> | undefined;
996
+ const fullSiteSeo = (site?.seo as Record<string, unknown>) ?? {};
997
+
998
+ // When SeoV2 loader ran, use its output as base (preserves key order)
999
+ // and only fill in missing fields from the site-wide SEO config.
1000
+ const loaderProps = seoResult?.props ?? {};
1001
+ const seoProps: Record<string, unknown> = { ...loaderProps };
1002
+ for (const [k, v] of Object.entries(fullSiteSeo)) {
1003
+ if (!(k in seoProps)) seoProps[k] = v;
1004
+ }
1005
+ // Strip internal template fields
1006
+ delete seoProps.titleTemplate;
1007
+ delete seoProps.descriptionTemplate;
1008
+
1009
+ // Build resolveChain statically to match legacy deco-cx/deco format.
1010
+ type FieldResolver = { type: string; value: string | number };
1011
+ const rawKey = page.blockKey ?? `pages-${page.name}`;
1012
+ const encodedKey = rawKey.replace(
1013
+ /^(pages-)(.+)$/,
1014
+ (_m, prefix, rest) => prefix + encodeURIComponent(rest),
1015
+ );
1016
+ const pageChain: FieldResolver[] = [
1017
+ { type: "resolver", value: "website/handlers/fresh.ts" },
1018
+ { type: "prop", value: "page" },
1019
+ { type: "resolver", value: "resolved" },
1020
+ { type: "resolvable", value: encodedKey },
1021
+ { type: "resolver", value: "website/pages/Page.tsx" },
1022
+ ];
1023
+
1024
+ const seoChain: FieldResolver[] = [
1025
+ ...pageChain,
1026
+ { type: "prop", value: "seo" },
1027
+ { type: "resolver", value: seoResult?.component ?? "website/sections/Seo/SeoV2.tsx" },
1028
+ ];
1029
+
982
1030
  const result = {
983
- ...pageData,
984
- resolvedSections: enrichedSections,
1031
+ props: {
1032
+ name: page.name,
1033
+ path: page.path,
1034
+ seo: {
1035
+ props: seoProps,
1036
+ metadata: {
1037
+ resolveChain: seoChain,
1038
+ component: seoResult?.component ?? "website/sections/Seo/SeoV2.tsx",
1039
+ },
1040
+ },
1041
+ sections: enrichedSections.map((s, i) => ({
1042
+ props: s.props,
1043
+ metadata: {
1044
+ resolveChain: [
1045
+ ...pageChain,
1046
+ { type: "prop", value: "sections" },
1047
+ { type: "prop", value: String(i) },
1048
+ { type: "resolver", value: s.component },
1049
+ ],
1050
+ component: s.component,
1051
+ },
1052
+ })),
1053
+ devMode: false,
1054
+ unindexedDomain: false,
1055
+ },
1056
+ metadata: {
1057
+ resolveChain: pageChain,
1058
+ component: "website/pages/Page.tsx",
1059
+ },
985
1060
  };
986
1061
  return Response.json(result, {
987
1062
  headers: {
@@ -1418,3 +1493,4 @@ export function createDecoWorkerEntry(
1418
1493
  return dressResponse(origin, "MISS");
1419
1494
  }
1420
1495
  }
1496
+