sbuilder-mcp 0.57.0 → 0.59.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/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ All notable changes to this project are documented in this file.
6
6
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
7
7
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.59.0] - 2026-09-15
10
+
11
+ ### Added
12
+ - `sb_review` now reports a `maintenancePage` readiness gap when a site has maintenance mode switched on but no published page of the `maintain` type, since every public address then answers a bare 503 sentence with no header, logo, or word about when the shop is back; the check reads the site's own maintenance flag and stays silent for a site that is not currently in maintenance.
13
+
14
+ ## [0.58.0] - 2026-09-15
15
+
16
+ ### Added
17
+ - `sb_review` now reports `blogCategoryPage` and `coursePage` readiness gaps when a site has blog categories or courses but no published page of the `blog` or `course` type, since `/blog-categories/{slug}` and `/courses/{slug}` fall back to those templates and every entity link 404s without them, completing the check against all five entity prefixes the storefront registers.
18
+
9
19
  ## [0.57.0] - 2026-09-15
10
20
 
11
21
  ### Added
package/CHANGELOG.vi.md CHANGED
@@ -6,6 +6,16 @@ Mọi thay đổi đáng chú ý của dự án được ghi lại trong file n
6
6
  Định dạng dựa trên [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
7
7
  và dự án tuân theo [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.59.0] - 2026-09-15
10
+
11
+ ### Added
12
+ - `sb_review` giờ báo lỗi sẵn sàng `maintenancePage` khi site đã bật chế độ bảo trì nhưng chưa có trang loại `maintain` nào được publish, vì khi đó mọi địa chỉ công khai sẽ chỉ trả về một câu 503 trơn, không header, không logo, không một dòng nào báo khi nào shop mở lại; việc kiểm tra đọc thẳng cờ bảo trì của site và im lặng nếu site hiện không ở chế độ bảo trì.
13
+
14
+ ## [0.58.0] - 2026-09-15
15
+
16
+ ### Added
17
+ - `sb_review` giờ báo lỗi sẵn sàng `blogCategoryPage` và `coursePage` khi site có danh mục blog hoặc khoá học nhưng chưa có trang loại `blog` hoặc `course` nào được publish, vì `/blog-categories/{slug}` và `/courses/{slug}` sẽ dùng các template đó, và mọi liên kết sẽ trả về 404 nếu thiếu — hoàn tất việc kiểm tra cho cả năm tiền tố thực thể mà storefront đăng ký.
18
+
9
19
  ## [0.57.0] - 2026-09-15
10
20
 
11
21
  ### Added
@@ -24,7 +24,7 @@ export async function gatherReadiness(ctx, siteId, pageNodes) {
24
24
  }
25
25
  };
26
26
  const site = encodeURIComponent(siteId);
27
- const [pageList, gateways, shipping, globals, productList, categoryList, pageLinks, formList, articleList] = await Promise.all([
27
+ const [pageList, gateways, shipping, globals, productList, categoryList, pageLinks, formList, articleList, blogCategoryList, courseList, siteRecord] = await Promise.all([
28
28
  get(`/api/sites/${site}/pages`),
29
29
  get(`/api/sites/${site}/payment-gateways`),
30
30
  get(`/api/sites/${site}/shipping-methods`),
@@ -52,6 +52,18 @@ export async function gatherReadiness(ctx, siteId, pageNodes) {
52
52
  // resolves to the site's `post` template, so a site that has written
53
53
  // articles and has no template 404s every one of them.
54
54
  get(`/api/sites/${site}/articles?limit=1`),
55
+ // THE LAST TWO ENTITY PREFIXES the storefront registers
56
+ // (storefront/entityroute.go): /blog-categories/{slug} and /courses/{slug}.
57
+ // Each resolves to the site's published page of its own TYPE, so each has
58
+ // the hole /products/{slug} has, and counting is how we know the site uses
59
+ // the prefix at all.
60
+ get(`/api/sites/${site}/blog-categories?limit=1`),
61
+ get(`/api/sites/${site}/courses?limit=1`),
62
+ // THE SWITCH ITSELF. `maintain` is the one page type whose absence matters
63
+ // only while a flag is on — see maintenanceGap. Read here rather than
64
+ // guessed, because the alternative is telling every site on earth to build
65
+ // a page for an outage it is not having.
66
+ get(`/api/sites/${site}`),
55
67
  ]);
56
68
  // A gateway counts only when it is BOTH enabled and configured — the editor's
57
69
  // `live` getter also filters by the store's currency, which is a narrowing:
@@ -62,6 +74,10 @@ export async function gatherReadiness(ctx, siteId, pageNodes) {
62
74
  : null;
63
75
  const methods = shipping?.shippingMethods ?? shipping?.methods;
64
76
  const shippingMethods = Array.isArray(methods) ? methods.length : null;
77
+ // Either key, like the product categories below: this reader has met both
78
+ // spellings from the platform and guessing one would read a real list as none.
79
+ const rawBlogCats = blogCategoryList?.blogCategories ?? blogCategoryList?.categories;
80
+ const blogCats = Array.isArray(rawBlogCats) ? rawBlogCats : null;
65
81
  const cats = categoryList?.categories ?? categoryList?.productCategories;
66
82
  const categories = Array.isArray(cats) ? (categoryList?.total ?? cats.length) : null;
67
83
  const links = pageLinks?.links ?? pageLinks?.pageLinks;
@@ -101,5 +117,12 @@ export async function gatherReadiness(ctx, siteId, pageNodes) {
101
117
  articles: Array.isArray(articleList?.articles)
102
118
  ? (articleList?.total ?? articleList.articles.length)
103
119
  : null,
120
+ blogCategories: blogCats ? (blogCategoryList?.total ?? blogCats.length) : null,
121
+ courses: Array.isArray(courseList?.courses)
122
+ ? (courseList?.total ?? courseList.courses.length)
123
+ : null,
124
+ maintenanceMode: typeof siteRecord?.site?.maintenanceMode === 'boolean'
125
+ ? siteRecord.site.maintenanceMode
126
+ : null,
104
127
  };
105
128
  }
@@ -96,6 +96,36 @@ export function readinessGaps(input) {
96
96
  'globalRef instead of a copy, and one edit reaches every page.',
97
97
  });
98
98
  }
99
+ // THE SITE IS DARK RIGHT NOW AND SAYING NOTHING IN ITS OWN VOICE.
100
+ //
101
+ // Reported FIRST, because it is the only finding here that is not about what
102
+ // a visitor might one day meet: with the switch on, every public address is
103
+ // answering 503 this second. `maintenance.go` serves the published `maintain`
104
+ // page as that body when there is one, and a PLAIN SENTENCE when there is
105
+ // not — and it FAILS CLOSED on purpose, so an unresolvable page does not
106
+ // reopen the shop. The owner gets the outage they asked for either way; what
107
+ // they lose is every word of it.
108
+ //
109
+ // ONLY WHILE THE SWITCH IS ON. Telling a site to build a page for an outage
110
+ // it is not having is advice about a page nobody will see, and it would
111
+ // arrive on every review of every site — the nag this file keeps warning
112
+ // about, at the widest possible scale. Silent when the site could not be
113
+ // read, like everything else.
114
+ if (pages && input.maintenanceMode === true && !published(pages, 'maintain')) {
115
+ const draft = drafted(pages, 'maintain');
116
+ gaps.push({
117
+ id: 'maintenancePage',
118
+ draft,
119
+ problem: 'This storefront is switched OFF right now and has no published page of the "maintain" ' +
120
+ 'type, so every address is answering a bare 503 sentence — no header, no logo, no word ' +
121
+ 'about when it is back, and nothing that looks like this shop.',
122
+ fix: draft
123
+ ? 'Publish the maintenance page that already exists.'
124
+ : 'Create a page of type "maintain" and publish it. It has no address of its own — the ' +
125
+ 'storefront serves it as the BODY of the 503 — so give it the shop\'s name and a line ' +
126
+ 'saying when you are back.',
127
+ });
128
+ }
99
129
  // A MISTYPED URL ANSWERS IN GO, NOT IN THE SHOP'S VOICE.
100
130
  //
101
131
  // storefront/errorpage.go: with no PUBLISHED page of type `error`, notFound
@@ -203,6 +233,35 @@ export function readinessGaps(input) {
203
233
  'headline, date and body an article cannot be read without.',
204
234
  });
205
235
  }
236
+ // THE LAST TWO ENTITY PREFIXES, the same hole in the same shape.
237
+ //
238
+ // storefront/entityroute.go registers five: /products, /collections, /blog,
239
+ // /blog-categories and /courses. Each resolves to the site's published page of
240
+ // its own TYPE, so each 404s everything under it when that page is missing.
241
+ // Four of the five are now checked above; these are the other two.
242
+ //
243
+ // COUNTED, NOT ASSUMED. A site with no blog categories has nothing under
244
+ // /blog-categories to break, and a site with no courses has not installed the
245
+ // app — the count IS the gate, which is why neither needs to ask about the
246
+ // app separately. Both sit above the store gate: a course is sold, but a blog
247
+ // is not commerce, and a site can be neither and still have one.
248
+ for (const [count, type, id, prefix, what] of [
249
+ [input.blogCategories, 'blog', 'blogCategoryPage', '/blog-categories/{slug}', 'blog category'],
250
+ [input.courses, 'course', 'coursePage', '/courses/{slug}', 'course'],
251
+ ]) {
252
+ if (!pages || (count ?? 0) === 0 || published(pages, type))
253
+ continue;
254
+ const draft = drafted(pages, type);
255
+ gaps.push({
256
+ id,
257
+ draft,
258
+ problem: `This site has ${count} ${what}${count === 1 ? '' : count && count > 1 ? 's' : ''} and no ` +
259
+ `published page of the "${type}" type. ${prefix} needs one, so every ${what} link 404s.`,
260
+ fix: draft
261
+ ? `Publish the ${what} template page that already exists.`
262
+ : `Create a page of type "${type}" and publish it.`,
263
+ });
264
+ }
206
265
  if (!isStore(input))
207
266
  return gaps;
208
267
  if (pages && !published(pages, 'checkout')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sbuilder-mcp",
3
- "version": "0.57.0",
3
+ "version": "0.59.0",
4
4
  "description": "MCP server that designs and operates a Store Builder site — pages, data, theme and publish — through the platform's own API and live-edit protocol.",
5
5
  "mcpName": "io.github.vuluu2k/sbuilder-mcp",
6
6
  "type": "module",