webcake-storefront-mcp 1.5.0 → 1.5.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/dist/api.js CHANGED
@@ -139,8 +139,16 @@ export class WebcakeCmsApi {
139
139
  listPages() {
140
140
  return this.request("GET", `/api/v1/site/${this.siteId}/pages`);
141
141
  }
142
+ /** Create a page. The backend creates the page AND its source in one call, so `source`
143
+ * is REQUIRED and must be a JSON string (stringified here if an object is passed).
144
+ * `slug`/`is_homepage` are NOT applied at create — set them afterwards via updatePage. */
142
145
  createPage(params) {
143
- return this.request("POST", `/api/v1/site/${this.siteId}/page`, { body: params });
146
+ const body = { ...params };
147
+ if (body.source != null && typeof body.source !== "string")
148
+ body.source = JSON.stringify(body.source);
149
+ if (body.source == null)
150
+ body.source = JSON.stringify({ sections: [] });
151
+ return this.request("POST", `/api/v1/site/${this.siteId}/page`, { body });
144
152
  }
145
153
  updatePage(pageId, params) {
146
154
  return this.request("POST", `/api/v1/site/${this.siteId}/${pageId}/update_page`, { body: params });
@@ -169,8 +177,21 @@ export class WebcakeCmsApi {
169
177
  saveSite(params = {}) {
170
178
  return this.request("POST", `/api/v1/site/${this.siteId}/save`, { body: params, timeout: 60000 });
171
179
  }
172
- publishSite(params = {}) {
173
- return this.request("POST", `/api/v1/site/${this.siteId}/publish`, { body: params, timeout: 60000 });
180
+ /** Publish the site live. /publish runs the full "save" pipeline, which OVERWRITES
181
+ * site.settings with the body's `settings` so we send the CURRENT settings (else
182
+ * they'd be nulled, disabling use_store/use_blog/etc.). Other collections default to []. */
183
+ async publishSite(params = {}) {
184
+ let settings = params.settings;
185
+ if (settings === undefined) {
186
+ settings = await this.getSiteSettings().catch(() => ({}));
187
+ }
188
+ // The save pipeline stores site.settings as a JSON STRING — an object body is
189
+ // rejected (422). Stringify unless the caller already passed a string.
190
+ const settingsStr = typeof settings === "string" ? settings : JSON.stringify(settings || {});
191
+ return this.request("POST", `/api/v1/site/${this.siteId}/publish`, {
192
+ body: { global_sources: [], global_sections: [], page_contents: [], ...params, settings: settingsStr },
193
+ timeout: 60000,
194
+ });
174
195
  }
175
196
  uploadImageBase64({ base64, content_type } = {}) {
176
197
  return this.request("POST", `/api/v1/site/${this.siteId}/media/content/b64`, {
@@ -1,4 +1,11 @@
1
1
  [
2
+ {
3
+ "v": "1.5.1",
4
+ "d": "23/06/2026",
5
+ "type": "Fixed",
6
+ "en": "build_page now passes the finalized page source to create_page in the initial create call (required by the backend), then sets slug and is_homepage…",
7
+ "vi": "build_page nay truyền source trang đã hoàn thiện vào lời gọi create_page ban đầu (bắt buộc bởi backend), sau đó đặt slug và is_homepage qua một lời…"
8
+ },
2
9
  {
3
10
  "v": "1.5.0",
4
11
  "d": "23/06/2026",
@@ -33,12 +40,5 @@
33
40
  "type": "Added",
34
41
  "en": "The remote landing page served by the serve command now includes a \"What's new\" section that renders a version timeline loaded from a build-time…",
35
42
  "vi": "Trang landing của lệnh serve nay có thêm mục \"Có gì mới\" hiển thị timeline lịch sử phiên bản được tải từ file changelog.json sinh ra lúc build (từ…"
36
- },
37
- {
38
- "v": "1.1.3",
39
- "d": "23/06/2026",
40
- "type": "Changed",
41
- "en": "The install command's interactive wizard now runs a three-step flow: environment selection (prod / staging / local), authentication, then IDE…",
42
- "vi": "Trình hướng dẫn tương tác của lệnh install nay chạy theo 3 bước: chọn môi trường (prod / staging / local), xác thực, rồi cấu hình IDE."
43
43
  }
44
44
  ]
@@ -96,14 +96,20 @@ The source must be { sections: [...] } — build sections with new_section. Vali
96
96
  return { error: `Could not enable site.settings.${requiredFlag} (needed for a '${kind}' page). ${e?.message ?? e}` };
97
97
  }
98
98
  }
99
- const created = await api.createPage({ name, slug, ...(typeNum != null ? { type: typeNum } : {}), is_homepage });
99
+ // Expand runtime -> bp1..bp4 so the saved source actually renders on the storefront.
100
+ finalizeForRender(parsed);
101
+ // createPage saves the page AND its source in one call (source is required there).
102
+ const created = await api.createPage({ name, source: parsed, ...(typeNum != null ? { type: typeNum } : {}) });
100
103
  const pageId = newPageId(created);
101
104
  if (!pageId) {
102
- return { error: "Page created but no id was returned; cannot save source.", created };
105
+ return { error: "Page created but no id was returned.", created };
106
+ }
107
+ // slug / homepage are not applied at create — set them via update_page.
108
+ if (slug || is_homepage) {
109
+ await api
110
+ .updatePage(pageId, { ...(slug ? { slug } : {}), ...(is_homepage ? { is_homepage: true } : {}) })
111
+ .catch(() => { });
103
112
  }
104
- // Expand runtime -> bp1..bp4 so the saved source actually renders on the storefront.
105
- finalizeForRender(parsed);
106
- const saved = await api.updatePageSource(pageId, { source: parsed });
107
113
  return {
108
114
  success: true,
109
115
  page_id: pageId,
@@ -111,7 +117,6 @@ The source must be { sections: [...] } — build sections with new_section. Vali
111
117
  slug,
112
118
  page_type: kind ?? null,
113
119
  ...(feature ? { data_source: { flag: feature.flag, newly_enabled: feature.changed } } : {}),
114
- page_source_id: saved && saved.data && saved.data.id,
115
120
  stats: validation.stats,
116
121
  };
117
122
  }));
@@ -69,19 +69,22 @@ Images must be HOSTED URLs — get them from search_images or upload_images firs
69
69
  const productParams = {
70
70
  name,
71
71
  variations: vars,
72
+ // These MUST be arrays — the backend does Enum.reduce over them and 500s on nil.
73
+ categories: category_ids || [],
74
+ ribbons: [],
72
75
  ...(description ? { description } : {}),
73
76
  ...(attributes ? { product_attributes: attributes } : {}),
74
- ...(category_ids ? { categories: category_ids } : {}),
75
77
  ...(images && images.length ? { image: images[0] } : {}),
76
78
  };
77
79
  const res = await api.createProduct(productParams);
78
- const data = res?.data;
79
- const productId = data?.attributes?.id || data?.id || data?.product?.id || null;
80
+ // Success response is { product: {...} } at the top level (not under data).
81
+ const prod = res?.product || res?.data?.product || res?.data?.attributes || res?.data || {};
82
+ const productId = prod?.id || null;
80
83
  return {
81
84
  success: true,
82
85
  product_id: productId,
83
86
  name,
84
- slug: data?.attributes?.slug || data?.slug || null,
87
+ slug: prod?.slug || null,
85
88
  variations: vars.length,
86
89
  categories: category_ids || [],
87
90
  raw: productId ? undefined : res, // surface raw response only if we couldn't find the id
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-storefront-mcp",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "MCP server for the WebCake/StoreCake storefront builder — page CRUD, page authoring, products, orders, and more",
5
5
  "mcpName": "io.github.vuluu2k/webcake-storefront-mcp",
6
6
  "license": "MIT",