Resizable TTY interface
Draws a colored terminal frame and redraws it when the client window changes size.
Port 30025Auth: none
Connect
Connect with a TTY
ssh -t -p 30025 demo@modernssh-examples.manaf.chTest without a TTY
ssh -T -p 30025 demo@modernssh-examples.manaf.chMinimal server
View complete containerimport { once } from "node:events"
import { Server, SessionChannel, type SessionWindowDimensions } from "@bunkerch/modernssh"
const hostKey = process.env.SSH_HOST_KEY_PRIVATE_KEY
if (!hostKey) throw new Error("SSH_HOST_KEY_PRIVATE_KEY is required")
const esc = "\u001b["
function frame({ columns, rows }: Readonly<SessionWindowDimensions>): string {
if (columns < 36 || rows < 12) return esc + "2J" + esc + "HResize to at least 36 × 12."
const width = Math.min(columns, 72)
const inner = width - 2
const line = (text = "", color = "") => {
const clipped = text.slice(0, inner)
const centered = clipped.padStart(Math.floor((inner + clipped.length) / 2)).padEnd(inner)
return "│" + color + centered + "\u001b[0m│"
}
return esc + "H" + [
"╭" + "─".repeat(inner) + "╮",
line("modernssh TTY", "\u001b[1;35m"),
line(),
line("Resize the window and this frame will follow."),
line(columns + " columns × " + rows + " rows"),
line(),
line("Press q or Ctrl-C to disconnect"),
"╰" + "─".repeat(inner) + "╯",
].join("\r\n") + esc + "J"
}
const server = new Server({ hostKeys: [hostKey] })
server.hooker.hook("noneAuthentication", (_hook, _context, decision) => {
decision.allowLogin = true
})
server.hooker.hook("channelOpenRequest", (_hook, channel, decision) => {
decision.allowOpen = channel instanceof SessionChannel
})
server.on("connection", (connection) => {
connection.on("channel", (channel) => {
if (!(channel instanceof SessionChannel)) return
let dimensions: Readonly<SessionWindowDimensions> | undefined
let shell = channel.shell
channel.hooker.hook("ptyRequest", (_hook, requested, decision) => {
dimensions = requested
decision.success = true
})
channel.hooker.hook("shellRequest", (_hook, decision) => {
decision.success = true
})
channel.hooker.hook("windowChange", async (_hook, resized) => {
dimensions = resized
if (shell) await shell.writeStdout(frame(resized))
})
channel.events.on("shell", (openedShell) => {
shell = openedShell
if (!channel.pty || !dimensions) {
void openedShell.writeStdout("No TTY detected. Reconnect with ssh -t.\n")
.then(() => openedShell.exit(1).close())
return
}
void openedShell.writeStdout(esc + "?1049h" + esc + "?25l" + frame(dimensions))
openedShell.on("data", (data: Buffer) => {
if (!data.includes(0x03) && !data.includes(0x71)) return
void (async () => {
await openedShell.writeStdout(esc + "?25h" + esc + "?1049l")
const closed = once(openedShell, "close")
openedShell.exit(0).close()
await closed
await connection.close()
})()
})
})
})
})
server.listen({ host: "0.0.0.0", port: Number(process.env.PORT ?? 2225) })