sbuilder-mcp 0.47.1 → 0.48.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 +10 -0
- package/CHANGELOG.vi.md +10 -0
- package/dist/domains/site/readiness.js +36 -0
- package/dist/tools/page.js +36 -0
- package/package.json +1 -1
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.48.0] - 2026-09-14
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `sb_review` now reports an `errorPage` gap on any site with two or more pages that has no published page of type `error`, since the platform's own fallback for a mistyped URL is a bare, unstyled "404 page not found" carrying none of the site's header, footer, or way back to the shop; the gap names whether an unpublished draft already exists.
|
|
13
|
+
|
|
14
|
+
## [0.47.2] - 2026-09-14
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- `sb_page_create` no longer stores an HTML entity verbatim in a page name; a name like `Chính sách giao hàng & đổi trả`, lifted undecoded from a page's own source, is now decoded once before it is sent, on both the create and the home-page-adopt rename path.
|
|
18
|
+
|
|
9
19
|
## [0.47.1] - 2026-09-14
|
|
10
20
|
|
|
11
21
|
### Fixed
|
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.48.0] - 2026-09-14
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `sb_review` giờ báo lỗi thiếu `errorPage` trên mọi site có từ hai trang trở lên mà chưa có trang loại `error` được publish, vì cách nền tảng tự xử lý khi gặp URL gõ sai chỉ là một trang "404 page not found" trần trụi, không kiểu dáng, không mang theo header, footer hay đường quay lại cửa hàng của site; lỗi này nêu rõ liệu đã có sẵn một bản nháp chưa publish hay chưa.
|
|
13
|
+
|
|
14
|
+
## [0.47.2] - 2026-09-14
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- `sb_page_create` không còn lưu nguyên một HTML entity trong tên trang; một tên như `Chính sách giao hàng & đổi trả`, lấy chưa giải mã từ chính nguồn của một trang, giờ được giải mã một lần trước khi gửi đi, trên cả đường tạo trang lẫn đường đổi tên khi nhận lại trang chủ.
|
|
18
|
+
|
|
9
19
|
## [0.47.1] - 2026-09-14
|
|
10
20
|
|
|
11
21
|
### Fixed
|
|
@@ -96,6 +96,42 @@ export function readinessGaps(input) {
|
|
|
96
96
|
'globalRef instead of a copy, and one edit reaches every page.',
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
|
+
// A MISTYPED URL ANSWERS IN GO, NOT IN THE SHOP'S VOICE.
|
|
100
|
+
//
|
|
101
|
+
// storefront/errorpage.go: with no PUBLISHED page of type `error`, notFound
|
|
102
|
+
// falls through to http.NotFound — the bare "404 page not found" in plain
|
|
103
|
+
// text. No header, no footer, no way back to the shop, and nothing that looks
|
|
104
|
+
// like the site the shopper was just in.
|
|
105
|
+
//
|
|
106
|
+
// Unlike the completion page, which backstops itself with a built-in receipt
|
|
107
|
+
// (measured 200 on a live store that had none), this fallback carries none of
|
|
108
|
+
// the site. And unlike a dead link, nothing reports it: the only person who
|
|
109
|
+
// sees it is a visitor who already took a wrong turn and now has no way back.
|
|
110
|
+
//
|
|
111
|
+
// Asked of EVERY site, not only a store, and so placed here with siteChrome
|
|
112
|
+
// rather than below the gate — a mistyped URL is not a commerce question.
|
|
113
|
+
//
|
|
114
|
+
// TWO PAGES IS THE THRESHOLD, the same one siteChrome uses and for a related
|
|
115
|
+
// reason: a one-page site has no second address to mistype, no menu to follow
|
|
116
|
+
// a stale link out of, and nothing to put in a header that would make a 404
|
|
117
|
+
// look like the site. Below it this would be a nag at a brochure — which the
|
|
118
|
+
// silence contract in readiness.test.ts names outright.
|
|
119
|
+
if (pages && pages.length >= 2 && !published(pages, 'error')) {
|
|
120
|
+
const draft = drafted(pages, 'error');
|
|
121
|
+
gaps.push({
|
|
122
|
+
id: 'errorPage',
|
|
123
|
+
draft,
|
|
124
|
+
problem: 'A URL that does not exist answers with the platform\'s own bare "404 page not found" ' +
|
|
125
|
+
'in plain text — no header, no footer, no way back to the shop. A shopper who follows ' +
|
|
126
|
+
'a stale link or mistypes an address lands on a blank page that does not look like ' +
|
|
127
|
+
'this site at all.',
|
|
128
|
+
fix: draft
|
|
129
|
+
? 'Publish the error page that already exists.'
|
|
130
|
+
: 'Create a page of type "error" and publish it. It has no address of its own — the ' +
|
|
131
|
+
'storefront serves it as the BODY of a 404 — so give it the site\'s header and ' +
|
|
132
|
+
'footer and a link back to the home page.',
|
|
133
|
+
});
|
|
134
|
+
}
|
|
99
135
|
if (!isStore(input))
|
|
100
136
|
return gaps;
|
|
101
137
|
if (pages && !published(pages, 'checkout')) {
|
package/dist/tools/page.js
CHANGED
|
@@ -311,6 +311,40 @@ async function siteChrome(ctx, siteId) {
|
|
|
311
311
|
return {};
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* Plain text, for a field the platform renders AS text.
|
|
316
|
+
*
|
|
317
|
+
* A page name is shown in the pages panel and in the browser tab and is never
|
|
318
|
+
* parsed as markup, so an HTML entity in one is always a mistake: text lifted
|
|
319
|
+
* from a page's source and handed on without being decoded. Measured on a real
|
|
320
|
+
* store, read back through sb_page_list: a page stored as "Chính sách giao hàng
|
|
321
|
+
* & đổi trả" — which is what the merchant then reads in their own editor,
|
|
322
|
+
* and what a browser tab then shows.
|
|
323
|
+
*
|
|
324
|
+
* ONE PASS, and only over what escaping actually produces. "&" decodes to
|
|
325
|
+
* "&" and stops there, because a second pass would be inventing an intent
|
|
326
|
+
* nobody expressed; an unknown entity is left exactly as it arrived. This
|
|
327
|
+
* un-escapes text that was escaped once. It does not interpret markup.
|
|
328
|
+
*/
|
|
329
|
+
const ENTITIES = {
|
|
330
|
+
amp: '&',
|
|
331
|
+
lt: '<',
|
|
332
|
+
gt: '>',
|
|
333
|
+
quot: '"',
|
|
334
|
+
apos: "'",
|
|
335
|
+
nbsp: ' ',
|
|
336
|
+
};
|
|
337
|
+
export function plainText(s) {
|
|
338
|
+
return s.replace(/&(#x[0-9a-fA-F]+|#\d+|[a-zA-Z]+);/g, (whole, body) => {
|
|
339
|
+
if (body.startsWith('#')) {
|
|
340
|
+
const code = body.startsWith('#x') ? parseInt(body.slice(2), 16) : parseInt(body.slice(1), 10);
|
|
341
|
+
// A code point that is not one is not a reference — leave the text alone
|
|
342
|
+
// rather than writing a replacement character into somebody's page name.
|
|
343
|
+
return Number.isFinite(code) && code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : whole;
|
|
344
|
+
}
|
|
345
|
+
return ENTITIES[body.toLowerCase()] ?? whole;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
314
348
|
/**
|
|
315
349
|
* The site's own home page, or null when it genuinely has none.
|
|
316
350
|
*
|
|
@@ -1004,6 +1038,8 @@ export function registerPageTools(server, ctx) {
|
|
|
1004
1038
|
}, async ({ site_id: given, name, type, slug, is_homepage, settings, seed, chrome, locale, headline, dry_run }) => {
|
|
1005
1039
|
const site_id = siteFor(ctx, given);
|
|
1006
1040
|
const path = `/api/sites/${encodeURIComponent(site_id)}/pages`;
|
|
1041
|
+
// The platform stores this verbatim and renders it as text — see plainText.
|
|
1042
|
+
name = plainText(name);
|
|
1007
1043
|
// TYPE IS THE ROUTE for several kinds of page: /checkout and
|
|
1008
1044
|
// /products/{slug} resolve to the site's PUBLISHED page of that type and
|
|
1009
1045
|
// fall through to a 404 when there is none. Without this argument the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sbuilder-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.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",
|