@decocms/blocks 7.41.0 → 7.42.0
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 +1 -1
- package/src/cms/renderJson.test.ts +27 -0
- package/src/cms/renderJson.ts +24 -1
package/package.json
CHANGED
|
@@ -68,6 +68,33 @@ describe("serializeRenderJson", () => {
|
|
|
68
68
|
expect(out).toEqual([{ component: "a", props: {} }]);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
+
it("strips framework-injected keys (__page*, device, isMobile) from props", () => {
|
|
72
|
+
const out = serializeRenderJson(
|
|
73
|
+
[
|
|
74
|
+
{
|
|
75
|
+
component: "a",
|
|
76
|
+
props: {
|
|
77
|
+
title: "keep",
|
|
78
|
+
__pageUrl: "https://x/y",
|
|
79
|
+
__pagePath: "/y",
|
|
80
|
+
device: "mobile",
|
|
81
|
+
isMobile: true,
|
|
82
|
+
currentSearchParam: "q",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
// no projection → pass-through, but injected keys must still be stripped
|
|
87
|
+
);
|
|
88
|
+
expect(out).toEqual([{ component: "a", props: { title: "keep" } }]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("strips injected keys even when a projection rest-spreads them through", () => {
|
|
92
|
+
const out = serializeRenderJson([{ component: "a", props: { keep: 1, __pageUrl: "u", device: "d" } }], {
|
|
93
|
+
getSectionModule: () => ({ renderJson: (p: Record<string, unknown>) => p }), // identity passes __ through
|
|
94
|
+
});
|
|
95
|
+
expect(out).toEqual([{ component: "a", props: { keep: 1 } }]);
|
|
96
|
+
});
|
|
97
|
+
|
|
71
98
|
it("interleaves deferred sections as { component, lazyUrl } by index", () => {
|
|
72
99
|
const out = serializeRenderJson(
|
|
73
100
|
[
|
package/src/cms/renderJson.ts
CHANGED
|
@@ -85,6 +85,28 @@ export interface SerializeOptions {
|
|
|
85
85
|
* `renderJson === false` (for a deferred section, dropping avoids emitting a
|
|
86
86
|
* lazyUrl the app would fetch for nothing).
|
|
87
87
|
*/
|
|
88
|
+
/**
|
|
89
|
+
* Keys the section loader / mixins inject into props at request time — page
|
|
90
|
+
* context (`__pageUrl`/`__pagePath`, `runSectionLoaders`) and device
|
|
91
|
+
* (`device`/`isMobile`/`currentSearchParam`, the withDevice/withMobile/
|
|
92
|
+
* withSearchParam mixins). They are request-derived framework internals, NOT
|
|
93
|
+
* content, so they are stripped from the JSON: they would bust the ETag per
|
|
94
|
+
* request/device and leak internals the mobile app shouldn't cache. Any
|
|
95
|
+
* `__`-prefixed key is treated as internal by convention (mirrors `__section`).
|
|
96
|
+
*/
|
|
97
|
+
const FRAMEWORK_INJECTED_KEYS = new Set(["device", "isMobile", "currentSearchParam"]);
|
|
98
|
+
|
|
99
|
+
function stripFrameworkKeys(props: Record<string, unknown>): Record<string, unknown> {
|
|
100
|
+
let out: Record<string, unknown> | null = null;
|
|
101
|
+
for (const k of Object.keys(props)) {
|
|
102
|
+
if (k.startsWith("__") || FRAMEWORK_INJECTED_KEYS.has(k)) {
|
|
103
|
+
out ??= { ...props };
|
|
104
|
+
delete out[k];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out ?? props;
|
|
108
|
+
}
|
|
109
|
+
|
|
88
110
|
export function serializeRenderJson(
|
|
89
111
|
sections: SerializableSection[],
|
|
90
112
|
opts: SerializeOptions = {},
|
|
@@ -104,7 +126,8 @@ export function serializeRenderJson(
|
|
|
104
126
|
.filter((s) => !isDropped(s.component))
|
|
105
127
|
.map((section) => {
|
|
106
128
|
const rj = renderJsonOf(section.component);
|
|
107
|
-
const
|
|
129
|
+
const projected = typeof rj === "function" ? rj(section.props ?? {}) : section.props ?? {};
|
|
130
|
+
const props = stripFrameworkKeys(projected);
|
|
108
131
|
return { index: section.index, out: { component: section.component, props } as SerializedSection };
|
|
109
132
|
});
|
|
110
133
|
|