import * as vscode from "vscode"; import { devtoolsEvents, sendToDevTools, serverState } from "./server"; type ActorMessage = { type: "actor"; message: unknown }; export function isActorMessage(message: any): message is ActorMessage { return message && message.type === "actor"; } type DevToolsOpenCommandMessage = { type: "vscode:executeCommand"; command: string; arguments?: unknown[]; }; export function isDevToolsExecuteCommandMessage( message: any, ): message is DevToolsOpenCommandMessage { return message && message.type === "vscode:executeCommand"; } type DevToolsOpenExternalMessage = { type: "vscode:openExternal"; uri: string; }; export function isDevToolsOpenExternalMessage( message: any, ): message is DevToolsOpenExternalMessage { return message && message.type === "vscode:openExternal"; } export class DevToolsViewProvider implements vscode.WebviewViewProvider { public static readonly viewType = "vscode-apollo-client-devtools"; constructor(private readonly _extensionUri: vscode.Uri) {} async resolveWebviewView( panel: vscode.WebviewView, context: vscode.WebviewViewResolveContext, token: vscode.CancellationToken, ): Promise { vscode.commands.executeCommand("apollographql/startDevToolsServer"); panel.webview.options = { enableScripts: true, localResourceRoots: [this._extensionUri], }; panel.webview.html = DevToolsViewProvider._getHtmlForWebview( panel.webview, this._extensionUri, ); const panelDisposables: vscode.Disposable[] = []; panel.webview.onDidReceiveMessage( (data) => { if (data.source === "apollo-client-devtools") { devtoolsEvents.emit("fromDevTools", data); } if (data.source === "vscode-panel") { if (data.type === "mounted") { sendToDevTools({ type: "initializePanel", initialContext: { port: serverState?.port || vscode.workspace .getConfiguration("apollographql") .get("devTools.serverPort", 0), listening: !!serverState?.port, }, }); } } }, this, panelDisposables, ); function forwardToDevTools(data: unknown) { panel.webview.postMessage(data); } devtoolsEvents.addListener("toDevTools", forwardToDevTools); panel.onDidDispose(() => { devtoolsEvents.removeListener("toDevTools", forwardToDevTools); for (const disposable of panelDisposables) { disposable.dispose(); } }); } private static _getHtmlForWebview( webview: vscode.Webview, extensionUri: vscode.Uri, ) { // Get the local path to main script run in the webview, then convert it to a uri we can use in the webview. const scriptUri = webview.asWebviewUri( vscode.Uri.joinPath(extensionUri, "lib", "panel.js"), ); // Use a nonce to only allow a specific script to be run. const nonce = getNonce(); return ` Apollo Client DevTools
`; } } function getNonce() { let text = ""; const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (let i = 0; i < 32; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; }