deckide 3.5.25 → 3.5.27
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/dist/utils/utf8.js
CHANGED
|
@@ -54,54 +54,106 @@ export function alignToUtf8End(buf, offset) {
|
|
|
54
54
|
return pos;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
* Skip past a partial ANSI
|
|
57
|
+
* Skip past a partial ANSI escape sequence at the start of a buffer.
|
|
58
58
|
*
|
|
59
59
|
* When a terminal buffer is trimmed from the front, the cut point may land
|
|
60
|
-
* inside
|
|
61
|
-
* discarded, leaving orphaned
|
|
60
|
+
* inside an escape sequence. The leading ESC byte (and possibly the type
|
|
61
|
+
* indicator) is discarded, leaving orphaned payload bytes that xterm.js
|
|
62
62
|
* would render as literal text, shifting all subsequent cursor positions.
|
|
63
63
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
64
|
+
* Handled sequence types:
|
|
65
|
+
*
|
|
66
|
+
* CSI (ESC [) — e.g. "\x1b[38;2;100;50m"
|
|
67
|
+
* Detected as: '[' + params/intermediates + final byte
|
|
68
|
+
* or: bare params with ';' + final byte (ESC and '[' both trimmed)
|
|
69
|
+
*
|
|
70
|
+
* OSC (ESC ]) — e.g. "\x1b]0;title\x07"
|
|
71
|
+
* Detected as: ']' + text + BEL/ST terminator
|
|
72
|
+
*
|
|
73
|
+
* DCS (ESC P) — e.g. "\x1bP1$r...\x1b\\"
|
|
74
|
+
* Detected as: 'P' + text + ST terminator
|
|
75
|
+
*
|
|
76
|
+
* APC (ESC _) — e.g. "\x1b_...\x1b\\"
|
|
77
|
+
* Detected as: '_' + text + ST terminator
|
|
70
78
|
*
|
|
71
79
|
* Returns the number of bytes to skip (0 if no partial sequence detected).
|
|
72
80
|
*/
|
|
73
81
|
export function skipPartialEscapeSequence(buf, offset) {
|
|
74
82
|
if (offset >= buf.length)
|
|
75
83
|
return 0;
|
|
84
|
+
const b = buf[offset];
|
|
85
|
+
// ── CSI: starts with '[' (ESC was trimmed) ──
|
|
86
|
+
if (b === 0x5B /* '[' */) {
|
|
87
|
+
return skipPartialCSI(buf, offset);
|
|
88
|
+
}
|
|
89
|
+
// ── OSC: starts with ']' (ESC was trimmed) ──
|
|
90
|
+
if (b === 0x5D /* ']' */) {
|
|
91
|
+
return skipStringSequence(buf, offset);
|
|
92
|
+
}
|
|
93
|
+
// ── DCS: starts with 'P' (ESC was trimmed) ──
|
|
94
|
+
// Only treat as DCS if followed by a parameter byte, '$', or printable
|
|
95
|
+
// control sequence byte — avoids false positive on words like "Path".
|
|
96
|
+
if (b === 0x50 /* 'P' */ && offset + 1 < buf.length) {
|
|
97
|
+
const next = buf[offset + 1];
|
|
98
|
+
if ((next >= 0x30 && next <= 0x3F) || next === 0x24 /* '$' */) {
|
|
99
|
+
return skipStringSequence(buf, offset);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ── APC: starts with '_' (ESC was trimmed) ──
|
|
103
|
+
if (b === 0x5F /* '_' */) {
|
|
104
|
+
return skipStringSequence(buf, offset);
|
|
105
|
+
}
|
|
106
|
+
// ── Bare CSI params (both ESC and '[' trimmed) ──
|
|
107
|
+
if (b >= 0x30 && b <= 0x3F) {
|
|
108
|
+
return skipBareCSIParams(buf, offset);
|
|
109
|
+
}
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Skip a partial CSI sequence starting with '['.
|
|
114
|
+
* Pattern: '[' params intermediates final
|
|
115
|
+
*/
|
|
116
|
+
function skipPartialCSI(buf, offset) {
|
|
76
117
|
const limit = Math.min(buf.length, offset + 128);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// CSI final byte — skip it and we're done
|
|
93
|
-
return (pos + 1) - offset;
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
return 0;
|
|
118
|
+
if (offset + 1 >= limit)
|
|
119
|
+
return 0;
|
|
120
|
+
const next = buf[offset + 1];
|
|
121
|
+
// Only treat as CSI if the next byte is a parameter (0x30-0x3F) or
|
|
122
|
+
// intermediate (0x20-0x2F) — avoids false positives like "[user@host"
|
|
123
|
+
if (next < 0x20 || (next > 0x3F && next < 0x40))
|
|
124
|
+
return 0;
|
|
125
|
+
// If next is already a final byte (letter), it could be "[H" (cursor home)
|
|
126
|
+
// or "[hello" — skip only the 2-byte "[H" style if the byte after final
|
|
127
|
+
// is a control char or ESC (strong signal it was a real sequence).
|
|
128
|
+
if (next >= 0x40 && next <= 0x7E) {
|
|
129
|
+
if (offset + 2 < buf.length) {
|
|
130
|
+
const after = buf[offset + 2];
|
|
131
|
+
if (after === 0x1B || after < 0x20)
|
|
132
|
+
return 2;
|
|
98
133
|
}
|
|
99
134
|
return 0;
|
|
100
135
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
136
|
+
let pos = offset + 1;
|
|
137
|
+
while (pos < limit) {
|
|
138
|
+
const c = buf[pos];
|
|
139
|
+
if ((c >= 0x30 && c <= 0x3F) || (c >= 0x20 && c <= 0x2F)) {
|
|
140
|
+
pos++;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (c >= 0x40 && c <= 0x7E) {
|
|
144
|
+
return (pos + 1) - offset;
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Skip bare CSI parameter bytes (both ESC and '[' were trimmed).
|
|
152
|
+
* Pattern: digits/';' (with at least one ';') + final byte
|
|
153
|
+
*/
|
|
154
|
+
function skipBareCSIParams(buf, offset) {
|
|
155
|
+
const limit = Math.min(buf.length, offset + 128);
|
|
156
|
+
let pos = offset;
|
|
105
157
|
let hasSemicolon = false;
|
|
106
158
|
while (pos < limit) {
|
|
107
159
|
const c = buf[pos];
|
|
@@ -114,8 +166,7 @@ export function skipPartialEscapeSequence(buf, offset) {
|
|
|
114
166
|
pos++;
|
|
115
167
|
}
|
|
116
168
|
else if (c >= 0x40 && c <= 0x7E) {
|
|
117
|
-
//
|
|
118
|
-
// (avoids false positives like "5m" at the start of normal text)
|
|
169
|
+
// Only skip if we saw ';' — avoids false positives like "5m"
|
|
119
170
|
return hasSemicolon ? (pos + 1) - offset : 0;
|
|
120
171
|
}
|
|
121
172
|
else {
|
|
@@ -124,3 +175,35 @@ export function skipPartialEscapeSequence(buf, offset) {
|
|
|
124
175
|
}
|
|
125
176
|
return 0;
|
|
126
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Skip a string-type escape sequence (OSC / DCS / APC) that starts with
|
|
180
|
+
* the type indicator byte (']', 'P', or '_') — the leading ESC was trimmed.
|
|
181
|
+
*
|
|
182
|
+
* These sequences are terminated by:
|
|
183
|
+
* - BEL (0x07) — common for OSC
|
|
184
|
+
* - ST (ESC \ = 0x1B 0x5C) — standard for all
|
|
185
|
+
*
|
|
186
|
+
* We scan up to 4 KB for the terminator; if not found we skip nothing
|
|
187
|
+
* (the partial sequence might span far beyond what we want to discard).
|
|
188
|
+
*/
|
|
189
|
+
function skipStringSequence(buf, offset) {
|
|
190
|
+
const limit = Math.min(buf.length, offset + 4096);
|
|
191
|
+
let pos = offset + 1; // skip the type indicator byte
|
|
192
|
+
while (pos < limit) {
|
|
193
|
+
const c = buf[pos];
|
|
194
|
+
if (c === 0x07) {
|
|
195
|
+
// BEL terminator
|
|
196
|
+
return (pos + 1) - offset;
|
|
197
|
+
}
|
|
198
|
+
if (c === 0x1B && pos + 1 < buf.length && buf[pos + 1] === 0x5C) {
|
|
199
|
+
// ST terminator (ESC \)
|
|
200
|
+
return (pos + 2) - offset;
|
|
201
|
+
}
|
|
202
|
+
// If we hit another ESC that's NOT followed by '\', it's a new sequence
|
|
203
|
+
if (c === 0x1B) {
|
|
204
|
+
return pos - offset;
|
|
205
|
+
}
|
|
206
|
+
pos++;
|
|
207
|
+
}
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
package/dist/websocket.js
CHANGED
|
@@ -149,11 +149,11 @@ function readBufferedRange(session, startOffset, endOffset) {
|
|
|
149
149
|
if (relativeEnd <= relativeStart || session.bufferChunks.length === 0) {
|
|
150
150
|
return Buffer.alloc(0);
|
|
151
151
|
}
|
|
152
|
-
// Materialize the raw range
|
|
153
|
-
//
|
|
152
|
+
// Materialize the raw range into a contiguous copy so the caller
|
|
153
|
+
// is not affected if buffer chunks are later trimmed or reassigned.
|
|
154
154
|
let raw;
|
|
155
155
|
if (session.bufferChunks.length === 1) {
|
|
156
|
-
raw = session.bufferChunks[0].subarray(relativeStart, relativeEnd);
|
|
156
|
+
raw = Buffer.from(session.bufferChunks[0].subarray(relativeStart, relativeEnd));
|
|
157
157
|
}
|
|
158
158
|
else {
|
|
159
159
|
const slices = [];
|
|
@@ -172,7 +172,7 @@ function readBufferedRange(session, startOffset, endOffset) {
|
|
|
172
172
|
const endInChunk = Math.min(chunk.length, relativeEnd - chunkStart);
|
|
173
173
|
slices.push(chunk.subarray(startInChunk, endInChunk));
|
|
174
174
|
}
|
|
175
|
-
raw = slices
|
|
175
|
+
raw = Buffer.concat(slices); // concat always creates a new Buffer
|
|
176
176
|
}
|
|
177
177
|
// Align start: skip orphaned continuation bytes
|
|
178
178
|
const alignedStart = alignToUtf8Start(raw, 0);
|
|
@@ -181,7 +181,7 @@ function readBufferedRange(session, startOffset, endOffset) {
|
|
|
181
181
|
if (alignedStart === 0 && alignedEnd === raw.length) {
|
|
182
182
|
return raw;
|
|
183
183
|
}
|
|
184
|
-
return raw.subarray(alignedStart, alignedEnd);
|
|
184
|
+
return Buffer.from(raw.subarray(alignedStart, alignedEnd));
|
|
185
185
|
}
|
|
186
186
|
export function setupWebSocketServer(server, terminals) {
|
|
187
187
|
const wss = new WebSocketServer({ server, maxPayload: MAX_MESSAGE_SIZE });
|