jupyterhub
v1.0.5
Published
A comprehensive TypeScript SDK for JupyterHub - manage users, servers, files, kernels, and execute notebooks
Maintainers
Readme
JupyterHub SDK
A comprehensive TypeScript SDK for JupyterHub - manage users, servers, files, kernels, terminals, and execute notebooks programmatically.
Installation
pnpm add jupyterhub
# or
npm install jupyterhub
# or
yarn add jupyterhubRequirements
- Node.js >= 18.0.0
- A running JupyterHub instance
- An API token with appropriate permissions
Quick Start
import { JupyterHubClient } from "jupyterhub";
const client = new JupyterHubClient({
baseUrl: "https://jupyterhub.example.com",
token: "your-api-token",
});
// List users
const users = await client.hub.users.list();
// Start a server
await client.hub.servers.start("username");
// Work with files
const server = client.server("username");
const files = await server.contents.list("/");
await server.contents.writeFile("/hello.txt", "Hello World!");
// Execute code in a kernel
const result = await server.executeCode('print("Hello!")', "python3");
// Run shell commands in a terminal
const cmdResult = await server.runCommand("ls -la");
// Run a notebook
const output = await server.runNotebook("/analysis.ipynb");Configuration Options
const client = new JupyterHubClient({
// Required
baseUrl: "https://jupyterhub.example.com",
token: "your-api-token",
// Optional
timeout: 30000, // Request timeout in ms (default: 30000)
retries: 3, // Number of retry attempts (default: 3)
rejectUnauthorized: false, // Set to false for self-signed certificates (default: false)
});Features
Hub API
Manage JupyterHub resources at the hub level.
Users
// List all users
const users = await client.hub.users.list();
// List users with pagination
const pagedUsers = await client.hub.users.list({ offset: 0, limit: 50 });
// Get a specific user
const user = await client.hub.users.get("username");
// Create a new user
await client.hub.users.create({ name: "newuser", admin: false });
// Create multiple users
await client.hub.users.createMany(["user1", "user2", "user3"]);
// Modify a user
await client.hub.users.modify("username", { admin: true });
// Delete a user
await client.hub.users.delete("username");
// Get current user (based on token)
const me = await client.hub.users.me();
// Get user activity
const activity = await client.hub.users.getActivity("username");Groups
// List all groups
const groups = await client.hub.groups.list();
// Get a specific group
const group = await client.hub.groups.get("data-scientists");
// Create a group
await client.hub.groups.create({ name: "data-scientists" });
// Add users to a group
await client.hub.groups.addUsers("data-scientists", ["alice", "bob"]);
// Remove a user from a group
await client.hub.groups.removeUser("data-scientists", "alice");
// Set group properties
await client.hub.groups.setProperties("data-scientists", {
description: "Data science team",
});
// Delete a group
await client.hub.groups.delete("data-scientists");Servers
// Start a user's default server
await client.hub.servers.start("username");
// Start with options
await client.hub.servers.start("username", {
user_options: { profile: "gpu" },
});
// Start a named server
await client.hub.servers.startNamed("username", "gpu-server");
// Wait for server to be ready
await client.hub.servers.waitForReady("username");
await client.hub.servers.waitForReady("username", "named-server", {
timeout: 120000,
pollInterval: 1000,
});
// Check if server is ready
const ready = await client.hub.servers.isReady("username");
// Get server status
const status = await client.hub.servers.getStatus("username");
// Stop a server
await client.hub.servers.stop("username");
// Stop a named server
await client.hub.servers.stopNamed("username", "gpu-server");
// Start and wait helper
const server = await client.startServerAndWait("username", {
serverName: "my-server",
userOptions: { profile: "large" },
timeout: 120000,
});Tokens
// List tokens for a user
const tokens = await client.hub.tokens.list("username");
// Create a new token
const token = await client.hub.tokens.create("username", {
note: "API access",
expires_in: 3600, // seconds
scopes: ["read:users", "servers"],
});
// Get token info
const tokenInfo = await client.hub.tokens.get("username", "token-id");
// Revoke a token
await client.hub.tokens.revoke("username", "token-id");Services
// List all services
const services = await client.hub.services.list();
// Get a specific service
const service = await client.hub.services.get("service-name");Proxy Routes
// List all proxy routes
const routes = await client.hub.proxy.list();
// Add a route
await client.hub.proxy.add("/custom-path", {
target: "http://localhost:8080",
});
// Remove a route
await client.hub.proxy.remove("/custom-path");Hub Information
// Get hub version
const version = await client.getVersion();
// Get hub info
const info = await client.hub.getInfo();Server API
Work with a user's running Jupyter server.
Contents (Files & Directories)
const server = client.server("username");
// List directory contents
const files = await server.contents.list("/");
// List with options
const items = await server.contents.list("/", { type: "notebook" });
// Check if file exists
const exists = await server.contents.exists("/notebook.ipynb");
// Read a text file
const content = await server.contents.read("/script.py");
// Read a notebook
const notebook = await server.contents.readNotebook("/analysis.ipynb");
// Get file info without content
const info = await server.contents.getInfo("/large-file.csv");
// Write a text file
await server.contents.writeFile("/data.txt", "Hello World");
// Write a notebook
await server.contents.writeNotebook("/new.ipynb", notebookContent);
// Create a directory
await server.contents.createDirectory("/new-folder");
// Create nested directories
await server.contents.createDirectory("/path/to/nested/folder");
// Rename/move a file
await server.contents.rename("/old-name.txt", "/new-name.txt");
// Copy a file
await server.contents.copy("/source.txt", "/destination-folder");
// Delete a file or directory
await server.contents.delete("/file-to-delete.txt");
// Upload binary data
const data = new Uint8Array([...]);
await server.contents.upload("/image.png", data);
// Download a file as binary
const binary = await server.contents.download("/image.png");
// Create/update checkpoints
const checkpoint = await server.contents.createCheckpoint("/notebook.ipynb");
const checkpoints = await server.contents.listCheckpoints("/notebook.ipynb");
await server.contents.restoreCheckpoint("/notebook.ipynb", checkpoint.id);
await server.contents.deleteCheckpoint("/notebook.ipynb", checkpoint.id);Kernels
Manage and interact with Jupyter kernels.
Kernel Management
const server = client.server("username");
// List running kernels
const kernels = await server.kernels.list();
// Start a new kernel
const kernel = await server.kernels.start({ name: "python3" });
// Start with path context
const kernel = await server.kernels.start({
name: "python3",
path: "/notebooks",
});
// Get kernel info
const kernelInfo = await server.kernels.get(kernel.id);
// Wait for kernel to be ready
await server.kernels.waitForReady(kernel.id, {
timeout: 30000,
pollInterval: 500,
});
// Check if kernel is ready
const ready = await server.kernels.isReady(kernel.id);
// Restart a kernel
await server.kernels.restart(kernel.id);
// Interrupt a kernel
await server.kernels.interrupt(kernel.id);
// Shutdown a kernel
await server.kernels.shutdown(kernel.id);
// Shutdown all kernels
await server.kernels.shutdownAll();Kernel Connection (WebSocket)
const server = client.server("username");
// Get or create a kernel with connection
const { kernel, connection, created } = await server.getOrCreateKernel("python3");
// Connect to the kernel
await connection.connect();
// Execute code
const result = await connection.execute('print("Hello World")');
console.log(result.outputs);
// Execute with options
const result = await connection.execute("import time; time.sleep(2)", {
timeout: 10000,
silent: false,
storeHistory: true,
stopOnError: true,
});
// Get code completions
const completions = await connection.complete("prin", 4);
console.log(completions.matches); // ['print']
// Get documentation/inspection
const docs = await connection.inspect("print", 5, 1);
console.log(docs.data);
// Get kernel info
const kernelInfo = await connection.kernelInfo();
// Listen for events
const unsubscribe = connection.on((event) => {
switch (event.type) {
case "connected":
console.log("Connected to kernel");
break;
case "disconnected":
console.log("Disconnected:", event.reason);
break;
case "status":
console.log("Kernel status:", event.state);
break;
case "message":
console.log("Message:", event.message);
break;
case "error":
console.error("Error:", event.error);
break;
}
});
// Check connection status
console.log("Connected:", connection.isConnected);
console.log("Execution state:", connection.executionState);
// Disconnect when done
connection.disconnect();
// Clean up
await server.kernels.shutdown(kernel.id);Direct Kernel Connection
import { createKernelConnection } from "jupyterhub";
// Create connection manually
const connection = createKernelConnection({
url: "wss://jupyterhub.example.com/user/alice/api/kernels/kernel-id/channels",
token: "your-token",
timeout: 30000,
rejectUnauthorized: false,
});
await connection.connect();
// ... use connection
connection.disconnect();Terminals
Manage and interact with Jupyter terminals for shell access.
Terminal Management
const server = client.server("username");
// List all terminals
const terminals = await server.terminals.list();
// Create a new terminal
const terminal = await server.terminals.create();
// Create with options
const terminal = await server.terminals.create({ cwd: "/home/jovyan" });
// Get terminal info
const info = await server.terminals.get(terminal.name);
// Delete a terminal
await server.terminals.delete(terminal.name);
// Delete all terminals
await server.terminals.deleteAll();
// Get or create a terminal
const { terminal, created } = await server.terminals.getOrCreate();Running Commands (High-Level)
The easiest way to run shell commands:
const server = client.server("username");
// Run a single command (auto-creates/cleans up terminal)
const result = await server.runCommand("ls -la");
console.log(result.output);
console.log(result.completed); // true if command finished
// Run with options
const result = await server.runCommand("python script.py", {
timeout: 60000,
waitForCompletion: true,
promptPattern: /\$\s*$/, // Custom prompt pattern
});
// Run multiple commands in sequence
const results = await server.runCommands(["cd /home/jovyan", "pwd", "ls -la"]);
results.forEach((r, i) => console.log(`Command ${i}:`, r.output));
// Run command in specific terminal (no cleanup)
const result = await server.terminals.executeCommand("echo hello", {
terminalName: "terminal-1",
cleanup: false,
});
// Run multiple commands in specific terminal
const results = await server.terminals.executeCommands(["pip install numpy", "python -c 'import numpy; print(numpy.__version__)'"], {
terminalName: "terminal-1",
timeout: 120000,
});Terminal Connection (WebSocket)
For interactive terminal sessions:
const server = client.server("username");
// Get or create a terminal with connection
const { terminal, connection, created } = await server.getOrCreateTerminal();
// Connect
await connection.connect();
// Send raw input
connection.send("echo hello\r");
// Send a command (auto-appends newline)
connection.sendCommand("ls -la");
// Run command and wait for output
const result = await connection.runCommand("pwd");
console.log(result.output);
// Run with options
const result = await connection.runCommand("python long_script.py", {
timeout: 120000,
waitForCompletion: true,
promptPattern: /\$\s*$/,
});
// Listen for output
const unsubscribe = connection.on((event) => {
switch (event.type) {
case "connected":
console.log("Connected to terminal");
break;
case "output":
console.log("Output:", event.data);
break;
case "disconnected":
console.log("Disconnected");
break;
case "error":
console.error("Error:", event.error);
break;
}
});
// Get accumulated output
console.log(connection.getOutput());
// Clear output buffer
connection.clearOutput();
// Resize terminal
connection.resize(24, 80);
// Check connection status
console.log("Connected:", connection.isConnected);
// Disconnect
connection.disconnect();
// Clean up
if (created) {
await server.terminals.delete(terminal.name);
}Direct Terminal Connection
import { createTerminalConnection } from "jupyterhub";
// Create connection manually
const connection = createTerminalConnection({
url: "wss://jupyterhub.example.com/user/alice/terminals/websocket/1",
token: "your-token",
timeout: 30000,
rejectUnauthorized: false,
});
await connection.connect();
const result = await connection.runCommand("whoami");
console.log(result.output);
connection.disconnect();Sessions
Manage notebook sessions (notebook + kernel associations).
const server = client.server("username");
// List all sessions
const sessions = await server.sessions.list();
// Create a session
const session = await server.sessions.create({
path: "/notebook.ipynb",
name: "notebook.ipynb",
type: "notebook",
kernel: { name: "python3" },
});
// Get a specific session
const session = await server.sessions.get(sessionId);
// Get or create a session for a notebook
const session = await server.sessions.getOrCreate("/notebook.ipynb", "python3");
// Modify a session
await server.sessions.modify(sessionId, {
path: "/new-path.ipynb",
kernel: { name: "python3" },
});
// Delete a session
await server.sessions.delete(sessionId);
// Delete all sessions
await server.sessions.deleteAll();Kernel Specifications
Get information about available kernels.
const server = client.server("username");
// List all available kernels
const specs = await server.kernelspecs.list();
console.log(specs.default); // Default kernel name
console.log(specs.kernelspecs); // All available kernels
// Get the default kernel spec
const defaultSpec = await server.kernelspecs.getDefault();
// Get a specific kernel spec
const pythonSpec = await server.kernelspecs.get("python3");
// Find kernels by language
const pythonKernels = await server.kernelspecs.findByLanguage("python");
const rKernels = await server.kernelspecs.findByLanguage("R");Code Execution
Execute code directly without managing kernels manually.
const server = client.server("username");
// Simple code execution
const result = await server.executeCode('print("Hello World")', "python3");
console.log(result.outputs);
// With timeout
const result = await server.executeCode("import time; time.sleep(5)", "python3", {
timeout: 10000,
});
// Complex execution
const result = await server.executeCode(
`
import pandas as pd
import numpy as np
df = pd.DataFrame({
'a': np.random.randn(100),
'b': np.random.randn(100)
})
print(df.describe())
df.head()
`,
"python3"
);
// Handle outputs
result.outputs.forEach((output) => {
switch (output.output_type) {
case "stream":
console.log(`${output.name}: ${output.text}`);
break;
case "execute_result":
console.log("Result:", output.data);
break;
case "display_data":
console.log("Display:", output.data);
break;
case "error":
console.error(`${output.ename}: ${output.evalue}`);
console.error(output.traceback.join("\n"));
break;
}
});Notebook Execution
Run entire notebooks programmatically.
const server = client.server("username");
// Run a notebook from file
const result = await server.runNotebook("/analysis.ipynb");
// Run with options
const result = await server.runNotebook("/analysis.ipynb", {
kernelName: "python3",
stopOnError: true,
saveOutput: true,
cellTimeout: 300000, // 5 min per cell
notebookTimeout: 3600000, // 1 hour total
onCellComplete: (index, cellResult) => {
console.log(`Cell ${index} completed:`, cellResult.status);
},
});
// Check results
console.log(`Success: ${result.success}`);
console.log(`Execution time: ${result.execution_time}ms`);
console.log(`Cells executed: ${result.cells.length}`);
// Handle errors
if (!result.success && result.error) {
console.error(`Error in cell ${result.error.cell_index}:`);
console.error(`${result.error.error.name}: ${result.error.error.value}`);
}
// Access the executed notebook
const executedNotebook = result.notebook;Create and Run Notebooks Programmatically
// Create a notebook
const notebook = client.createNotebook([
{ type: "markdown", source: "# My Analysis" },
{ type: "code", source: 'print("Hello World")' },
{ type: "code", source: "import pandas as pd\ndf = pd.DataFrame({'a': [1,2,3]})\ndf" },
]);
// Save it
const server = client.server("username");
await server.contents.writeNotebook("/generated.ipynb", notebook);
// Run it
const result = await server.runNotebook("/generated.ipynb", { saveOutput: true });Named Servers
Work with named servers for multi-server setups.
// Start a named server
await client.hub.servers.startNamed("username", "gpu-server", {
user_options: { profile: "gpu" },
});
// Wait for it
await client.hub.servers.waitForReady("username", "gpu-server");
// Get server API for named server
const server = client.namedServer("username", "gpu-server");
// Work with it like any other server
const files = await server.contents.list("/");
await server.executeCode('print("Running on GPU server")', "python3");
// Stop it
await client.hub.servers.stopNamed("username", "gpu-server");Error Handling
The SDK provides typed errors for common scenarios:
import { ApiError, AuthenticationError, ForbiddenError, NotFoundError, TimeoutError, WebSocketError, KernelExecutionError, KernelNotReadyError, ServerNotRunningError, ValidationError } from "jupyterhub";
try {
await client.hub.users.get("nonexistent");
} catch (error) {
if (error instanceof NotFoundError) {
console.log("User not found");
console.log("URL:", error.url);
console.log("Method:", error.method);
} else if (error instanceof AuthenticationError) {
console.log("Invalid or expired token");
} else if (error instanceof ForbiddenError) {
console.log("Insufficient permissions");
} else if (error instanceof TimeoutError) {
console.log("Request timed out after", error.timeout, "ms");
} else if (error instanceof ApiError) {
console.log(`API error: ${error.status} - ${error.message}`);
console.log("Response body:", error.body);
}
}
// Kernel execution errors
try {
const result = await server.executeCode("raise ValueError('test')", "python3");
} catch (error) {
if (error instanceof KernelExecutionError) {
console.log("Error:", error.ename, error.evalue);
console.log("Traceback:", error.traceback.join("\n"));
}
}
// WebSocket errors
try {
await connection.connect();
} catch (error) {
if (error instanceof WebSocketError) {
console.log("WebSocket error:", error.message);
console.log("URL:", error.url);
}
}Advanced Usage
Custom HTTP Client
Access the underlying HTTP client for advanced scenarios:
import { HttpClient } from "jupyterhub";
// Create a custom HTTP client
const http = new HttpClient({
baseUrl: "https://jupyterhub.example.com",
token: "your-token",
timeout: 60000,
retries: 5,
rejectUnauthorized: false,
});
// Make custom requests
const response = await http.get("/hub/api/custom-endpoint");
const result = await http.post("/hub/api/custom", { data: "value" });Self-Signed Certificates
For JupyterHub instances with self-signed certificates:
const client = new JupyterHubClient({
baseUrl: "https://jupyterhub.local",
token: "your-token",
rejectUnauthorized: false, // Disable SSL verification
});Accessing Raw APIs
// Access individual API modules
const { hub } = client;
const server = client.server("username");
// Hub APIs
hub.users; // UsersApi
hub.groups; // GroupsApi
hub.servers; // ServersApi
hub.tokens; // TokensApi
hub.services; // ServicesApi
hub.proxy; // ProxyApi
// Server APIs
server.contents; // ContentsApi
server.kernels; // KernelsApi
server.sessions; // SessionsApi
server.terminals; // TerminalsApi
server.kernelspecs; // KernelspecsApiTypeScript Types
All types are exported for TypeScript users:
import type {
// Client options
JupyterHubClientOptions,
// Hub types
User,
Group,
Token,
Service,
ServerStatus,
// Server types
ContentModel,
Kernel,
Session,
Terminal,
KernelSpec,
NotebookContent,
NotebookCell,
// Execution types
ExecutionResult,
NotebookExecutionResult,
CellOutput,
CommandResult,
// Connection types
KernelConnectionOptions,
TerminalConnectionOptions,
ExecuteOptions,
RunCommandOptions,
} from "jupyterhub";Development
# Clone the repository
git clone https://github.com/pawan-osman/jupyterhub-sdk.git
cd jupyterhub-sdk
# Install dependencies
pnpm install
# Build
pnpm run build
# Type check
pnpm run typecheck
# Run tests
pnpm test
# Development mode (watch)
pnpm run devLicense
MIT
