(ws: WebSocket, raw: unknown, isBinary: boolean)
| 495 | } |
| 496 | |
| 497 | private onWsMessage(ws: WebSocket, raw: unknown, isBinary: boolean): void { |
| 498 | if (this.disposed) return; |
| 499 | if (this.ws !== ws) return; // stale (this ws was kicked) |
| 500 | |
| 501 | if (isBinary) { |
| 502 | const buf = toBuffer(raw); |
| 503 | if (!buf) return; |
| 504 | try { |
| 505 | // Browser stdin arrives as UTF-8 bytes. Keep this edge byte-faithful: |
| 506 | // converting through string corrupts arbitrary terminal sequences and |
| 507 | // makes CJK/IME behavior depend on JS decoding instead of the PTY. |
| 508 | this.term.write(buf as unknown as string); |
| 509 | } catch (err) { |
| 510 | this.log.warn('session.write_error', { err }); |
| 511 | } |
| 512 | return; |
| 513 | } |
| 514 | |
| 515 | const buf = toBuffer(raw); |
| 516 | if (!buf) return; |
| 517 | let parsed: unknown; |
| 518 | try { |
| 519 | parsed = JSON.parse(buf.toString('utf8')); |
| 520 | } catch { |
| 521 | return; |
| 522 | } |
| 523 | if (!isClientControlMessage(parsed)) return; |
| 524 | |
| 525 | if (parsed.type === 'resize') { |
| 526 | this.resize(parsed.cols, parsed.rows); |
| 527 | } |
| 528 | // `attach` mid-stream is ignored — the initial attach already happened. |
| 529 | } |
| 530 | |
| 531 | private wireWs(ws: WebSocket): void { |
| 532 | const messageHandler = (raw: unknown, isBinary: boolean): void => |
no test coverage detected