sbuilder-mcp 0.63.1 → 0.63.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/transport/socket.js +34 -2
- 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.63.2] - 2026-09-24
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- The live-edit socket now holds frames sent before the server's welcome instead of dropping them, so a section added right after `sb_page_open` reaches an editor watching the page instead of leaving it showing "This page is empty" and risking that empty state being autosaved over the agent's work; the held queue is capped at 500 frames so a long reconnect loop cannot grow memory without bound.
|
|
13
|
+
|
|
9
14
|
## [0.63.1] - 2026-09-24
|
|
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.63.2] - 2026-09-24
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Socket live-edit giờ giữ lại các frame được gửi trước khi server chào (welcome) thay vì loại bỏ chúng, để một section được thêm ngay sau `sb_page_open` đến được với editor đang xem trang thay vì để trang đó hiển thị "This page is empty" và có nguy cơ trạng thái rỗng đó bị autosave đè lên công việc của agent; hàng đợi giữ frame bị giới hạn ở 500 frame để một vòng lặp reconnect kéo dài không thể làm bộ nhớ tăng vô hạn.
|
|
13
|
+
|
|
9
14
|
## [0.63.1] - 2026-09-24
|
|
10
15
|
|
|
11
16
|
### Fixed
|
package/dist/transport/socket.js
CHANGED
|
@@ -11,6 +11,8 @@ import { agentIdentity } from './identity.js';
|
|
|
11
11
|
const OPEN = 1;
|
|
12
12
|
const RETRY_BASE_MS = 500;
|
|
13
13
|
const RETRY_MAX_MS = 15_000;
|
|
14
|
+
/** Frames held while not ready. A reconnect loop must not grow memory forever. */
|
|
15
|
+
const QUEUE_MAX = 500;
|
|
14
16
|
export class RealtimeSocket {
|
|
15
17
|
url;
|
|
16
18
|
token;
|
|
@@ -20,6 +22,19 @@ export class RealtimeSocket {
|
|
|
20
22
|
attempt = 0;
|
|
21
23
|
handlers = [];
|
|
22
24
|
timer = null;
|
|
25
|
+
/** The server has welcomed THIS connection — frames sent now are read. */
|
|
26
|
+
ready = false;
|
|
27
|
+
/**
|
|
28
|
+
* Frames sent while not ready, flushed on the welcome.
|
|
29
|
+
*
|
|
30
|
+
* `sb_page_open` starts the connection and returns; the `sb_add` right after
|
|
31
|
+
* it ran before the handshake finished, and a send that DROPPED on a
|
|
32
|
+
* not-open socket lost it without a trace. The editor watching the page never
|
|
33
|
+
* saw the section appear — it showed an empty page, and its next autosave
|
|
34
|
+
* could write that empty page over the agent's work. Same for every edit made
|
|
35
|
+
* during a reconnect.
|
|
36
|
+
*/
|
|
37
|
+
queue = [];
|
|
23
38
|
constructor(url,
|
|
24
39
|
/**
|
|
25
40
|
* A GETTER, read per attempt. The access token lives ~15 minutes and
|
|
@@ -44,6 +59,7 @@ export class RealtimeSocket {
|
|
|
44
59
|
const ws = this.factory(this.url);
|
|
45
60
|
this.ws = ws;
|
|
46
61
|
this.attempt += 1;
|
|
62
|
+
this.ready = false;
|
|
47
63
|
ws.onopen = () => {
|
|
48
64
|
// Auth is the FIRST message, never a header (a browser cannot set one on a
|
|
49
65
|
// WebSocket) and never a query parameter (a token in a URL lands in logs).
|
|
@@ -92,10 +108,17 @@ export class RealtimeSocket {
|
|
|
92
108
|
catch {
|
|
93
109
|
return; // a malformed frame must never throw into the socket
|
|
94
110
|
}
|
|
111
|
+
// Ready BEFORE the handlers, flushed AFTER them: the page announcement
|
|
112
|
+
// the welcome triggers goes out directly, ahead of the ops held for it.
|
|
113
|
+
const held = this.ready ? [] : this.queue.splice(0);
|
|
114
|
+
this.ready = true;
|
|
95
115
|
for (const h of this.handlers)
|
|
96
116
|
h(parsed);
|
|
117
|
+
for (const f of held)
|
|
118
|
+
ws.send(f);
|
|
97
119
|
};
|
|
98
120
|
ws.onclose = () => {
|
|
121
|
+
this.ready = false;
|
|
99
122
|
if (this.closed)
|
|
100
123
|
return;
|
|
101
124
|
const wait = Math.min(RETRY_BASE_MS * 2 ** this.attempt, RETRY_MAX_MS);
|
|
@@ -109,12 +132,21 @@ export class RealtimeSocket {
|
|
|
109
132
|
send(e) {
|
|
110
133
|
if (this.closed)
|
|
111
134
|
return;
|
|
112
|
-
|
|
135
|
+
const frame = JSON.stringify(e);
|
|
136
|
+
if (this.ready && this.ws?.readyState === OPEN) {
|
|
137
|
+
this.ws.send(frame);
|
|
113
138
|
return;
|
|
114
|
-
|
|
139
|
+
}
|
|
140
|
+
if (this.queue.length >= QUEUE_MAX) {
|
|
141
|
+
// ponytail: drops the oldest past the cap; the peer re-pulls on the gap.
|
|
142
|
+
console.error('[sbuilder-mcp] live queue full, dropping the oldest frame');
|
|
143
|
+
this.queue.shift();
|
|
144
|
+
}
|
|
145
|
+
this.queue.push(frame);
|
|
115
146
|
}
|
|
116
147
|
close() {
|
|
117
148
|
this.closed = true;
|
|
149
|
+
this.queue = [];
|
|
118
150
|
if (this.timer)
|
|
119
151
|
clearTimeout(this.timer);
|
|
120
152
|
this.ws?.close();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sbuilder-mcp",
|
|
3
|
-
"version": "0.63.
|
|
3
|
+
"version": "0.63.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",
|