Repository navigation
API Development
Architecture guide, API reference, and contribution guidelines for developers.
HetznerCloudToolkit/
├── src/
│ ├── extension.ts # Entry point - activate/deactivate
│ ├── api/
│ │ └── hetzner.ts # Hetzner Cloud REST API client
│ ├── commands/
│ │ ├── manageTokens.ts # Token CRUD operations
│ │ ├── serverCommands.ts # Server create/power/delete
│ │ ├── networkCommands.ts # Network CRUD
│ │ ├── sshKeyCommands.ts # SSH key CRUD
│ │ ├── firewallCommands.ts # Firewall & rules CRUD
│ │ └── volumeCommands.ts # Volume operations
│ ├── providers/
│ │ ├── setupProvider.ts # SETUP tree view (onboarding)
│ │ ├── projectsProvider.ts # PROJECTS selector
│ │ ├── serversProvider.ts # SERVERS tree + polling
│ │ ├── networksProvider.ts # NETWORKS tree
│ │ ├── imagesProvider.ts # IMAGES tree
│ │ ├── sshKeysProvider.ts # SSH KEYS tree
│ │ ├── firewallsProvider.ts # FIREWALLS tree
│ │ └── volumesProvider.ts # VOLUMES tree
│ ├── utils/
│ │ └── secretStorage.ts # TokenManager, CloudInitLibrary
│ └── webviews/
│ ├── serverWizard.ts # 7-step server creation WebView
│ ├── serverDetail.ts # Server detail panel
│ ├── sshKeyGuide.ts # SSH key generation guide
│ └── welcomePage.ts # Welcome/overview panel
├── resources/
│ └── icon.png # Extension marketplace icon
├── package.json # Extension metadata
├── tsconfig.json # TypeScript config
└── esbuild.js # Build configuration
Responsibilities:
- Activate extension on first use
- Register all commands
- Initialize all TreeView providers
- Set up webviews
- Handle deactivation cleanup
Key Functions:
export async function activate(context: vscode.ExtensionContext) {
// Initialize TokenManager with SecretStorage
// Register all commands
// Create tree views
// Start polling for server status
}
export function deactivate() {
// Cleanup: stop polling, clear handlers
}Typed REST client for Hetzner Cloud API v1
class HetznerClient {
constructor(token: string) {};
// Servers
async listServers(): Promise<Server[]>
async getServer(id: number): Promise<Server>
async createServer(opts: CreateServerRequest): Promise<Server>
async powerOnServer(id: number): Promise<void>
async powerOffServer(id: number): Promise<void>
async rebootServer(id: number): Promise<void>
async deleteServer(id: number): Promise<void>
// Networks
async listNetworks(): Promise<Network[]>
async createNetwork(name: string, cidr: string): Promise<Network>
async deleteNetwork(id: number): Promise<void>
// SSH Keys
async listSSHKeys(): Promise<SSHKey[]>
async createSSHKey(name: string, publicKey: string): Promise<SSHKey>
async deleteSSHKey(id: number): Promise<void>
// Images, Locations, ServerTypes, Firewalls, Volumes, etc.
}Features:
- No external dependencies (native
fetch) - Type-safe requests/responses
- Automatic error handling
- Pagination support
Manages Hetzner API tokens securely using VS Code's SecretStorage.
class TokenManager {
async addToken(projectName: string, token: string): Promise<void>
async removeToken(projectName: string): Promise<void>
async listProjects(): Promise<Project[]>
async getActiveProject(): Promise<Project | null>
async setActiveProject(projectName: string): Promise<void>
// Returns HetznerClient or null if no active token
async getActiveClient(): Promise<HetznerClient | null>
}Storage:
- Uses
context.secrets(VS Code's SecretStorage API) - Encrypted by OS (Windows: Credential Manager, macOS: Keychain, Linux: gnome-keyring)
- Tokens never logged or exposed
- CSV index in state (non-sensitive metadata)
File: utils/secretStorage.ts
TreeView providers display resources in the VS Code sidebar.
Base Pattern:
class ServersProvider implements vscode.TreeDataProvider<ServerItem> {
private _onDidChangeTreeData = new vscode.EventEmitter<void>();
onDidChangeTreeData = this._onDidChangeTreeData.event;
async getTreeItem(element: ServerItem): Promise<vscode.TreeItem> {
// Return item with icon, label, collapsible state
}
async getChildren(element?: ServerItem): Promise<ServerItem[]> {
// Return children nodes
}
refresh(): void {
this._onDidChangeTreeData.fire();
}
}Providers:
-
setupProvider.ts— SETUP panel (onboarding tasks) -
projectsProvider.ts— PROJECTS selector (multi-project) -
serversProvider.ts— SERVERS tree (with status polling every 5s) -
networksProvider.ts— NETWORKS tree (subnets as children) -
sshKeysProvider.ts— SSH KEYS tree -
firewallsProvider.ts— FIREWALLS tree (rules as children) -
volumesProvider.ts— VOLUMES tree
Interactive WebViews for complex UIs.
7-step form in a WebView panel:
- Basics — Name, Location
- Server Type — CPU/RAM selection
- OS Image — System or snapshot
- SSH Keys — Authentication
- Network — Private network
- Cloud-Init — Custom scripts
- Review — Confirmation
Communication:
- Extension ↔ WebView via
postMessage() - WebView sends form data, extension validates & creates server
- Polling updates server status in extension
File: webviews/serverWizard.ts
Shows server info and action buttons:
- Status, IPs, specs
- Quick actions (Power On/Off, Reboot, Delete)
- Root password (if no SSH key)
Tabbed WebView with OS-specific SSH key generation instructions:
- Windows (OpenSSH + PuTTY)
- macOS
- Linux
Base URL: https://api.hetzner.cloud/v1
Authentication: Bearer token in Authorization header
Example Request:
const response = await fetch('https://api.hetzner.cloud/v1/servers', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
const data = await response.json();Key Endpoints:
-
GET /servers— List servers -
POST /servers— Create server -
GET /servers/{id}— Get server details -
POST /servers/{id}/actions/power/on— Power on -
POST /servers/{id}/actions/power/off— Power off -
POST /servers/{id}/actions/reboot— Reboot -
DELETE /servers/{id}— Delete server
Official Docs: https://docs.hetzner.cloud/cloud/servers/overview
- Node.js 18+
- VS Code 1.85.0+
- TypeScript
- esbuild (bundler)
git clone https://github.com/brwinnov/vscode-hetzner-cloud.git
cd vscode-hetzner-cloud
npm install# Development build
npm run build
# Watch mode (rebuilds on file changes)
npm run watch- Open project in VS Code
- Press F5 to launch debug extension host
- A new VS Code window opens with extension active
- Set breakpoints in TypeScript files
- Breakpoints pause execution in debug window
Debug Configuration: .vscode/launch.json
# Build VSIX package
npm run build
vsce package
# This creates: vscode-hetzner-cloud-0.1.0.vsix-
Sidebar TreeViews —
vscode.window.createTreeView() -
WebView Panels —
vscode.window.createWebviewPanel() -
Commands —
vscode.commands.registerCommand() -
SecretStorage —
context.secrets.store/get/delete() -
Status Bar —
vscode.window.createStatusBarItem()
Reference: https://code.visualstudio.com/api/references/vscode-api
- Fork repo on GitHub
- Clone your fork locally
- Create feature branch:
git checkout -b feat/my-feature - Install dependencies:
npm install - Run watch mode:
npm run watch - Test in extension host (F5)
- Language: TypeScript
- Linter: ESLint
- Formatter: Prettier
- Indentation: 2 spaces
# Format code
npm run format
# Lint
npm run lint
# Build
npm run build
# Test in extension host (F5)Follow conventional commits:
feat: Add feature X
fix: Fix bug in Y
docs: Update README
refactor: Reorganize module Z
test: Add tests for X
- ✅ Tests pass in extension host (F5)
- ✅ Code formatted with Prettier
- ✅ No ESLint errors
- ✅ Changelog updated (CHANGELOG.md)
- ✅ Clear PR title and description
- Find what changed: Open Source Control in VS Code
- Test with real token: Use a test Hetzner Cloud project
- Check extension logs: Open Extension Host console (F5)
-
Reload extension:
Developer: Reload Window(Ctrl+R) -
Build before testing: Always run
npm run buildfirst
-
Create function in
commands/:// commands/exampleCommand.ts export async function exampleCommand() { const client = await tokenManager.getActiveClient(); // Do something }
-
Register in
extension.ts:const exampleCmd = vscode.commands.registerCommand( 'hcloud.example', () => exampleCommand() ); context.subscriptions.push(exampleCmd);
-
Add to
package.jsoncontributions:{ "command": "hcloud.example", "title": "Hetzner Cloud: Example Command" }
-
Create class implementing
vscode.TreeDataProvider<ItemType> -
Implement
getTreeItem()andgetChildren() -
Create event emitter for
onDidChangeTreeData -
Register in
extension.ts:const provider = new MyProvider(); vscode.window.createTreeView('myView', { treeDataProvider: provider });
-
Add to
package.jsoncontributions:{ "id": "myView", "name": "My View" }
npm run clean
npm install
npm run build- Check Extension Host output (Debug Console)
- Verify
package.jsoncontributions syntax - Reload:
Developer: Reload Window
- SecretStorage only available in VS Code 1.85.0+
- Check
logLevelin.npmrcfor debugging - Verify token manager initialization
- Update version in
package.json - Update
CHANGELOG.md - Create git tag:
git tag v0.1.1 - Push to GitHub:
git push origin main --tags - Build VSIX:
npm run build && vsce package - Create GitHub Release with VSIX attached
- Publish to marketplace (requires publisher account)
- Hetzner Cloud API Docs: https://docs.hetzner.cloud/
- VS Code Extension API: https://code.visualstudio.com/api
- WebView Best Practices: https://code.visualstudio.com/api/extension-guides/webview
- esbuild Docs: https://esbuild.github.io/
- TypeScript Handbook: https://www.typescriptlang.org/docs/
Questions? Open an issue on GitHub: https://github.com/brwinnov/vscode-hetzner-cloud/issues