sbuilder-mcp 0.90.0 → 0.91.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 +11 -0
- package/CHANGELOG.vi.md +11 -0
- package/dist/catalog/appscaffolds.generated.js +6 -0
- package/dist/catalog/deadkeys.generated.js +3 -3
- package/dist/catalog/elements.generated.js +80 -2
- package/dist/catalog/overlays.generated.js +5 -0
- package/dist/catalog/shapes.generated.js +1 -1
- package/dist/catalog/source.generated.js +2 -2
- package/dist/catalog/storepages.generated.js +15 -0
- package/dist/domains/site/builder.js +3 -3
- package/dist/domains/site/findings.js +6 -2
- package/dist/domains/site/record.js +13 -5
- package/dist/domains/site/review.js +40 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,17 @@ 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.91.0] - 2026-10-23
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `sb_bind` accepts `record.money.<fid>` for number and integer Collections fields, showing the stored whole-unit value as money in the site's base currency (1850000 renders as 1.850.000 ₫).
|
|
13
|
+
- `sb_review` reports `record_filter_invalid` for filter and sort controls aimed at a record list whose axis is not an ID field, whose target is not a collection record list or is a relation list, whose behaviour is not `filter`, or whose sort value is not `<fieldId>_asc|desc`.
|
|
14
|
+
- Filter controls accept `filterSource: "record"` to filter and sort record lists through the `?f.record.<fld>~<list>=…&s.<list>=<fld>_desc&p.<list>=2` URL contract.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- `sb_set` re-derives a text record tile's binding when `recordFormat`, `recordField` or `recordFieldType` changes, so choosing `recordFormat: "money"` switches it to `record.money.<fid>`.
|
|
18
|
+
- The API catalog is synced with web_builder v1.0.171, and `recordFormat` is now a base-only config key.
|
|
19
|
+
|
|
9
20
|
## [0.90.0] - 2026-10-22
|
|
10
21
|
|
|
11
22
|
### Added
|
package/CHANGELOG.vi.md
CHANGED
|
@@ -6,6 +6,17 @@ 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.91.0] - 2026-10-23
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `sb_bind` nhận `record.money.<fid>` cho field number và integer của Collections, hiển thị giá trị đã lưu (đơn vị nguyên) thành tiền theo tiền tệ gốc của site (1850000 hiện là 1.850.000 ₫).
|
|
13
|
+
- `sb_review` báo `record_filter_invalid` cho control lọc và sắp xếp nhắm vào danh sách record mà axis không phải ID field, target không phải danh sách record của collection hoặc là relation list, behaviour khác `filter`, hay giá trị sort không theo `<fieldId>_asc|desc`.
|
|
14
|
+
- Các control lọc nhận `filterSource: "record"` để lọc và sắp xếp danh sách record qua hợp đồng URL `?f.record.<fld>~<list>=…&s.<list>=<fld>_desc&p.<list>=2`.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- `sb_set` suy lại binding của tile text record khi `recordFormat`, `recordField` hoặc `recordFieldType` đổi, nên chọn `recordFormat: "money"` chuyển binding sang `record.money.<fid>`.
|
|
18
|
+
- Catalog API được đồng bộ với web_builder v1.0.171, và `recordFormat` nay là khoá config base-only.
|
|
19
|
+
|
|
9
20
|
## [0.90.0] - 2026-10-22
|
|
10
21
|
|
|
11
22
|
### Added
|
|
@@ -53,6 +53,7 @@ export const APP_SCAFFOLDS = {
|
|
|
53
53
|
"kind": "title",
|
|
54
54
|
"recordField": "",
|
|
55
55
|
"recordFieldType": "",
|
|
56
|
+
"recordFormat": "",
|
|
56
57
|
"textValue": "",
|
|
57
58
|
"descriptionDisplayType": "Full",
|
|
58
59
|
"descriptionLines": 3,
|
|
@@ -98,6 +99,7 @@ export const APP_SCAFFOLDS = {
|
|
|
98
99
|
"kind": "summary",
|
|
99
100
|
"recordField": "",
|
|
100
101
|
"recordFieldType": "",
|
|
102
|
+
"recordFormat": "",
|
|
101
103
|
"textValue": "",
|
|
102
104
|
"descriptionDisplayType": "Full",
|
|
103
105
|
"descriptionLines": 3,
|
|
@@ -143,6 +145,7 @@ export const APP_SCAFFOLDS = {
|
|
|
143
145
|
"kind": "price",
|
|
144
146
|
"recordField": "",
|
|
145
147
|
"recordFieldType": "",
|
|
148
|
+
"recordFormat": "",
|
|
146
149
|
"textValue": "",
|
|
147
150
|
"descriptionDisplayType": "Full",
|
|
148
151
|
"descriptionLines": 3,
|
|
@@ -238,6 +241,7 @@ export const APP_SCAFFOLDS = {
|
|
|
238
241
|
"kind": "description",
|
|
239
242
|
"recordField": "",
|
|
240
243
|
"recordFieldType": "",
|
|
244
|
+
"recordFormat": "",
|
|
241
245
|
"textValue": "",
|
|
242
246
|
"descriptionDisplayType": "Full",
|
|
243
247
|
"descriptionLines": 3,
|
|
@@ -571,6 +575,7 @@ export const APP_SCAFFOLDS = {
|
|
|
571
575
|
"kind": "title",
|
|
572
576
|
"recordField": "",
|
|
573
577
|
"recordFieldType": "",
|
|
578
|
+
"recordFormat": "",
|
|
574
579
|
"textValue": "",
|
|
575
580
|
"descriptionDisplayType": "Full",
|
|
576
581
|
"descriptionLines": 3,
|
|
@@ -616,6 +621,7 @@ export const APP_SCAFFOLDS = {
|
|
|
616
621
|
"kind": "price",
|
|
617
622
|
"recordField": "",
|
|
618
623
|
"recordFieldType": "",
|
|
624
|
+
"recordFormat": "",
|
|
619
625
|
"textValue": "",
|
|
620
626
|
"descriptionDisplayType": "Full",
|
|
621
627
|
"descriptionLines": 3,
|
|
@@ -36144,6 +36144,7 @@ export const ELEMENTS = {
|
|
|
36144
36144
|
"kind": "title",
|
|
36145
36145
|
"recordField": "",
|
|
36146
36146
|
"recordFieldType": "",
|
|
36147
|
+
"recordFormat": "",
|
|
36147
36148
|
"textValue": "",
|
|
36148
36149
|
"descriptionDisplayType": "Full",
|
|
36149
36150
|
"descriptionLines": 3,
|
|
@@ -37197,6 +37198,7 @@ export const ELEMENTS = {
|
|
|
37197
37198
|
"datasetSource",
|
|
37198
37199
|
"recordField",
|
|
37199
37200
|
"recordFieldType",
|
|
37201
|
+
"recordFormat",
|
|
37200
37202
|
"textValue",
|
|
37201
37203
|
"descriptionDisplayType",
|
|
37202
37204
|
"descriptionLines",
|
|
@@ -37221,6 +37223,7 @@ export const ELEMENTS = {
|
|
|
37221
37223
|
"datasetSource",
|
|
37222
37224
|
"recordField",
|
|
37223
37225
|
"recordFieldType",
|
|
37226
|
+
"recordFormat",
|
|
37224
37227
|
"textValue",
|
|
37225
37228
|
"descriptionDisplayType",
|
|
37226
37229
|
"descriptionLines",
|
|
@@ -37245,6 +37248,7 @@ export const ELEMENTS = {
|
|
|
37245
37248
|
"datasetSource",
|
|
37246
37249
|
"recordField",
|
|
37247
37250
|
"recordFieldType",
|
|
37251
|
+
"recordFormat",
|
|
37248
37252
|
"textValue",
|
|
37249
37253
|
"descriptionDisplayType",
|
|
37250
37254
|
"descriptionLines",
|
|
@@ -37268,6 +37272,7 @@ export const ELEMENTS = {
|
|
|
37268
37272
|
"datasetSource",
|
|
37269
37273
|
"recordField",
|
|
37270
37274
|
"recordFieldType",
|
|
37275
|
+
"recordFormat",
|
|
37271
37276
|
"textValue",
|
|
37272
37277
|
"descriptionDisplayType",
|
|
37273
37278
|
"descriptionLines",
|
|
@@ -37284,7 +37289,8 @@ export const ELEMENTS = {
|
|
|
37284
37289
|
"key": "record",
|
|
37285
37290
|
"label": "Data",
|
|
37286
37291
|
"controls": [
|
|
37287
|
-
"record_field"
|
|
37292
|
+
"record_field",
|
|
37293
|
+
"record_format"
|
|
37288
37294
|
]
|
|
37289
37295
|
},
|
|
37290
37296
|
{
|
|
@@ -37404,6 +37410,7 @@ export const ELEMENTS = {
|
|
|
37404
37410
|
"datasetSource",
|
|
37405
37411
|
"recordField",
|
|
37406
37412
|
"recordFieldType",
|
|
37413
|
+
"recordFormat",
|
|
37407
37414
|
"textValue",
|
|
37408
37415
|
"descriptionDisplayType",
|
|
37409
37416
|
"descriptionLines",
|
|
@@ -37417,6 +37424,7 @@ export const ELEMENTS = {
|
|
|
37417
37424
|
"collection",
|
|
37418
37425
|
"article",
|
|
37419
37426
|
"record_field",
|
|
37427
|
+
"record_format",
|
|
37420
37428
|
"description_display",
|
|
37421
37429
|
"width_select",
|
|
37422
37430
|
"height_select",
|
|
@@ -37457,7 +37465,8 @@ export const ELEMENTS = {
|
|
|
37457
37465
|
"Set config.kind to \"title\", \"vendor\", or \"description\"",
|
|
37458
37466
|
"For a description, set config.descriptionDisplayType to \"Compact\" and config.descriptionLines to clamp it; enable specials.moreButtonEnabled for the toggle",
|
|
37459
37467
|
"Customise config.moreText / config.lessText and config.icon (the chevron) for the toggle",
|
|
37460
|
-
"Style per state (default / hover / active) via the state switcher"
|
|
37468
|
+
"Style per state (default / hover / active) via the state switcher",
|
|
37469
|
+
"In a record list on a number/integer field, set config.recordFormat to \"money\" to print it in the site currency (record.money.<fieldId>)"
|
|
37461
37470
|
],
|
|
37462
37471
|
"semantics": [
|
|
37463
37472
|
"product",
|
|
@@ -45690,6 +45699,69 @@ export const RECORD_BINDING_PROBES = [
|
|
|
45690
45699
|
}
|
|
45691
45700
|
]
|
|
45692
45701
|
},
|
|
45702
|
+
{
|
|
45703
|
+
"type": "text-dataset",
|
|
45704
|
+
"config": {
|
|
45705
|
+
"datasetSource": "record",
|
|
45706
|
+
"recordField": "fld_0123456789abcdef",
|
|
45707
|
+
"recordFieldType": "integer",
|
|
45708
|
+
"recordFormat": "money"
|
|
45709
|
+
},
|
|
45710
|
+
"bindings": [
|
|
45711
|
+
{
|
|
45712
|
+
"id": "bind-text",
|
|
45713
|
+
"source": "record.money.fld_0123456789abcdef",
|
|
45714
|
+
"field": "specials.boundText",
|
|
45715
|
+
"target": {
|
|
45716
|
+
"type": "record",
|
|
45717
|
+
"id": "",
|
|
45718
|
+
"kind": "title"
|
|
45719
|
+
}
|
|
45720
|
+
}
|
|
45721
|
+
]
|
|
45722
|
+
},
|
|
45723
|
+
{
|
|
45724
|
+
"type": "text-dataset",
|
|
45725
|
+
"config": {
|
|
45726
|
+
"datasetSource": "record",
|
|
45727
|
+
"recordField": "fld_0123456789abcdef",
|
|
45728
|
+
"recordFieldType": "number",
|
|
45729
|
+
"recordFormat": "money"
|
|
45730
|
+
},
|
|
45731
|
+
"bindings": [
|
|
45732
|
+
{
|
|
45733
|
+
"id": "bind-text",
|
|
45734
|
+
"source": "record.money.fld_0123456789abcdef",
|
|
45735
|
+
"field": "specials.boundText",
|
|
45736
|
+
"target": {
|
|
45737
|
+
"type": "record",
|
|
45738
|
+
"id": "",
|
|
45739
|
+
"kind": "title"
|
|
45740
|
+
}
|
|
45741
|
+
}
|
|
45742
|
+
]
|
|
45743
|
+
},
|
|
45744
|
+
{
|
|
45745
|
+
"type": "text-dataset",
|
|
45746
|
+
"config": {
|
|
45747
|
+
"datasetSource": "record",
|
|
45748
|
+
"recordField": "fld_0123456789abcdef",
|
|
45749
|
+
"recordFieldType": "text",
|
|
45750
|
+
"recordFormat": "money"
|
|
45751
|
+
},
|
|
45752
|
+
"bindings": [
|
|
45753
|
+
{
|
|
45754
|
+
"id": "bind-text",
|
|
45755
|
+
"source": "record.fld_0123456789abcdef",
|
|
45756
|
+
"field": "specials.boundText",
|
|
45757
|
+
"target": {
|
|
45758
|
+
"type": "record",
|
|
45759
|
+
"id": "",
|
|
45760
|
+
"kind": "title"
|
|
45761
|
+
}
|
|
45762
|
+
}
|
|
45763
|
+
]
|
|
45764
|
+
},
|
|
45693
45765
|
{
|
|
45694
45766
|
"type": "text-dataset",
|
|
45695
45767
|
"config": {
|
|
@@ -49547,6 +49619,7 @@ export const ELEMENT_VALUES = {
|
|
|
49547
49619
|
"custom",
|
|
49548
49620
|
"price",
|
|
49549
49621
|
"purchase_history",
|
|
49622
|
+
"record",
|
|
49550
49623
|
"search",
|
|
49551
49624
|
"sort",
|
|
49552
49625
|
"tag"
|
|
@@ -49618,6 +49691,7 @@ export const ELEMENT_VALUES = {
|
|
|
49618
49691
|
"custom",
|
|
49619
49692
|
"price",
|
|
49620
49693
|
"purchase_history",
|
|
49694
|
+
"record",
|
|
49621
49695
|
"search",
|
|
49622
49696
|
"sort",
|
|
49623
49697
|
"tag"
|
|
@@ -49689,6 +49763,7 @@ export const ELEMENT_VALUES = {
|
|
|
49689
49763
|
"custom",
|
|
49690
49764
|
"price",
|
|
49691
49765
|
"purchase_history",
|
|
49766
|
+
"record",
|
|
49692
49767
|
"search",
|
|
49693
49768
|
"sort",
|
|
49694
49769
|
"tag"
|
|
@@ -49760,6 +49835,7 @@ export const ELEMENT_VALUES = {
|
|
|
49760
49835
|
"custom",
|
|
49761
49836
|
"price",
|
|
49762
49837
|
"purchase_history",
|
|
49838
|
+
"record",
|
|
49763
49839
|
"search",
|
|
49764
49840
|
"sort",
|
|
49765
49841
|
"tag"
|
|
@@ -49831,6 +49907,7 @@ export const ELEMENT_VALUES = {
|
|
|
49831
49907
|
"custom",
|
|
49832
49908
|
"price",
|
|
49833
49909
|
"purchase_history",
|
|
49910
|
+
"record",
|
|
49834
49911
|
"search",
|
|
49835
49912
|
"sort",
|
|
49836
49913
|
"tag"
|
|
@@ -50091,6 +50168,7 @@ export const BASE_ONLY_CONFIG = [
|
|
|
50091
50168
|
"openItems",
|
|
50092
50169
|
"kind",
|
|
50093
50170
|
"datasetSource",
|
|
50171
|
+
"recordFormat",
|
|
50094
50172
|
"collectionId",
|
|
50095
50173
|
"collectionType",
|
|
50096
50174
|
"quantity",
|
|
@@ -363,6 +363,7 @@ export const OVERLAY_SEEDS = {
|
|
|
363
363
|
"kind": "title",
|
|
364
364
|
"recordField": "",
|
|
365
365
|
"recordFieldType": "",
|
|
366
|
+
"recordFormat": "",
|
|
366
367
|
"textValue": "Product name",
|
|
367
368
|
"descriptionDisplayType": "Full",
|
|
368
369
|
"descriptionLines": 3,
|
|
@@ -1354,6 +1355,7 @@ export const OVERLAY_SEEDS = {
|
|
|
1354
1355
|
"kind": "title",
|
|
1355
1356
|
"recordField": "",
|
|
1356
1357
|
"recordFieldType": "",
|
|
1358
|
+
"recordFormat": "",
|
|
1357
1359
|
"textValue": "",
|
|
1358
1360
|
"descriptionDisplayType": "Full",
|
|
1359
1361
|
"descriptionLines": 3,
|
|
@@ -1769,6 +1771,7 @@ export const OVERLAY_SEEDS = {
|
|
|
1769
1771
|
"kind": "description",
|
|
1770
1772
|
"recordField": "",
|
|
1771
1773
|
"recordFieldType": "",
|
|
1774
|
+
"recordFormat": "",
|
|
1772
1775
|
"textValue": "",
|
|
1773
1776
|
"descriptionDisplayType": "Full",
|
|
1774
1777
|
"descriptionLines": 3,
|
|
@@ -2409,6 +2412,7 @@ export const CART_SEEDS = {
|
|
|
2409
2412
|
"kind": "title",
|
|
2410
2413
|
"recordField": "",
|
|
2411
2414
|
"recordFieldType": "",
|
|
2415
|
+
"recordFormat": "",
|
|
2412
2416
|
"textValue": "Product name",
|
|
2413
2417
|
"descriptionDisplayType": "Full",
|
|
2414
2418
|
"descriptionLines": 3,
|
|
@@ -3245,6 +3249,7 @@ export const CART_SEEDS = {
|
|
|
3245
3249
|
"kind": "title",
|
|
3246
3250
|
"recordField": "",
|
|
3247
3251
|
"recordFieldType": "",
|
|
3252
|
+
"recordFormat": "",
|
|
3248
3253
|
"textValue": "Product name",
|
|
3249
3254
|
"descriptionDisplayType": "Full",
|
|
3250
3255
|
"descriptionLines": 3,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// GENERATED by scripts/gen-catalog.ts — do not edit by hand.
|
|
2
2
|
// The platform commit every other generated file here describes.
|
|
3
3
|
export const PLATFORM_SOURCE = {
|
|
4
|
-
"commit": "
|
|
5
|
-
"committedAt": "2026-10-
|
|
4
|
+
"commit": "4a6a6b151a18713d4f6c3235f063b870d314a968",
|
|
5
|
+
"committedAt": "2026-10-23T14:44:15+07:00",
|
|
6
6
|
"dirty": false
|
|
7
7
|
};
|
|
@@ -881,6 +881,7 @@ export const PAGE_LAYOUT_SEEDS = {
|
|
|
881
881
|
"kind": "title",
|
|
882
882
|
"recordField": "",
|
|
883
883
|
"recordFieldType": "",
|
|
884
|
+
"recordFormat": "",
|
|
884
885
|
"textValue": "Article title",
|
|
885
886
|
"descriptionDisplayType": "Full",
|
|
886
887
|
"descriptionLines": 3,
|
|
@@ -926,6 +927,7 @@ export const PAGE_LAYOUT_SEEDS = {
|
|
|
926
927
|
"kind": "summary",
|
|
927
928
|
"recordField": "",
|
|
928
929
|
"recordFieldType": "",
|
|
930
|
+
"recordFormat": "",
|
|
929
931
|
"textValue": "Article summary",
|
|
930
932
|
"descriptionDisplayType": "Full",
|
|
931
933
|
"descriptionLines": 3,
|
|
@@ -971,6 +973,7 @@ export const PAGE_LAYOUT_SEEDS = {
|
|
|
971
973
|
"kind": "date",
|
|
972
974
|
"recordField": "",
|
|
973
975
|
"recordFieldType": "",
|
|
976
|
+
"recordFormat": "",
|
|
974
977
|
"textValue": "2026-08-13",
|
|
975
978
|
"descriptionDisplayType": "Full",
|
|
976
979
|
"descriptionLines": 3,
|
|
@@ -2057,6 +2060,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
2057
2060
|
"kind": "title",
|
|
2058
2061
|
"recordField": "",
|
|
2059
2062
|
"recordFieldType": "",
|
|
2063
|
+
"recordFormat": "",
|
|
2060
2064
|
"textValue": "",
|
|
2061
2065
|
"descriptionDisplayType": "Full",
|
|
2062
2066
|
"descriptionLines": 3,
|
|
@@ -2472,6 +2476,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
2472
2476
|
"kind": "description",
|
|
2473
2477
|
"recordField": "",
|
|
2474
2478
|
"recordFieldType": "",
|
|
2479
|
+
"recordFormat": "",
|
|
2475
2480
|
"textValue": "",
|
|
2476
2481
|
"descriptionDisplayType": "Full",
|
|
2477
2482
|
"descriptionLines": 3,
|
|
@@ -2899,6 +2904,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
2899
2904
|
"kind": "title",
|
|
2900
2905
|
"recordField": "",
|
|
2901
2906
|
"recordFieldType": "",
|
|
2907
|
+
"recordFormat": "",
|
|
2902
2908
|
"textValue": "",
|
|
2903
2909
|
"descriptionDisplayType": "Full",
|
|
2904
2910
|
"descriptionLines": 3,
|
|
@@ -3334,6 +3340,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
3334
3340
|
"kind": "title",
|
|
3335
3341
|
"recordField": "",
|
|
3336
3342
|
"recordFieldType": "",
|
|
3343
|
+
"recordFormat": "",
|
|
3337
3344
|
"textValue": "Product name",
|
|
3338
3345
|
"descriptionDisplayType": "Full",
|
|
3339
3346
|
"descriptionLines": 3,
|
|
@@ -4054,6 +4061,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
4054
4061
|
"kind": "title",
|
|
4055
4062
|
"recordField": "",
|
|
4056
4063
|
"recordFieldType": "",
|
|
4064
|
+
"recordFormat": "",
|
|
4057
4065
|
"textValue": "Product name",
|
|
4058
4066
|
"descriptionDisplayType": "Full",
|
|
4059
4067
|
"descriptionLines": 3,
|
|
@@ -4347,6 +4355,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
4347
4355
|
"kind": "title",
|
|
4348
4356
|
"recordField": "",
|
|
4349
4357
|
"recordFieldType": "",
|
|
4358
|
+
"recordFormat": "",
|
|
4350
4359
|
"textValue": "",
|
|
4351
4360
|
"descriptionDisplayType": "Full",
|
|
4352
4361
|
"descriptionLines": 3,
|
|
@@ -4607,6 +4616,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
4607
4616
|
"kind": "title",
|
|
4608
4617
|
"recordField": "",
|
|
4609
4618
|
"recordFieldType": "",
|
|
4619
|
+
"recordFormat": "",
|
|
4610
4620
|
"textValue": "Article title",
|
|
4611
4621
|
"descriptionDisplayType": "Full",
|
|
4612
4622
|
"descriptionLines": 3,
|
|
@@ -4652,6 +4662,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
4652
4662
|
"kind": "summary",
|
|
4653
4663
|
"recordField": "",
|
|
4654
4664
|
"recordFieldType": "",
|
|
4665
|
+
"recordFormat": "",
|
|
4655
4666
|
"textValue": "Article summary",
|
|
4656
4667
|
"descriptionDisplayType": "Full",
|
|
4657
4668
|
"descriptionLines": 3,
|
|
@@ -4697,6 +4708,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
4697
4708
|
"kind": "date",
|
|
4698
4709
|
"recordField": "",
|
|
4699
4710
|
"recordFieldType": "",
|
|
4711
|
+
"recordFormat": "",
|
|
4700
4712
|
"textValue": "2026-08-13",
|
|
4701
4713
|
"descriptionDisplayType": "Full",
|
|
4702
4714
|
"descriptionLines": 3,
|
|
@@ -4967,6 +4979,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
4967
4979
|
"kind": "title",
|
|
4968
4980
|
"recordField": "",
|
|
4969
4981
|
"recordFieldType": "",
|
|
4982
|
+
"recordFormat": "",
|
|
4970
4983
|
"textValue": "",
|
|
4971
4984
|
"descriptionDisplayType": "Full",
|
|
4972
4985
|
"descriptionLines": 3,
|
|
@@ -5012,6 +5025,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
5012
5025
|
"kind": "date",
|
|
5013
5026
|
"recordField": "",
|
|
5014
5027
|
"recordFieldType": "",
|
|
5028
|
+
"recordFormat": "",
|
|
5015
5029
|
"textValue": "",
|
|
5016
5030
|
"descriptionDisplayType": "Full",
|
|
5017
5031
|
"descriptionLines": 3,
|
|
@@ -5057,6 +5071,7 @@ export const STORE_PAGE_SEEDS = {
|
|
|
5057
5071
|
"kind": "description",
|
|
5058
5072
|
"recordField": "",
|
|
5059
5073
|
"recordFieldType": "",
|
|
5074
|
+
"recordFormat": "",
|
|
5060
5075
|
"textValue": "",
|
|
5061
5076
|
"descriptionDisplayType": "Full",
|
|
5062
5077
|
"descriptionLines": 3,
|
|
@@ -512,9 +512,9 @@ export function baseOnlyKeys(doc, id, keys, opts) {
|
|
|
512
512
|
* binding is worse.
|
|
513
513
|
*/
|
|
514
514
|
function rebindPatch(doc, id, keys) {
|
|
515
|
-
// `recordField` / `recordFieldType` are a record tile's field
|
|
516
|
-
// (datasetBindings.ts
|
|
517
|
-
const touchesAxis = ['kind', 'datasetSource', 'recordField', 'recordFieldType'].some((k) => k in keys);
|
|
515
|
+
// `recordField` / `recordFieldType` / `recordFormat` are a record tile's field
|
|
516
|
+
// axis (datasetBindings.ts recordSource) — `setRecordField` / `setRecordFormat` heal on them.
|
|
517
|
+
const touchesAxis = ['kind', 'datasetSource', 'recordField', 'recordFieldType', 'recordFormat'].some((k) => k in keys);
|
|
518
518
|
if (!touchesAxis)
|
|
519
519
|
return null;
|
|
520
520
|
const node = doc.node(id);
|
|
@@ -120,6 +120,10 @@ export const FIX = {
|
|
|
120
120
|
'datasetSource is "record" — one card template, rows edited as data. Logic the platform has ' +
|
|
121
121
|
'no native control for yet (visitor filters, computed totals) may stay in code, reading ' +
|
|
122
122
|
'GET /_wb/collections/{slug}/records instead of its own copy.',
|
|
123
|
+
record_filter_invalid: 'Aim it at ONE collection\'s record list(s) and a field: sb_set id "<id>", namespace specials, keys ' +
|
|
124
|
+
'{ "filterSource": "record", "filterAxis": "fld_…", "filterTargets": ["<list id>"], "filterBehavior": "filter" } — ' +
|
|
125
|
+
'axis types text/select/reference/url/date/boolean/integer/number. A sort select takes filterValues ' +
|
|
126
|
+
'[{ "value": "fld_…_asc" | "fld_…_desc", "label": "…" }].',
|
|
123
127
|
record_relation_unset: 'Link it to its parent row: sb_set id "<id>", namespace config, keys { "recordRelationField": "fld_…" } — ' +
|
|
124
128
|
'the ID of a "reference" field in THIS list\'s collection that targets the enclosing list\'s collection ' +
|
|
125
129
|
'(GET /api/sites/{siteId}/collections/{id}/fields, refCollectionId).',
|
|
@@ -129,8 +133,8 @@ export const FIX = {
|
|
|
129
133
|
'e.g. a short "Chưa có dữ liệu" line.',
|
|
130
134
|
record_field_unset: 'Name the field by its ID: sb_set id "<id>", namespace config, keys { "recordField": "fld_…", ' +
|
|
131
135
|
'"recordFieldType": "<the field\'s type>" } — ids and types are on GET /api/sites/{siteId}/collections/{id}/fields. ' +
|
|
132
|
-
'A text-dataset shows text/richtext/number/integer/boolean/date/select/url/reference (integer
|
|
133
|
-
'
|
|
136
|
+
'A text-dataset shows text/richtext/number/integer/boolean/date/select/url/reference (a number/integer ' +
|
|
137
|
+
'prints as money with "recordFormat": "money"); a collection-media shows image. A gallery field binds nothing yet.',
|
|
134
138
|
unread_value: 'Write a value the renderer reads: sb_traits_for "<type>" lists them; sb_set id "<id>" ' +
|
|
135
139
|
'with one, at the same breakpoint it is stored at.',
|
|
136
140
|
unknown_icon: 'Write a real icon name: sb_set id "<id>", namespace <ns>, keys { "<key>": "<name>" } — the ' +
|
|
@@ -10,10 +10,13 @@
|
|
|
10
10
|
/** `collections.NewID("fld")` — schema/src/elements/recordContext.ts:33. Anything else binds nothing. */
|
|
11
11
|
export const RECORD_FIELD_ID = /^fld_[0-9a-f]{16}$/;
|
|
12
12
|
/**
|
|
13
|
-
* A `record.*` source a context can supply: `record.<fid>`, `record.html.<fid>`,
|
|
14
|
-
* `record.
|
|
13
|
+
* A `record.*` source a context can supply: `record.<fid>`, `record.html.<fid>`,
|
|
14
|
+
* `record.money.<fid>` (a number/integer field formatted in the site's currency),
|
|
15
|
+
* or `record.id` — the row's own record id (recordContext.ts).
|
|
15
16
|
*/
|
|
16
|
-
export const RECORD_SOURCE = /^record\.(?:id|(?:html\.)?fld_[0-9a-f]{16})$/;
|
|
17
|
+
export const RECORD_SOURCE = /^record\.(?:id|(?:html\.|money\.)?fld_[0-9a-f]{16})$/;
|
|
18
|
+
/** The field types `record.money.<fid>` formats — recordContext.ts RECORD_MONEY_FIELD_TYPES. */
|
|
19
|
+
export const RECORD_MONEY_TYPES = new Set(['number', 'integer']);
|
|
17
20
|
/** The only record source `specials.boundHtml` admits — schema/src/rawSinkBindings.ts:102. */
|
|
18
21
|
export const RECORD_HTML_SOURCE = /^record\.html\.fld_[0-9a-f]{16}$/;
|
|
19
22
|
/** The tile elements whose binding the record field drives (editor/src/element/recordList.ts TILE_FIELD_TYPES). */
|
|
@@ -33,6 +36,8 @@ export function recordTileBindings(type, config, rows) {
|
|
|
33
36
|
const fid = config.recordField;
|
|
34
37
|
const ok = typeof fid === 'string' && RECORD_FIELD_ID.test(fid);
|
|
35
38
|
const html = type === 'text-dataset' && config.recordFieldType === 'richtext';
|
|
39
|
+
// datasetBindings.ts isRecordMoney: a stale recordFormat on any other type is ignored.
|
|
40
|
+
const money = type === 'text-dataset' && config.recordFormat === 'money' && RECORD_MONEY_TYPES.has(String(config.recordFieldType));
|
|
36
41
|
return rows.map((row) => {
|
|
37
42
|
const b = row;
|
|
38
43
|
if (b.id === 'bind-image')
|
|
@@ -40,7 +45,7 @@ export function recordTileBindings(type, config, rows) {
|
|
|
40
45
|
if (b.id === 'bind-text') {
|
|
41
46
|
return {
|
|
42
47
|
...b,
|
|
43
|
-
source: ok ? `record.${html ? 'html.' : ''}${fid}` : '',
|
|
48
|
+
source: ok ? `record.${html ? 'html.' : money ? 'money.' : ''}${fid}` : '',
|
|
44
49
|
field: html ? 'specials.boundHtml' : 'specials.boundText',
|
|
45
50
|
};
|
|
46
51
|
}
|
|
@@ -85,7 +90,8 @@ export function recordFieldProblem(source, scope) {
|
|
|
85
90
|
if (source === 'record.id')
|
|
86
91
|
return undefined;
|
|
87
92
|
const html = source.startsWith('record.html.');
|
|
88
|
-
const
|
|
93
|
+
const money = source.startsWith('record.money.');
|
|
94
|
+
const fid = source.slice(html ? 12 : money ? 13 : 7);
|
|
89
95
|
const f = scope.flatMap((s) => s.fields).find((x) => x.id === fid);
|
|
90
96
|
if (!f) {
|
|
91
97
|
const avail = scope
|
|
@@ -95,6 +101,8 @@ export function recordFieldProblem(source, scope) {
|
|
|
95
101
|
}
|
|
96
102
|
if (f.type === 'gallery')
|
|
97
103
|
return `${fid} (${f.key}) is a gallery field, which the renderers do not bind yet — it emits nothing.`;
|
|
104
|
+
if (money && !RECORD_MONEY_TYPES.has(f.type))
|
|
105
|
+
return `${fid} (${f.key}) is ${f.type} — record.money. formats only a number or integer field.`;
|
|
98
106
|
if (html && f.type !== 'richtext')
|
|
99
107
|
return `${fid} (${f.key}) is ${f.type}, not richtext — bind it as "record.${fid}".`;
|
|
100
108
|
if (!html && f.type === 'richtext')
|
|
@@ -670,6 +670,46 @@ opts = {}) {
|
|
|
670
670
|
});
|
|
671
671
|
}
|
|
672
672
|
}
|
|
673
|
+
// RECORD FILTERS (web_builder PR #157, contract §7.1): a filter/sort control aimed at a
|
|
674
|
+
// record list. Every miss below renders a control that empties the list or narrows nothing.
|
|
675
|
+
{
|
|
676
|
+
const sp = (n.specials ?? {});
|
|
677
|
+
const targets = Array.isArray(sp.filterTargets) ? sp.filterTargets.map(String) : [];
|
|
678
|
+
const recordTargets = targets.filter((t) => {
|
|
679
|
+
const c = d.nodes[t]?.config;
|
|
680
|
+
return d.nodes[t]?.data.type === 'list-dataset' && c?.datasetSource === 'record';
|
|
681
|
+
});
|
|
682
|
+
const why = [];
|
|
683
|
+
if (sp.filterSource === 'record') {
|
|
684
|
+
if (!RECORD_FIELD_ID.test(String(sp.filterAxis ?? '')))
|
|
685
|
+
why.push(`filterAxis "${String(sp.filterAxis ?? '')}" is not a field ID`);
|
|
686
|
+
if (targets.length && recordTargets.length !== targets.length)
|
|
687
|
+
why.push('a filterTargets entry is not a record list');
|
|
688
|
+
const cfgOf = (t) => d.nodes[t].config ?? {};
|
|
689
|
+
if (recordTargets.some((t) => String(cfgOf(t).recordRelationField ?? '')))
|
|
690
|
+
why.push('it targets a relation list');
|
|
691
|
+
if (new Set(recordTargets.map((t) => String(cfgOf(t).recordCollectionId ?? ''))).size > 1)
|
|
692
|
+
why.push('its targets read different collections');
|
|
693
|
+
if (sp.filterBehavior !== undefined && sp.filterBehavior !== 'filter')
|
|
694
|
+
why.push(`filterBehavior "${String(sp.filterBehavior)}" — a record filter only narrows ("filter")`);
|
|
695
|
+
}
|
|
696
|
+
if (sp.filterSource === 'sort' && recordTargets.length) {
|
|
697
|
+
const bad = (Array.isArray(sp.filterValues) ? sp.filterValues : [])
|
|
698
|
+
.map((v) => String(v?.value ?? ''))
|
|
699
|
+
.filter((v) => !/^fld_[0-9a-f]{16}_(?:asc|desc)$/.test(v));
|
|
700
|
+
if (bad.length)
|
|
701
|
+
why.push(`sort values ${bad.slice(0, 3).map((v) => `"${v}"`).join(', ')} are not "<fieldId>_asc|desc" — a record list ignores product sort keys`);
|
|
702
|
+
}
|
|
703
|
+
if (why.length) {
|
|
704
|
+
out.push({
|
|
705
|
+
code: 'record_filter_invalid',
|
|
706
|
+
nodeId: id,
|
|
707
|
+
type,
|
|
708
|
+
problem: `A record ${sp.filterSource === 'sort' ? 'sort' : 'filter'} control that narrows nothing or empties its list: ${why.join('; ')}.`,
|
|
709
|
+
fix: fill('record_filter_invalid', { id }),
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
673
713
|
if (RECORD_TILES.has(type) && cfg.datasetSource === 'record') {
|
|
674
714
|
const fid = cfg.recordField;
|
|
675
715
|
if (typeof fid !== 'string' || !RECORD_FIELD_ID.test(fid)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sbuilder-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.91.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",
|