Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

ターミナル

最終更新 Markdown で表示Agent セットアップ

ターミナル は、サンドボックスの現在のコンテナ内にある対話型 PTY です。全二重のターミナル I/O に使います。ブラウザシェル、リサイズ、割り込み、再接続ができます。

コマンド実行には exec とプロセスハンドルを使います。ターミナルは別のリソース種別です。API リファレンスは Terminals API です。

プロセスとターミナル

プロセス(exec ターミナル
役割 監視付きの argv プロセス 対話型 PTY
入力 起動時の argv(およびプログラムが独自に読む入力) write() またはブラウザの connect() による PTY 入力
出力 logs()output()、待機 output()、スナップショット、waitForExit()
停止 kill(signal?) interrupt() / terminate()
参照 getProcess / listProcesses getTerminal / listTerminals

どちらのリソースも、サンドボックス ID の現在のコンテナ内にだけ存在します。参照メソッドはコンテナを起動しません。Sandbox のライフサイクルプロセスの生存期間 を参照してください。

ターミナルを作成する

const terminal = await sandbox.createTerminal({
	command: ["bash"],
	cwd: "/workspace",
	cols: 120,
	rows: 40,
});

console.log(terminal.id);
const terminal = await sandbox.createTerminal({
	command: ["bash"],
	cwd: "/workspace",
	cols: 120,
	rows: 40,
});

console.log(terminal.id);

Worker から PTY へ書き込み、リサイズ、出力のストリーム、終了ができます。

await terminal.write(new TextEncoder().encode("uname -a\n"));
await terminal.resize(100, 30);
await terminal.terminate();
await terminal.write(new TextEncoder().encode("uname -a\n"));
await terminal.resize(100, 30);
await terminal.terminate();

生存期間

  • ターミナルは、そのサンドボックス ID の 現在のコンテナ 内にだけ存在します。
  • コンテナが動いていないとき、getTerminal / listTerminalsnull / [] を返します。コンテナは起動しません。
  • コンテナが停止または置き換わると、古いターミナル ID は無効になります。再度必要なら、新しいターミナルを作成します。
  • アクティブなプロセスと同様に、アクティブなターミナルは Worker リクエストをまたいでコンテナを生かし続けられます。

そのコンテナが稼働しているあいだ、同じ PTY を再開するには terminal.id を保存します。

ブラウザ接続

  1. ターミナルを作成し、サンドボックス ID と一緒に terminal.id を保持します。
  2. WebSocket のアップグレードごとに、getTerminal でターミナルを解決し、terminal.connect(request) を返します。
  3. ブラウザでは、@cloudflare/sandbox/xtermterminalId 付きで使います。

Worker

import { getSandbox } from "@cloudflare/sandbox";

export { Sandbox } from "@cloudflare/sandbox";

export default {
	async fetch(request, env) {
		const url = new URL(request.url);

		if (
			url.pathname === "/ws/terminal" &&
			request.headers.get("Upgrade")?.toLowerCase() === "websocket"
		) {
			const sandboxId = url.searchParams.get("sandboxId");
			const terminalId = url.searchParams.get("terminalId");
			if (!sandboxId || !terminalId) {
				return new Response("sandboxId and terminalId are required", {
					status: 400,
				});
			}

			const sandbox = getSandbox(env.Sandbox, sandboxId);
			const terminal = await sandbox.getTerminal(terminalId);
			if (!terminal) {
				return new Response("Terminal not found", { status: 404 });
			}

			return terminal.connect(request, {
				cursor: url.searchParams.get("cursor") ?? undefined,
			});
		}

		return new Response("Not found", { status: 404 });
	},
};
import { getSandbox } from "@cloudflare/sandbox";

export { Sandbox } from "@cloudflare/sandbox";

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		const url = new URL(request.url);

		if (
			url.pathname === "/ws/terminal" &&
			request.headers.get("Upgrade")?.toLowerCase() === "websocket"
		) {
			const sandboxId = url.searchParams.get("sandboxId");
			const terminalId = url.searchParams.get("terminalId");
			if (!sandboxId || !terminalId) {
				return new Response("sandboxId and terminalId are required", {
					status: 400,
				});
			}

			const sandbox = getSandbox(env.Sandbox, sandboxId);
			const terminal = await sandbox.getTerminal(terminalId);
			if (!terminal) {
				return new Response("Terminal not found", { status: 404 });
			}

			return terminal.connect(request, {
				cursor: url.searchParams.get("cursor") ?? undefined,
			});
		}

		return new Response("Not found", { status: 404 });
	},
};

UI がターミナルを必要とするときに、アプリケーションのルートから作成します。

const sandboxId = "user-123";
const sandbox = getSandbox(env.Sandbox, sandboxId);
const terminal = await sandbox.createTerminal({ command: ["bash"] });
return Response.json({ sandboxId, terminalId: terminal.id });
const sandboxId = "user-123";
const sandbox = getSandbox(env.Sandbox, sandboxId);
const terminal = await sandbox.createTerminal({ command: ["bash"] });
return Response.json({ sandboxId, terminalId: terminal.id });

ブラウザ(xterm.js)

npm install @xterm/xterm @xterm/addon-fit @cloudflare/sandbox@next
import { Terminal } from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit";
import { SandboxAddon } from "@cloudflare/sandbox/xterm";
import "@xterm/xterm/css/xterm.css";

const term = new Terminal({ cursorBlink: true });
const fitAddon = new FitAddon();
const sandboxAddon = new SandboxAddon({
	// `origin` is already a WebSocket origin (`wss://` or `ws://`).
	getWebSocketUrl: ({ sandboxId, terminalId, cursor, origin }) => {
		const params = new URLSearchParams({ sandboxId });
		if (terminalId) params.set("terminalId", terminalId);
		if (cursor) params.set("cursor", cursor);
		return `${origin}/ws/terminal?${params}`;
	},
	reconnect: true,
});

term.loadAddon(fitAddon);
term.loadAddon(sandboxAddon);
term.open(document.getElementById("terminal"));
fitAddon.fit();

// Values returned by your create-terminal route
const sandboxId = "user-123";
const terminalId = "term_...";
sandboxAddon.connect({ sandboxId, terminalId });
import { Terminal } from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit";
import { SandboxAddon } from "@cloudflare/sandbox/xterm";
import "@xterm/xterm/css/xterm.css";

const term = new Terminal({ cursorBlink: true });
const fitAddon = new FitAddon();
const sandboxAddon = new SandboxAddon({
	// `origin` is already a WebSocket origin (`wss://` or `ws://`).
	getWebSocketUrl: ({ sandboxId, terminalId, cursor, origin }) => {
		const params = new URLSearchParams({ sandboxId });
		if (terminalId) params.set("terminalId", terminalId);
		if (cursor) params.set("cursor", cursor);
		return `${origin}/ws/terminal?${params}`;
	},
	reconnect: true,
});

term.loadAddon(fitAddon);
term.loadAddon(sandboxAddon);
term.open(document.getElementById("terminal")!);
fitAddon.fit();

// Values returned by your create-terminal route
const sandboxId = "user-123";
const terminalId = "term_...";
sandboxAddon.connect({ sandboxId, terminalId });
安定版パッケージ プレビュー
sandbox.terminal(request) createTerminal + getTerminal + connect
xterm / URL の sessionId terminalId(任意の cursor

関連情報

役に立ちましたか?