sbuilder-mcp 0.4.1 → 0.4.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 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.4.2] - 2026-09-08
10
+
11
+ ### Changed
12
+ - sb_look now waits for the page to stop changing (a MutationObserver, 250 ms quiet / 2000 ms cap) instead of waiting on a networkidle timeout that a storefront's polling cart island and session checks could never satisfy, cutting a typical shot from ~3.2s to under 1s while still photographing a page that never settles rather than holding the shot forever.
13
+
9
14
  ## [0.4.1] - 2026-09-08
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.4.2] - 2026-09-08
10
+
11
+ ### Changed
12
+ - sb_look giờ chờ trang ngừng thay đổi (dùng MutationObserver, 250 ms yên tĩnh / giới hạn 2000 ms) thay vì chờ timeout networkidle mà cart island liên tục polling và các kiểm tra session của storefront không bao giờ thỏa mãn được, rút ngắn một lần chụp điển hình từ ~3.2s xuống dưới 1s, đồng thời vẫn chụp ảnh một trang không bao giờ ổn định thay vì giữ mãi không chụp.
13
+
9
14
  ## [0.4.1] - 2026-09-08
10
15
 
11
16
  ### Fixed
@@ -138,6 +138,54 @@ export async function shoot(url, opts = {}) {
138
138
  }
139
139
  }));
140
140
  }
141
+ /**
142
+ * WAIT FOR THE PAGE TO STOP CHANGING, not for the network to go quiet.
143
+ *
144
+ * This used to be `waitForLoadState('networkidle', { timeout: 2_500 })`, with a
145
+ * comment explaining that a storefront never goes idle — the cart island polls,
146
+ * a session endpoint answers 401 forever. That was correct, and it meant the
147
+ * wait ALWAYS ran to its cap: measured at 2502 ms on every single look, three
148
+ * runs out of three, against a 2847 ms total. Eighty-eight per cent of a
149
+ * screenshot was a timeout the code already knew would never resolve, paid after
150
+ * every edit of a vision loop.
151
+ *
152
+ * A MutationObserver answers the question actually being asked — has the page
153
+ * finished rendering — and answers it the moment it is true. Measured on the
154
+ * same three pages: 400-460 ms, with identical content on screen (images,
155
+ * prices, no empty states). The storefront renders its lists SERVER-side, so
156
+ * everything is present a few hundred ms after `load`; the old wait bought
157
+ * nothing but latency.
158
+ *
159
+ * Bounded twice over, and both bounds matter: `quiet` is how long nothing may
160
+ * change before the page counts as settled, and `cap` stops an animation or a
161
+ * polling widget from holding the shot forever. A page that never settles is
162
+ * photographed anyway — a late picture beats none.
163
+ */
164
+ async function settleDom(page) {
165
+ await page
166
+ .evaluate(({ quiet, cap }) => new Promise((resolve) => {
167
+ const start = Date.now();
168
+ let last = Date.now();
169
+ const mo = new MutationObserver(() => {
170
+ last = Date.now();
171
+ });
172
+ mo.observe(document.documentElement, {
173
+ subtree: true,
174
+ childList: true,
175
+ attributes: true,
176
+ characterData: true,
177
+ });
178
+ const tick = setInterval(() => {
179
+ const now = Date.now();
180
+ if (now - last >= quiet || now - start >= cap) {
181
+ clearInterval(tick);
182
+ mo.disconnect();
183
+ resolve();
184
+ }
185
+ }, 50);
186
+ }), { quiet: 250, cap: 2_000 })
187
+ .catch(() => { });
188
+ }
141
189
  /**
142
190
  * WALK THE PAGE so its lazy images load, then come back to the top.
143
191
  *
@@ -187,7 +235,7 @@ async function shootOne(page, url, width, format, opts) {
187
235
  // storefront. The settle is best-effort: if the page does go quiet, the shot
188
236
  // waits for it; if it never does, the shot happens anyway.
189
237
  await page.goto(url, { waitUntil: 'load', timeout: 30_000 });
190
- await page.waitForLoadState('networkidle', { timeout: 2_500 }).catch(() => { });
238
+ await settleDom(page);
191
239
  await settleLazyImages(page);
192
240
  // A RENDERED page carries its node ids as the HTML `id` attribute — not as
193
241
  // `data-node-id`, which is the editor CANVAS's hook and never reaches the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sbuilder-mcp",
3
- "version": "0.4.1",
3
+ "version": "0.4.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",