{"id":31667864,"url":"https://github.com/orshefi/vscode-extension-rest-webview","last_synced_at":"2026-05-14T20:31:11.273Z","repository":{"id":297815695,"uuid":"997844616","full_name":"orshefi/vscode-extension-rest-webview","owner":"orshefi","description":"Wrapper around VSCode events as transport for Webview \u003c-\u003e Extension communication","archived":false,"fork":false,"pushed_at":"2025-06-08T09:33:17.000Z","size":1084,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-04T21:59:59.711Z","etag":null,"topics":["eventbus","http","vscode","vscode-extension","vscode-webview","vscode-webview-extension","webview"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/orshefi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-07T10:03:54.000Z","updated_at":"2025-06-10T10:22:33.000Z","dependencies_parsed_at":"2025-06-07T17:37:36.409Z","dependency_job_id":null,"html_url":"https://github.com/orshefi/vscode-extension-rest-webview","commit_stats":null,"previous_names":["orshefi/vscode-extension-rest-webview"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/orshefi/vscode-extension-rest-webview","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orshefi%2Fvscode-extension-rest-webview","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orshefi%2Fvscode-extension-rest-webview/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orshefi%2Fvscode-extension-rest-webview/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orshefi%2Fvscode-extension-rest-webview/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orshefi","download_url":"https://codeload.github.com/orshefi/vscode-extension-rest-webview/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orshefi%2Fvscode-extension-rest-webview/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33042075,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eventbus","http","vscode","vscode-extension","vscode-webview","vscode-webview-extension","webview"],"created_at":"2025-10-08T00:48:40.826Z","updated_at":"2026-05-14T20:31:11.267Z","avatar_url":"https://github.com/orshefi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VS Code REST Webview\n\nA standalone NPM library that enables HTTP REST-like communication between VS Code extensions and webviews using VS Code's native messaging system as the transport layer.\n\n## ✨ Features\n\n- **Fastify Compatible**: Drop-in replacement using custom transport\n- **Fetch-like Client API**: Familiar HTTP patterns for webviews  \n- **Full HTTP Support**: Methods, headers, status codes, middleware\n- **TypeScript First**: Complete type safety and IntelliSense\n- **Framework Agnostic**: Works with React, Vue, vanilla JS\n- **Development Tools**: Hot reload, configurable logging, debugging\n\n## 🚀 Quick Start\n\n### Extension Side (Server)\n\n```typescript\nimport * as vscode from 'vscode';\nimport { createVSCodeFastify } from '@vscode-rest/server';\n\nexport function activate(context: vscode.ExtensionContext) {\n  const disposable = vscode.commands.registerCommand('myext.openWebview', () =\u003e {\n    // Create webview panel\n    const panel = vscode.window.createWebviewPanel(\n      'myWebview',\n      'My Extension',\n      vscode.ViewColumn.One,\n      { enableScripts: true }\n    );\n\n    // Create Fastify server with VS Code transport\n    const server = createVSCodeFastify({\n      webview: panel.webview,\n      options: {\n        development: { logging: 'debug' }\n      }\n    });\n\n    // Define API routes (standard Fastify!)\n    server.get('/api/hello', async () =\u003e {\n      return { message: 'Hello from extension!' };\n    });\n\n    server.post('/api/data', async (request) =\u003e {\n      const body = request.body;\n      return { received: body, timestamp: new Date() };\n    });\n\n    // Start listening for webview messages\n    server.listen();\n\n    // Set webview content\n    panel.webview.html = getWebviewContent();\n\n    // Cleanup on disposal\n    panel.onDidDispose(() =\u003e server.close());\n  });\n\n  context.subscriptions.push(disposable);\n}\n```\n\n### Webview Side (Client)\n\nFirst, install the client library in your extension project:\n\n```bash\nnpm install @vscode-rest/client\n```\n\n#### Option 1: Using a Build Tool (Recommended)\n\nCreate a webview TypeScript/JavaScript file:\n\n```typescript\n// src/webview/main.ts\nimport { VSCodeHttpClient } from '@vscode-rest/client';\n\nconst vscode = acquireVsCodeApi();\nconst client = new VSCodeHttpClient(vscode);\n\nasync function fetchData() {\n    try {\n        const response = await client.get('/api/hello');\n        const data = await response.json();\n        document.getElementById('result')!.textContent = JSON.stringify(data, null, 2);\n    } catch (error) {\n        console.error('Error:', error);\n        document.getElementById('result')!.textContent = 'Error: ' + (error as Error).message;\n    }\n}\n\nasync function postData() {\n    try {\n        const response = await client.post('/api/data', {\n            message: 'Hello from webview!',\n            timestamp: new Date().toISOString()\n        });\n        const data = await response.json();\n        document.getElementById('result')!.textContent = JSON.stringify(data, null, 2);\n    } catch (error) {\n        console.error('Error:', error);\n        document.getElementById('result')!.textContent = 'Error: ' + (error as Error).message;\n    }\n}\n\n// Make functions globally available\n(globalThis as any).fetchData = fetchData;\n(globalThis as any).postData = postData;\n```\n\nBundle with webpack, rollup, or your preferred bundler. Here's a sample webpack config for the webview:\n\n```javascript\n// webpack.webview.config.js\nconst path = require('path');\n\nmodule.exports = {\n    entry: './src/webview/main.ts',\n    module: {\n        rules: [\n            {\n                test: /\\.tsx?$/,\n                use: 'ts-loader',\n                exclude: /node_modules/,\n            },\n        ],\n    },\n    resolve: {\n        extensions: ['.tsx', '.ts', '.js'],\n    },\n    output: {\n        filename: 'main.js',\n        path: path.resolve(__dirname, 'dist', 'webview'),\n    },\n    mode: 'development',\n    devtool: 'source-map',\n};\n```\n\nThen reference the bundled file:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eMy Extension Webview\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cbutton onclick=\"fetchData()\"\u003eGet Hello\u003c/button\u003e\n    \u003cbutton onclick=\"postData()\"\u003ePost Data\u003c/button\u003e\n    \u003cdiv id=\"result\"\u003e\u003c/div\u003e\n    \n    \u003c!-- Reference your bundled script --\u003e\n    \u003cscript src=\"${scriptUri}\"\u003e\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n#### Option 2: Pre-bundled UMD (No Build Step)\n\nYou can also use a pre-built UMD bundle by copying it to your extension's resources:\n\n```bash\n# Copy the UMD bundle to your extension\ncp node_modules/@vscode-rest/client/dist/index.umd.js src/webview/\n```\n\nThen reference it locally:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eMy Extension Webview\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cbutton onclick=\"fetchData()\"\u003eGet Hello\u003c/button\u003e\n    \u003cbutton onclick=\"postData()\"\u003ePost Data\u003c/button\u003e\n    \u003cdiv id=\"result\"\u003e\u003c/div\u003e\n\n    \u003cscript src=\"${clientScriptUri}\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n        const vscode = acquireVsCodeApi();\n        const client = new VSCodeRest.VSCodeHttpClient(vscode);\n        \n        async function fetchData() {\n            try {\n                const response = await client.get('/api/hello');\n                const data = await response.json();\n                document.getElementById('result').textContent = JSON.stringify(data, null, 2);\n            } catch (error) {\n                console.error('Error:', error);\n                document.getElementById('result').textContent = 'Error: ' + error.message;\n            }\n        }\n        \n        async function postData() {\n            try {\n                const response = await client.post('/api/data', {\n                    message: 'Hello from webview!',\n                    timestamp: new Date().toISOString()\n                });\n                const data = await response.json();\n                document.getElementById('result').textContent = JSON.stringify(data, null, 2);\n            } catch (error) {\n                console.error('Error:', error);\n                document.getElementById('result').textContent = 'Error: ' + error.message;\n            }\n        }\n    \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n#### Extension Code for Serving Scripts\n\nIn your extension, you'll need to serve the script with proper URIs:\n\n```typescript\n// In your extension activation\nfunction getWebviewContent(webview: vscode.Webview, extensionUri: vscode.Uri) {\n    // Option 1: Bundled script\n    const scriptUri = webview.asWebviewUri(\n        vscode.Uri.joinPath(extensionUri, 'dist', 'webview', 'main.js')\n    );\n    \n    // Option 2: UMD script\n    const clientScriptUri = webview.asWebviewUri(\n        vscode.Uri.joinPath(extensionUri, 'src', 'webview', 'index.umd.js')\n    );\n\n    return `\u003c!DOCTYPE html\u003e\n    \u003chtml\u003e\n    \u003chead\u003e\n        \u003ctitle\u003eMy Extension Webview\u003c/title\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n        \u003cbutton onclick=\"fetchData()\"\u003eGet Hello\u003c/button\u003e\n        \u003cbutton onclick=\"postData()\"\u003ePost Data\u003c/button\u003e\n        \u003cdiv id=\"result\"\u003e\u003c/div\u003e\n        \n        \u003cscript src=\"${scriptUri}\"\u003e\u003c/script\u003e\n    \u003c/body\u003e\n    \u003c/html\u003e`;\n}\n\n## 📦 Packages\n\nThis is a monorepo with three main packages:\n\n- **`@vscode-rest/server`**: Extension-side Fastify integration\n- **`@vscode-rest/client`**: Webview-side HTTP client\n- **`@vscode-rest/shared`**: Shared protocol and utilities\n\n## 🏗️ Architecture\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                VS Code Extension Host                        │\n│  ┌─────────────────┐    ┌─────────────────────────────────┐ │\n│  │   Fastify       │    │   VSCodeHttpTransportServer    │ │\n│  │   Server        │────│   - Message routing            │ │\n│  │   - Routes      │    │   - Request correlation        │ │\n│  │   - Middleware  │    │   - Error handling             │ │\n│  └─────────────────┘    └─────────────────────────────────┘ │\n└─────────────────────────────────────────────────────────────┘\n                                  │\n                                  │ postMessage/onDidReceive\n                                  │\n┌─────────────────────────────────────────────────────────────┐\n│                    Webview Process                          │\n│  ┌─────────────────┐    ┌─────────────────────────────────┐ │\n│  │   Web App       │    │   VSCodeHttpClient             │ │\n│  │   - React/Vue   │────│   - HTTP API implementation    │ │\n│  │   - Components  │    │   - Request/Response handling   │ │\n│  └─────────────────┘    └─────────────────────────────────┘ │\n└─────────────────────────────────────────────────────────────┘\n```\n\n## 🧪 Example\n\nA complete working example is available in [`examples/basic-extension/`](examples/basic-extension/).\n\nTo run the example:\n\n1. Open this workspace in VS Code\n2. Navigate to `examples/basic-extension/` \n3. Press F5 to launch the Extension Development Host\n4. In the new window, open Command Palette (Cmd/Ctrl+Shift+P)\n5. Run \"Open REST Webview Example\"\n6. Try the buttons to test the HTTP-like communication!\n\n## 🆔 Multiple Servers \u0026 Instance IDs\n\nWhen creating multiple servers (e.g., in CustomEditorProvider), you need to coordinate instance IDs between client and server to avoid message routing conflicts.\n\n### Problem\nMultiple servers can cause instance ID mismatches where:\n- Request comes from client with one instance ID\n- Response comes back from a different server with a different instance ID\n- Client rejects the response due to ID mismatch\n\n### Solution: Custom Instance IDs\n\n#### Extension Side (Server)\n```typescript\nimport { createVSCodeTransport } from '@vscode-rest/server';\n\nclass MyCustomEditorProvider implements vscode.CustomEditorProvider {\n  async resolveCustomEditor(document: vscode.CustomDocument, webviewPanel: vscode.WebviewPanel) {\n    // Create unique instance ID for this editor\n    const instanceId = `editor_${document.uri.toString()}`;\n    \n    // Create server with custom instance ID\n    const server = createVSCodeTransport({\n      webview: webviewPanel.webview,\n      options: {\n        instanceId: instanceId\n      }\n    });\n    \n    // Pass the instanceId to the webview\n    webviewPanel.webview.html = `\n      \u003c!DOCTYPE html\u003e\n      \u003chtml\u003e\n      \u003chead\u003e\n        \u003cscript\u003e\n          window.SERVER_INSTANCE_ID = '${instanceId}';\n        \u003c/script\u003e\n      \u003c/head\u003e\n      \u003cbody\u003e\n        \u003cscript src=\"client.js\"\u003e\u003c/script\u003e\n      \u003c/body\u003e\n      \u003c/html\u003e\n    `;\n  }\n}\n```\n\n#### Webview Side (Client)\n```typescript\nimport { VSCodeHttpClient } from '@vscode-rest/client';\n\n// Get the instance ID that was passed from the extension\nconst instanceId = (window as any).SERVER_INSTANCE_ID;\n\n// Create client with matching instance ID\nconst client = new VSCodeHttpClient(undefined, {\n  instanceId: instanceId\n});\n\n// Now requests and responses will have matching instance IDs\nconst response = await client.get('/api/data');\n```\n\n#### Multiple Servers Example\n```typescript\n// Extension side - multiple servers for different purposes\nconst apiServer = createVSCodeTransport({\n  webview: panel.webview,\n  options: { instanceId: 'api-server' }\n});\n\nconst fileServer = createVSCodeTransport({\n  webview: panel.webview,\n  options: { instanceId: 'file-server' }\n});\n\n// Webview side - corresponding clients\nconst apiClient = new VSCodeHttpClient(undefined, {\n  instanceId: 'api-server'\n});\n\nconst fileClient = new VSCodeHttpClient(undefined, {\n  instanceId: 'file-server'\n});\n```\n\n### Benefits\n- ✅ No instance ID mismatches\n- ✅ Multiple editors work independently  \n- ✅ Predictable, debuggable instance IDs\n- ✅ Full control over server/client pairing\n- ✅ Backward compatible (auto-generates IDs if not provided)\n\n## 🔧 Development\n\n### Building\n\n```bash\n# Install dependencies\nnpm install\n\n# Build all packages\nnpm run build\n\n# Development mode (watch)\nnpm run dev\n```\n\n### Testing\n\n```bash\n# Run tests\nnpm test\n\n# Watch mode\nnpm run test:watch\n```\n\n## 📋 API Reference\n\n### Server Side\n\n#### `createVSCodeFastify(config)`\n\nCreates a Fastify instance with VS Code transport.\n\n```typescript\ninterface VSCodeTransportConfig {\n  webview: vscode.Webview;\n  options?: {\n    development?: {\n      logging?: 'debug' | 'info' | 'warn' | 'error' | 'none';\n      hotReload?: boolean;\n    };\n    timeout?: number;\n  };\n}\n```\n\n#### `createVSCodeTransport(config)`\n\nCreates just the transport server (for advanced use cases).\n\n### Client Side\n\n#### `new VSCodeHttpClient(vscode?, options?)` or `createVSCodeHttpClient(config?)`\n\nCreates an HTTP client for webview communication.\n\n```typescript\n// Constructor options\ninterface ClientOptions {\n  /** Custom instance ID to match server instance */\n  instanceId?: string;\n  /** Base URL for relative requests */\n  baseUrl?: string;\n}\n\n// Factory function config\ninterface VSCodeClientConfig {\n  /** Base URL for relative requests */\n  baseUrl?: string;\n  /** Custom instance ID to match server instance */\n  instanceId?: string;\n  /** VS Code API instance (optional, will use global if available) */\n  vscode?: any;\n}\n```\n\n#### `VSCodeHttpClient` Methods\n\n- `fetch(url, options?)` - Make HTTP request\n- `get(url, options?)` - GET request\n- `post(url, body?, options?)` - POST request  \n- `put(url, body?, options?)` - PUT request\n- `delete(url, options?)` - DELETE request\n\n## 🎯 Why This Library?\n\n### Before (Manual Messaging)\n\n```typescript\n// Extension side - complex message handling\npanel.webview.onDidReceiveMessage(message =\u003e {\n  if (message.type === 'getData') {\n    const data = getMyData();\n    panel.webview.postMessage({ \n      type: 'dataResponse', \n      id: message.id, \n      data \n    });\n  }\n});\n\n// Webview side - manual correlation\nconst id = Math.random().toString();\nwindow.addEventListener('message', event =\u003e {\n  if (event.data.type === 'dataResponse' \u0026\u0026 event.data.id === id) {\n    handleData(event.data.data);\n  }\n});\nvscode.postMessage({ type: 'getData', id });\n```\n\n### After (HTTP-like)\n\n```typescript\n// Extension side - familiar Fastify patterns\nserver.get('/api/data', async () =\u003e {\n  return getMyData();\n});\n\n// Webview side - familiar fetch patterns using @vscode-rest/client\nimport { VSCodeHttpClient } from '@vscode-rest/client';\n\nconst client = new VSCodeHttpClient();\nconst response = await client.get('/api/data');\nconst data = await response.json();\n```\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests\n5. Submit a pull request\n\n## 📄 License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n---\n\n**Built with ❤️ for the VS Code extension community** ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forshefi%2Fvscode-extension-rest-webview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forshefi%2Fvscode-extension-rest-webview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forshefi%2Fvscode-extension-rest-webview/lists"}