sbuilder-mcp 0.47.1 → 0.47.2
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 +5 -0
- package/CHANGELOG.vi.md +5 -0
- package/dist/tools/page.js +36 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@ 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.47.2] - 2026-09-14
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- `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.
|
|
13
|
+
|
|
9
14
|
## [0.47.1] - 2026-09-14
|
|
10
15
|
|
|
11
16
|
### Fixed
|
package/CHANGELOG.vi.md
CHANGED
|
@@ -6,6 +6,11 @@ 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.47.2] - 2026-09-14
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- `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ủ.
|
|
13
|
+
|
|
9
14
|
## [0.47.1] - 2026-09-14
|
|
10
15
|
|
|
11
16
|
### Fixed
|
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.47.
|
|
3
|
+
"version": "0.47.2",
|
|
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",
|