sbuilder-mcp 0.58.0 → 0.59.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/CHANGELOG.md +16 -0
- package/CHANGELOG.vi.md +16 -0
- package/README.md +1 -1
- package/README.vi.md +1 -1
- package/dist/catalog/api.generated.js +40 -4
- package/dist/catalog/deadkeys.generated.js +2 -2
- package/dist/catalog/elements.generated.js +57 -7
- package/dist/catalog/shapes.generated.js +19 -4
- package/dist/catalog/storepages.generated.js +4 -4
- package/dist/domains/site/readiness-fetch.js +9 -1
- package/dist/domains/site/readiness.js +30 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ 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.1] - 2026-09-15
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `sb_api_find` and `sb_api_call` now reach `POST /api/sites/{siteId}/ai/messages`, the editor's own AI assistant for a product, with its request shape (`question` plus a `history` of prior turns).
|
|
13
|
+
- `sb_traits_for` now lists `articleSourceType` and `relationSlotKey` as controls on article-list repeaters, and both it and `sb_set` recognize `page_category` as a legal `articleSourceType` value and `page_collections` as a legal `collectionListType` value, so a single blog or collection template can render the category or collection the page itself names.
|
|
14
|
+
- `list-dataset`'s generated empty-state table now seeds a `review` source ("No reviews yet"), so a review list repeater gets a styled empty state instead of none.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- `sb_page_create` and `sb_template_use` now seed new collection-list pages with `collectionListType: "page_collections"` instead of `all_collections`, so a collection template's sub-collection grid follows the page it is on rather than listing every collection on the site.
|
|
18
|
+
- The generated empty-state copy for collections, blog topics, and courses now reads "New … will show up here. Check back soon." instead of "… you create will show up here."
|
|
19
|
+
|
|
20
|
+
## [0.59.0] - 2026-09-15
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- `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.
|
|
24
|
+
|
|
9
25
|
## [0.58.0] - 2026-09-15
|
|
10
26
|
|
|
11
27
|
### Added
|
package/CHANGELOG.vi.md
CHANGED
|
@@ -6,6 +6,22 @@ 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.1] - 2026-09-15
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `sb_api_find` và `sb_api_call` giờ với tới được `POST /api/sites/{siteId}/ai/messages`, trợ lý AI của chính editor dành cho một sản phẩm, cùng hình dạng request của nó (`question` và một `history` gồm các lượt hỏi đáp trước đó).
|
|
13
|
+
- `sb_traits_for` giờ liệt kê `articleSourceType` và `relationSlotKey` là control trên các repeater danh sách bài viết, và cả nó lẫn `sb_set` đều nhận `page_category` là giá trị hợp lệ của `articleSourceType` và `page_collections` là giá trị hợp lệ của `collectionListType`, nhờ đó một template blog hoặc collection duy nhất có thể hiển thị đúng danh mục hoặc collection mà trang đó đại diện.
|
|
14
|
+
- Bảng trạng thái rỗng sinh sẵn của `list-dataset` giờ gieo thêm nguồn `review` ("No reviews yet"), nên một repeater danh sách đánh giá có trạng thái rỗng được thiết kế riêng thay vì không có gì.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- `sb_page_create` và `sb_template_use` giờ gieo các trang danh sách collection mới với `collectionListType: "page_collections"` thay vì `all_collections`, nên lưới sub-collection của một template collection sẽ theo đúng trang nó đang nằm trên đó thay vì liệt kê mọi collection của site.
|
|
18
|
+
- Nội dung trạng thái rỗng sinh sẵn cho collection, chủ đề blog và khoá học giờ đọc là "New … will show up here. Check back soon." thay vì "… you create will show up here."
|
|
19
|
+
|
|
20
|
+
## [0.59.0] - 2026-09-15
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- `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ì.
|
|
24
|
+
|
|
9
25
|
## [0.58.0] - 2026-09-15
|
|
10
26
|
|
|
11
27
|
### Added
|
package/README.md
CHANGED
|
@@ -112,7 +112,7 @@ in this client: one would put the very key the platform exists to hold back into
|
|
|
112
112
|
| `sb_store` | Run a store flow that must happen in a fixed order — the four writes that make a working checkout, or any of the platform's 17 form templates (login, register, forgot, contact, subscribe …) with its own field document |
|
|
113
113
|
| `sb_undo` | Put back what a PUT replaced. The SECOND answer for a page, not the only one: the platform has versions, history and restore (`sb_api_find` "page versions"), which outlive this process — reach for those first and use this for every other shaped PUT |
|
|
114
114
|
|
|
115
|
-
Twenty-eight tools, **
|
|
115
|
+
Twenty-eight tools, **525 API operations** (176 of the 235 writes carrying a body shape read
|
|
116
116
|
off the handler), 113 elements, 79 binding sources. `sb_api_find`
|
|
117
117
|
is an index rather than a tool per endpoint, so the tool list stays short while everything
|
|
118
118
|
the platform can do stays reachable — and operations added to the platform arrive with the
|
package/README.vi.md
CHANGED
|
@@ -109,7 +109,7 @@ nhét ngược lại vào mọi bản cài.
|
|
|
109
109
|
| `sb_store` | Chạy một luồng cửa hàng bắt buộc đúng thứ tự — bốn lệnh ghi tạo nên trang thanh toán, hoặc gieo bất kỳ template nào trong 17 form của nền tảng (login, register, forgot, contact, subscribe …) kèm field document của nó |
|
|
110
110
|
| `sb_undo` | Trả lại thứ mà một lệnh PUT đã ghi đè. Với TRANG thì đây là đường về thứ hai chứ không phải duy nhất: nền tảng có version, history và restore (`sb_api_find` "page versions"), và chúng sống lâu hơn tiến trình này — hãy dùng chúng trước, còn tool này cho mọi PUT có hình dạng khác |
|
|
111
111
|
|
|
112
|
-
Hai mươi tám tool, **
|
|
112
|
+
Hai mươi tám tool, **525 operation API** (176 trong 235 lệnh ghi có hình dạng body đọc thẳng
|
|
113
113
|
từ handler), 113 element, 79 nguồn binding. `sb_api_find` là
|
|
114
114
|
một chỉ mục chứ không phải mỗi endpoint một tool, nên danh sách tool vẫn ngắn trong khi mọi
|
|
115
115
|
thứ nền tảng làm được vẫn với tới — và operation mới thêm bên nền tảng sẽ tự có sau lần
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export const SWAGGER_SOURCE = {
|
|
2
|
-
"operations":
|
|
2
|
+
"operations": 525,
|
|
3
3
|
"definitions": 107,
|
|
4
|
-
"bodyCarrying":
|
|
5
|
-
"bodyUndescribed":
|
|
4
|
+
"bodyCarrying": 193,
|
|
5
|
+
"bodyUndescribed": 74,
|
|
6
6
|
"generatedFrom": "server/docs/swagger.json"
|
|
7
7
|
};
|
|
8
8
|
export const API_OPERATIONS = [
|
|
@@ -3321,6 +3321,41 @@ export const API_OPERATIONS = [
|
|
|
3321
3321
|
"bodyRef": null,
|
|
3322
3322
|
"credential": "siteScoped"
|
|
3323
3323
|
},
|
|
3324
|
+
{
|
|
3325
|
+
"id": "post:/api/sites/{siteId}/ai/messages",
|
|
3326
|
+
"method": "POST",
|
|
3327
|
+
"path": "/api/sites/{siteId}/ai/messages",
|
|
3328
|
+
"tags": [
|
|
3329
|
+
"sites"
|
|
3330
|
+
],
|
|
3331
|
+
"summary": "Ask the editor's AI assistant a question about this product",
|
|
3332
|
+
"params": [
|
|
3333
|
+
{
|
|
3334
|
+
"name": "siteId",
|
|
3335
|
+
"in": "path",
|
|
3336
|
+
"required": true,
|
|
3337
|
+
"type": "string",
|
|
3338
|
+
"description": "Site ID"
|
|
3339
|
+
},
|
|
3340
|
+
{
|
|
3341
|
+
"name": "Accept",
|
|
3342
|
+
"in": "header",
|
|
3343
|
+
"required": false,
|
|
3344
|
+
"type": "string",
|
|
3345
|
+
"description": "text/event-stream to receive the answer as it is written; anything else returns one JSON body"
|
|
3346
|
+
},
|
|
3347
|
+
{
|
|
3348
|
+
"name": "message",
|
|
3349
|
+
"in": "body",
|
|
3350
|
+
"required": true,
|
|
3351
|
+
"type": "object",
|
|
3352
|
+
"description": "question (required) and history (prior turns: role user|assistant, text)"
|
|
3353
|
+
}
|
|
3354
|
+
],
|
|
3355
|
+
"bodyDescribed": false,
|
|
3356
|
+
"bodyRef": null,
|
|
3357
|
+
"credential": "siteScoped"
|
|
3358
|
+
},
|
|
3324
3359
|
{
|
|
3325
3360
|
"id": "get:/api/sites/{siteId}/api-keys",
|
|
3326
3361
|
"method": "GET",
|
|
@@ -18023,7 +18058,8 @@ export const API_DEFINITIONS = {
|
|
|
18023
18058
|
"description": "ZoneFees prices this method PER ZONE, keyed by zone id — the map behind\nFeeForZone. A zone with no entry falls back to FeeCents, so a merchant\nwho prices one method for one zone still has a working checkout for\nevery other combination.\n\nA MAP ON THE ROW rather than a method×zone table, and that is a\nconsidered exception to the normalise-everything rule: these fees are\nnever queried, sorted or aggregated on their own — every read wants them\nalongside the method they belong to — so a join table would buy a query\nnobody makes and cost one on every checkout.",
|
|
18024
18059
|
"type": "object",
|
|
18025
18060
|
"additionalProperties": {
|
|
18026
|
-
"type": "integer"
|
|
18061
|
+
"type": "integer",
|
|
18062
|
+
"format": "int64"
|
|
18027
18063
|
}
|
|
18028
18064
|
}
|
|
18029
18065
|
}
|
|
@@ -32181,7 +32181,7 @@ export const ELEMENTS = {
|
|
|
32181
32181
|
"collectionType": "all_products",
|
|
32182
32182
|
"collectionId": "all_products",
|
|
32183
32183
|
"articleCategoryId": "all_articles",
|
|
32184
|
-
"collectionListType": "
|
|
32184
|
+
"collectionListType": "page_collections",
|
|
32185
32185
|
"listNavIcon": "ArrowLeftSLine",
|
|
32186
32186
|
"listNavPosition": "inside",
|
|
32187
32187
|
"listNavIconSize": 16,
|
|
@@ -33178,7 +33178,9 @@ export const ELEMENTS = {
|
|
|
33178
33178
|
"label": "Article",
|
|
33179
33179
|
"controls": [
|
|
33180
33180
|
"article_category",
|
|
33181
|
-
"
|
|
33181
|
+
"articleSourceType",
|
|
33182
|
+
"articleCategoryId",
|
|
33183
|
+
"relationSlotKey"
|
|
33182
33184
|
]
|
|
33183
33185
|
},
|
|
33184
33186
|
{
|
|
@@ -33433,7 +33435,9 @@ export const ELEMENTS = {
|
|
|
33433
33435
|
"paginationItemActiveBorderStyle",
|
|
33434
33436
|
"paginationItemActiveBorderRadius",
|
|
33435
33437
|
"article_category",
|
|
33438
|
+
"articleSourceType",
|
|
33436
33439
|
"articleCategoryId",
|
|
33440
|
+
"relationSlotKey",
|
|
33437
33441
|
"list_loading_mode",
|
|
33438
33442
|
"list_load_more_label",
|
|
33439
33443
|
"list_pager_style",
|
|
@@ -33513,8 +33517,9 @@ export const ELEMENTS = {
|
|
|
33513
33517
|
"The dataset-block template — and every dataset node inside it — must carry the SAME config.datasetSource as this repeater. Each node reads its OWN key, so a collection list whose card omits it leaves that card on the product default: it binds product.url, no product context reaches a collection row, and the card publishes with no link, so clicking it does nothing",
|
|
33514
33518
|
"config.datasetSource picks the ENTITY: \"product\" for a product list, \"category\" for a collection list. It is what derives the node's binding target (product::product_list / category::collection_list)",
|
|
33515
33519
|
"Product lists: config.collectionType \"page_collection\" renders THE COLLECTION THE PAGE IS (the one /collections/{slug} named) so a single collection template serves every collection, \"all_products\" renders the whole catalog and narrows to the page collection on a collection template, \"collection\" renders the one named by config.collectionId, \"related\" renders the PAGE PRODUCT's neighbours — the products sharing one of its collections, minus itself",
|
|
33520
|
+
"Article lists: config.articleSourceType \"page_category\" renders THE BLOG CATEGORY THE PAGE IS (the one /blog-categories/{slug} named) so a single blog template serves every category — off a blog template it shows every article; \"category\" filters by config.articleCategoryId (the \"all_articles\" sentinel means no filter, and on a blog template it narrows to the page category anyway); \"slot\" renders a curated shelf, the rows filed by hand under config.relationSlotKey",
|
|
33516
33521
|
"Use \"related\" for a cross-sell shelf on a product page (\"Sản phẩm liên quan\" / \"You may also like\"). It reads no collectionId — its axis is whatever collections the page product is filed under — and it renders nothing on a page that names no product, so pair it with an emptyStateId if the section must never be blank",
|
|
33517
|
-
"Collection lists: config.collectionListType \"all_collections\" renders every collection; \"custom_collections\" renders specials.collectionIds, in that order",
|
|
33522
|
+
"Collection lists: config.collectionListType \"page_collections\" renders THE SUB-COLLECTIONS OF THE COLLECTION THE PAGE IS (the one /collections/{slug} named), so a single collection template draws every collection's browse grid — off a collection template it shows every collection instead; \"all_collections\" renders every collection; \"custom_collections\" renders specials.collectionIds, in that order",
|
|
33518
33523
|
"config.quantity caps how many records render; config.itemsPerRow is the row size (grid columns / slide page size) and style.gap is the space between cards — both are per-breakpoint",
|
|
33519
33524
|
"config.layout \"grid\" for a multi-row grid, \"slide\" for row-by-row carousel behaviour",
|
|
33520
33525
|
"Navigation and pagination only matter when layout is \"slide\". The arrows exist while config.listNavIcon names an icon (clearing it turns them off); the dots exist while paginationItemWidth and paginationItemHeight are both above 0",
|
|
@@ -36419,7 +36424,7 @@ export const SATELLITE_RULES = {
|
|
|
36419
36424
|
"textAlign": "center"
|
|
36420
36425
|
},
|
|
36421
36426
|
"specials": {
|
|
36422
|
-
"text": "
|
|
36427
|
+
"text": "New collections will show up here. Check back soon."
|
|
36423
36428
|
}
|
|
36424
36429
|
}
|
|
36425
36430
|
]
|
|
@@ -36505,7 +36510,7 @@ export const SATELLITE_RULES = {
|
|
|
36505
36510
|
"textAlign": "center"
|
|
36506
36511
|
},
|
|
36507
36512
|
"specials": {
|
|
36508
|
-
"text": "
|
|
36513
|
+
"text": "New topics will show up here. Check back soon."
|
|
36509
36514
|
}
|
|
36510
36515
|
}
|
|
36511
36516
|
]
|
|
@@ -36548,7 +36553,50 @@ export const SATELLITE_RULES = {
|
|
|
36548
36553
|
"textAlign": "center"
|
|
36549
36554
|
},
|
|
36550
36555
|
"specials": {
|
|
36551
|
-
"text": "
|
|
36556
|
+
"text": "New courses will show up here. Check back soon."
|
|
36557
|
+
}
|
|
36558
|
+
}
|
|
36559
|
+
]
|
|
36560
|
+
},
|
|
36561
|
+
"review": {
|
|
36562
|
+
"type": "list-empty",
|
|
36563
|
+
"children": [
|
|
36564
|
+
{
|
|
36565
|
+
"type": "icon",
|
|
36566
|
+
"style": {
|
|
36567
|
+
"color": "#d4d4d4"
|
|
36568
|
+
},
|
|
36569
|
+
"config": {
|
|
36570
|
+
"iconSize": 32
|
|
36571
|
+
},
|
|
36572
|
+
"specials": {
|
|
36573
|
+
"name": "ChatQuoteLine"
|
|
36574
|
+
}
|
|
36575
|
+
},
|
|
36576
|
+
{
|
|
36577
|
+
"type": "heading",
|
|
36578
|
+
"style": {
|
|
36579
|
+
"width": "auto",
|
|
36580
|
+
"fontSize": "20px",
|
|
36581
|
+
"fontWeight": "600",
|
|
36582
|
+
"color": "#171717",
|
|
36583
|
+
"textAlign": "center"
|
|
36584
|
+
},
|
|
36585
|
+
"specials": {
|
|
36586
|
+
"htmlTag": "h3",
|
|
36587
|
+
"text": "No reviews yet"
|
|
36588
|
+
}
|
|
36589
|
+
},
|
|
36590
|
+
{
|
|
36591
|
+
"type": "text",
|
|
36592
|
+
"style": {
|
|
36593
|
+
"width": "auto",
|
|
36594
|
+
"fontSize": "14px",
|
|
36595
|
+
"color": "#737373",
|
|
36596
|
+
"textAlign": "center"
|
|
36597
|
+
},
|
|
36598
|
+
"specials": {
|
|
36599
|
+
"text": "Reviews will show up here once customers leave them."
|
|
36552
36600
|
}
|
|
36553
36601
|
}
|
|
36554
36602
|
]
|
|
@@ -36836,6 +36884,7 @@ export const CONFIG_VALUES = {
|
|
|
36836
36884
|
"articleSourceType": {
|
|
36837
36885
|
"values": [
|
|
36838
36886
|
"category",
|
|
36887
|
+
"page_category",
|
|
36839
36888
|
"slot"
|
|
36840
36889
|
],
|
|
36841
36890
|
"fallback": "category",
|
|
@@ -36845,7 +36894,8 @@ export const CONFIG_VALUES = {
|
|
|
36845
36894
|
"collectionListType": {
|
|
36846
36895
|
"values": [
|
|
36847
36896
|
"all_collections",
|
|
36848
|
-
"custom_collections"
|
|
36897
|
+
"custom_collections",
|
|
36898
|
+
"page_collections"
|
|
36849
36899
|
],
|
|
36850
36900
|
"fallback": "all_collections",
|
|
36851
36901
|
"aliases": {},
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const SHAPE_SOURCE = {
|
|
2
|
-
"writeOperations":
|
|
3
|
-
"shaped":
|
|
4
|
-
"fromHandlers":
|
|
2
|
+
"writeOperations": 235,
|
|
3
|
+
"shaped": 176,
|
|
4
|
+
"fromHandlers": 176,
|
|
5
5
|
"fromSwaggerOnly": 0,
|
|
6
6
|
"withReadOnly": 26,
|
|
7
|
-
"structsRead":
|
|
7
|
+
"structsRead": 1678
|
|
8
8
|
};
|
|
9
9
|
export const REQUEST_SHAPES = {
|
|
10
10
|
"post:/api/sites/{siteId}/api-keys": {
|
|
@@ -2998,6 +2998,21 @@ export const REQUEST_SHAPES = {
|
|
|
2998
2998
|
"updatedAt"
|
|
2999
2999
|
]
|
|
3000
3000
|
},
|
|
3001
|
+
"post:/api/sites/{siteId}/ai/messages": {
|
|
3002
|
+
"fields": [
|
|
3003
|
+
{
|
|
3004
|
+
"name": "question",
|
|
3005
|
+
"type": "string"
|
|
3006
|
+
},
|
|
3007
|
+
{
|
|
3008
|
+
"name": "history",
|
|
3009
|
+
"type": "llm.Turn[]",
|
|
3010
|
+
"note": "History is sent by the CLIENT, unlike the storefront chatbot's, which removed it as a security fix."
|
|
3011
|
+
}
|
|
3012
|
+
],
|
|
3013
|
+
"source": "go",
|
|
3014
|
+
"goType": "(inline)"
|
|
3015
|
+
},
|
|
3001
3016
|
"post:/api/sites/{siteId}/fonts": {
|
|
3002
3017
|
"fields": [
|
|
3003
3018
|
{
|
|
@@ -675,7 +675,7 @@ export const PAGE_LAYOUT_SEEDS = {
|
|
|
675
675
|
"collectionType": "all_products",
|
|
676
676
|
"collectionId": "all_products",
|
|
677
677
|
"articleCategoryId": "all_articles",
|
|
678
|
-
"collectionListType": "
|
|
678
|
+
"collectionListType": "page_collections",
|
|
679
679
|
"listNavIcon": "ArrowLeftSLine",
|
|
680
680
|
"listNavPosition": "inside",
|
|
681
681
|
"listNavIconSize": 16,
|
|
@@ -2411,7 +2411,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
2411
2411
|
"collectionType": "all_products",
|
|
2412
2412
|
"collectionId": "all_products",
|
|
2413
2413
|
"articleCategoryId": "all_articles",
|
|
2414
|
-
"collectionListType": "
|
|
2414
|
+
"collectionListType": "page_collections",
|
|
2415
2415
|
"listNavIcon": "ArrowLeftSLine",
|
|
2416
2416
|
"listNavPosition": "inside",
|
|
2417
2417
|
"listNavIconSize": 16,
|
|
@@ -3109,7 +3109,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
3109
3109
|
"collectionType": "all_products",
|
|
3110
3110
|
"collectionId": "all_products",
|
|
3111
3111
|
"articleCategoryId": "all_articles",
|
|
3112
|
-
"collectionListType": "
|
|
3112
|
+
"collectionListType": "page_collections",
|
|
3113
3113
|
"listNavIcon": "ArrowLeftSLine",
|
|
3114
3114
|
"listNavPosition": "inside",
|
|
3115
3115
|
"listNavIconSize": 16,
|
|
@@ -3813,7 +3813,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
3813
3813
|
"collectionType": "all_products",
|
|
3814
3814
|
"collectionId": "all_products",
|
|
3815
3815
|
"articleCategoryId": "all_articles",
|
|
3816
|
-
"collectionListType": "
|
|
3816
|
+
"collectionListType": "page_collections",
|
|
3817
3817
|
"listNavIcon": "ArrowLeftSLine",
|
|
3818
3818
|
"listNavPosition": "inside",
|
|
3819
3819
|
"listNavIconSize": 16,
|
|
@@ -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, blogCategoryList, courseList] = 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`),
|
|
@@ -59,6 +59,11 @@ export async function gatherReadiness(ctx, siteId, pageNodes) {
|
|
|
59
59
|
// the prefix at all.
|
|
60
60
|
get(`/api/sites/${site}/blog-categories?limit=1`),
|
|
61
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}`),
|
|
62
67
|
]);
|
|
63
68
|
// A gateway counts only when it is BOTH enabled and configured — the editor's
|
|
64
69
|
// `live` getter also filters by the store's currency, which is a narrowing:
|
|
@@ -116,5 +121,8 @@ export async function gatherReadiness(ctx, siteId, pageNodes) {
|
|
|
116
121
|
courses: Array.isArray(courseList?.courses)
|
|
117
122
|
? (courseList?.total ?? courseList.courses.length)
|
|
118
123
|
: null,
|
|
124
|
+
maintenanceMode: typeof siteRecord?.site?.maintenanceMode === 'boolean'
|
|
125
|
+
? siteRecord.site.maintenanceMode
|
|
126
|
+
: null,
|
|
119
127
|
};
|
|
120
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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sbuilder-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.1",
|
|
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",
|