sbuilder-mcp 0.9.0 → 0.9.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 +5 -0
- package/CHANGELOG.vi.md +5 -0
- package/dist/domains/site/builder.js +7 -1
- package/dist/domains/site/sticky.js +40 -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.9.1] - 2026-09-09
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- sb_set now refuses a `config.stuckAfter` write the renderer would drop on the floor — a negative, non-finite, or empty value, or one set on a node that cannot pin — instead of silently storing, saving, and publishing a threshold the runtime island never reads and quietly falling back to its automatic answer.
|
|
13
|
+
|
|
9
14
|
## [0.9.0] - 2026-09-08
|
|
10
15
|
|
|
11
16
|
### Added
|
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.9.1] - 2026-09-09
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- sb_set giờ từ chối ghi `config.stuckAfter` nếu giá trị sẽ bị renderer âm thầm bỏ qua — số âm, không hữu hạn, rỗng, hoặc được đặt trên một node không thể ghim — thay vì lưu, save rồi publish một ngưỡng mà runtime island không bao giờ đọc và lặng lẽ quay về đáp án tự động của nó.
|
|
13
|
+
|
|
9
14
|
## [0.9.0] - 2026-09-08
|
|
10
15
|
|
|
11
16
|
### Added
|
|
@@ -2,7 +2,7 @@ import { isOverlay, subtreeIds, ancestors, appBlockRoot, SPEC_GLOBAL_ID, SPEC_GL
|
|
|
2
2
|
import { ELEMENTS, ELEMENT_SEEDS, SATELLITE_RULES } from '../../catalog/elements.generated.js';
|
|
3
3
|
import { bindingsForConfig, createNode, mintSatellites } from './node.js';
|
|
4
4
|
import { refuseSecondTemplate } from './traps.js';
|
|
5
|
-
import { STUCK_STATE, refuseStuckConfig, requireStuckHost, stickySeeds } from './sticky.js';
|
|
5
|
+
import { STUCK_STATE, refuseStuckAfter, refuseStuckConfig, requireStuckHost, stickySeeds, } from './sticky.js';
|
|
6
6
|
import { genId } from './ids.js';
|
|
7
7
|
/** Append sentinel: splice clamps a too-large index, and `isSyncablePatch`
|
|
8
8
|
* deliberately allows one — an append is a legitimate thing to describe. */
|
|
@@ -182,6 +182,12 @@ export function setKeys(doc, id, keys, opts) {
|
|
|
182
182
|
// the same silent shape as an unbound element, which cost a whole page of
|
|
183
183
|
// "$0.00" cards to find once.
|
|
184
184
|
const rebind = namespace === 'config' ? rebindPatch(doc, id, keys) : null;
|
|
185
|
+
// The scroll THRESHOLD is a plain config key, and the renderer drops it in two
|
|
186
|
+
// different ways without a word — see sticky.ts. Checked here rather than in
|
|
187
|
+
// the state branch because it is written on the node that PINS, at base or at
|
|
188
|
+
// a breakpoint, never inside a stuck slot.
|
|
189
|
+
if (namespace === 'config')
|
|
190
|
+
refuseStuckAfter(doc.doc, id, keys);
|
|
185
191
|
if (namespace === 'specials') {
|
|
186
192
|
refuseComposedStamp(keys);
|
|
187
193
|
// `specials` is content and identity, base-only by definition, and states
|
|
@@ -36,6 +36,17 @@ import { ancestors } from '../../core/tree.js';
|
|
|
36
36
|
*/
|
|
37
37
|
/** The state key, in `node.states` and `responsive[bp].states`. */
|
|
38
38
|
export const STUCK_STATE = 'stuck';
|
|
39
|
+
/**
|
|
40
|
+
* The config key holding "pinned from WHEN?", in px of page scroll.
|
|
41
|
+
*
|
|
42
|
+
* It reaches the runtime island as a CSS custom property (`--wb-stuck-after`)
|
|
43
|
+
* rather than through `wb:props`, because it is per breakpoint and the cascade
|
|
44
|
+
* is what picks the right number at the right width. Unset is the common case:
|
|
45
|
+
* the island then decides from the element itself — a sticky one the moment it
|
|
46
|
+
* is held away from its place in the flow, a fixed one the moment the page
|
|
47
|
+
* scrolls past where it would have sat.
|
|
48
|
+
*/
|
|
49
|
+
export const STUCK_AFTER = 'stuckAfter';
|
|
39
50
|
/**
|
|
40
51
|
* The positions that HAVE a pinned moment.
|
|
41
52
|
*
|
|
@@ -206,3 +217,32 @@ export function stickyWarning(doc, id, bp) {
|
|
|
206
217
|
`scrolls. The node will not move. Clear overflowX/overflowY on ${blocker}, or pin a node ` +
|
|
207
218
|
'outside it.');
|
|
208
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Refuse a `stuckAfter` that the renderer would drop on the floor.
|
|
222
|
+
*
|
|
223
|
+
* `stuckAfterCss` emits the custom property only for a node that CAN pin and
|
|
224
|
+
* that carries a usable number, and returns an empty string otherwise — so both
|
|
225
|
+
* mistakes here are stored, saved, published and read by nothing. The value
|
|
226
|
+
* rules are the platform's own: zero is honoured ("as soon as the page moves at
|
|
227
|
+
* all" is a real answer, and dropping it would silently fall back to the
|
|
228
|
+
* automatic one); negative and non-finite are not, because no scroll position
|
|
229
|
+
* can satisfy them.
|
|
230
|
+
*/
|
|
231
|
+
export function refuseStuckAfter(doc, id, keys) {
|
|
232
|
+
if (!(STUCK_AFTER in keys))
|
|
233
|
+
return;
|
|
234
|
+
const raw = keys[STUCK_AFTER];
|
|
235
|
+
const n = typeof raw === 'number' ? raw : Number(raw);
|
|
236
|
+
if (raw == null || raw === '' || !Number.isFinite(n) || n < 0) {
|
|
237
|
+
throw new Error(`sbuilder: config.${STUCK_AFTER} is px of page scroll — a finite number, zero or more ` +
|
|
238
|
+
`(0 means "as soon as the page moves at all"). ${JSON.stringify(raw)} is dropped by ` +
|
|
239
|
+
"the renderer, which then falls back to the island's automatic answer without saying " +
|
|
240
|
+
'so. To go back to automatic, remove the key.');
|
|
241
|
+
}
|
|
242
|
+
if (!isPinnedNode(doc.nodes[id])) {
|
|
243
|
+
throw new Error(`sbuilder: config.${STUCK_AFTER} says WHEN a pinned element counts as stuck, and ${id} ` +
|
|
244
|
+
'cannot pin — the renderer emits the threshold only for a node that can ' +
|
|
245
|
+
'(stickyState.ts stuckAfterCss), so this would be stored and read by nothing. ' +
|
|
246
|
+
`Pin it first: sb_set ${id} style { position: "sticky" }.`);
|
|
247
|
+
}
|
|
248
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sbuilder-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.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",
|