webcake-landing-mcp 1.0.41 → 1.0.42

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.
@@ -1,4 +1,11 @@
1
1
  [
2
+ {
3
+ "v": "1.0.42",
4
+ "d": "09/06/2026",
5
+ "type": "Fixed",
6
+ "en": "validate_page now raises an error when a countdown element's specials.language is set to a value outside the eight supported word-values (vietnam,…",
7
+ "vi": "validate_page nay phát lỗi khi element countdown có specials.language là giá trị nằm ngoài tám word-value được hỗ trợ (vietnam, english, filipino,…"
8
+ },
2
9
  {
3
10
  "v": "1.0.41",
4
11
  "d": "09/06/2026",
@@ -33,12 +40,5 @@
33
40
  "type": "Changed",
34
41
  "en": "get_generation_guide now includes a HEADER section build hint directing the agent to place every header child (logo, brand text, CTA button) on a…",
35
42
  "vi": "get_generation_guide nay bổ sung gợi ý dựng section HEADER yêu cầu agent đặt mọi phần tử con trong header (logo, tên thương hiệu, nút CTA) trên cùng…"
36
- },
37
- {
38
- "v": "1.0.36",
39
- "d": "08/06/2026",
40
- "type": "Changed",
41
- "en": "The GET / web guide page now lists \"Claude · Codex · Cursor, etc.\" instead of only \"Claude · Cursor\" in the AI assistant flow diagram, reflecting…",
42
- "vi": "Trang hướng dẫn GET / nay hiển thị \"Claude · Codex · Cursor, v.v.\" thay vì chỉ \"Claude · Cursor\" trong sơ đồ luồng AI assistant, phản ánh danh sách…"
43
43
  }
44
44
  ]
@@ -16,8 +16,8 @@ export const MARKETING = [
16
16
  showDay: "boolean — show the days segment.",
17
17
  showSecond: "boolean — show the seconds segment.",
18
18
  showText: "boolean — show unit labels (days/hours/minutes/seconds).",
19
- language: "locale string for unit labels.",
20
- customTranslation: "object — custom unit label overrides.",
19
+ language: "unit-label locale MUST be one of: vietnam | english | filipino | khmer | lao | indonesian | thai | malay | custom. NOT a code like 'vi'/'en' (that crashes the renderer). For any other language use 'custom' + customTranslation.",
20
+ customTranslation: "object {day,hour,minute,second} of label strings used (and required) when language='custom'. e.g. {day:'Ngày',hour:'Giờ',minute:'Phút',second:'Giây'}.",
21
21
  },
22
22
  seed: (el) => {
23
23
  seedPosition(el);
@@ -25,7 +25,7 @@ export const MARKETING = [
25
25
  setStyle(el, "color", "rgba(255, 255, 255, 1)");
26
26
  setStyle(el, "background", "rgba(0, 0, 0, 1)");
27
27
  setStyle(el, "fontSize", 20);
28
- el.specials = { type: "minute", duration: "60", showDay: true, showSecond: true, showText: true, repeat: false, customize: false, customMessage: "", dailyStart: "", dailyEnd: "" };
28
+ el.specials = { type: "minute", duration: "60", language: "english", showDay: true, showSecond: true, showText: true, repeat: false, customize: false, customMessage: "", dailyStart: "", dailyEnd: "" };
29
29
  },
30
30
  },
31
31
  {
@@ -230,7 +230,7 @@
230
230
  },
231
231
  "specials": {
232
232
  "type": "object",
233
- "description": "Type-specific content/config. The user-visible CONTENT lives here, NOT in styles. Open object; key fields by type: section{globalSection,globalSectionName,custom_class,imageCompression}; text-block{text(HTML),tag}; list-paragraph{text(<li>..)}; image-block{src,resize}; button{text,required,format,connectedSurvey}; video{typeVideo,video_cdn,img,autoReplay}; gallery{media[]}; form{field_type,form_type,sheetOrder,validate,submit_success,fb_event_type,fb_conversion_value,fb_tracking_currency,tiktok_conversion_value,tiktok_tracking_currency}; input/textarea/select/checkbox/radio/address/...{field_name,field_placeholder,field_type,required,options}; countdown{type,duration,startTime,endTime,showDay,showSecond,showText,language,customTranslation}; survey{options[{id,image,title,value,field_name}],type,multiOption,selectedBackground,selectedBorder}; list-product{format_title,numerical_order,remain_quantity_text}.",
233
+ "description": "Type-specific content/config. The user-visible CONTENT lives here, NOT in styles. Open object; key fields by type: section{globalSection,globalSectionName,custom_class,imageCompression}; text-block{text(HTML),tag}; list-paragraph{text(<li>..)}; image-block{src,resize}; button{text,required,format,connectedSurvey}; video{typeVideo,video_cdn,img,autoReplay}; gallery{media[]}; form{field_type,form_type,sheetOrder,validate,submit_success,fb_event_type,fb_conversion_value,fb_tracking_currency,tiktok_conversion_value,tiktok_tracking_currency}; input/textarea/select/checkbox/radio/address/...{field_name,field_placeholder,field_type,required,options}; countdown{type,duration,startTime,endTime,showDay,showSecond,showText,language(vietnam|english|filipino|khmer|lao|indonesian|thai|malay|custom — NOT a locale code; 'custom' uses customTranslation),customTranslation{day,hour,minute,second}}; survey{options[{id,image,title,value,field_name}],type,multiOption,selectedBackground,selectedBorder}; list-product{format_title,numerical_order,remain_quantity_text}.",
234
234
  "additionalProperties": true,
235
235
  "properties": {
236
236
  "text": { "type": "string", "description": "text-block/button label/list-paragraph (may contain HTML)." },
@@ -36,6 +36,11 @@ const OPTION_NAME_FIELDS = new Set(["select", "radio", "checkbox-group"]);
36
36
  // field_placeholder throws "Cannot read properties of undefined (reading 'replace')"
37
37
  // and the whole page fails to render.
38
38
  const PLACEHOLDER_REQUIRED_FIELDS = new Set(["select", "country-select", "group-select-item"]);
39
+ // countdown's renderer indexes a fixed `lang` table by specials.language and then
40
+ // destructures the result: `const [d,h,m,s] = lang[language]`. Any value outside
41
+ // this set (e.g. a locale code like "vi"/"en") yields undefined → "is not iterable"
42
+ // and the whole page fails to render. 'custom' instead reads specials.customTranslation.
43
+ const COUNTDOWN_LANGUAGES = new Set(["vietnam", "english", "filipino", "khmer", "lao", "indonesian", "thai", "malay", "custom"]);
39
44
  // Fixed canvas reference (matches vocab CANVAS) used for the layout/bounds check.
40
45
  const CANVAS_DESKTOP = 960;
41
46
  const CANVAS_MOBILE = 420;
@@ -149,6 +154,15 @@ export function validatePage(input) {
149
154
  });
150
155
  }
151
156
  }
157
+ // countdown.language must be a key the renderer's lang table knows (or 'custom');
158
+ // anything else (e.g. a locale code "vi"/"en") crashes the renderer with
159
+ // "is not iterable" when it destructures lang[language].
160
+ if (type === "countdown") {
161
+ const lang = node.specials?.language;
162
+ if (typeof lang === "string" && !COUNTDOWN_LANGUAGES.has(lang)) {
163
+ errors.push(`${path} (countdown): specials.language="${lang}" is not supported and crashes the renderer. Use one of: ${[...COUNTDOWN_LANGUAGES].join(", ")} (use "custom" + specials.customTranslation for other languages).`);
164
+ }
165
+ }
152
166
  // collect events
153
167
  if (Array.isArray(node.events)) {
154
168
  for (const ev of node.events) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-landing-mcp",
3
- "version": "1.0.41",
3
+ "version": "1.0.42",
4
4
  "description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
5
5
  "mcpName": "io.github.vuluu2k/webcake-landing-mcp",
6
6
  "type": "module",