* Send a request to the extension and wait for a matching response message. * Returns `undefined` from `extract` to skip non-matching messages, or the * parsed value to resolve the promise.
( host: ExtensionHost, request: WebviewMessage, extract: (message: Record<string, unknown>) => T | undefined, )
| 143 | * parsed value to resolve the promise. |
| 144 | */ |
| 145 | function requestFromExtension<T>( |
| 146 | host: ExtensionHost, |
| 147 | request: WebviewMessage, |
| 148 | extract: (message: Record<string, unknown>) => T | undefined, |
| 149 | ): Promise<T> { |
| 150 | return new Promise<T>((resolve, reject) => { |
| 151 | let settled = false |
| 152 | |
| 153 | const cleanup = () => { |
| 154 | clearTimeout(timeoutId) |
| 155 | host.off("extensionWebviewMessage", onMessage) |
| 156 | offError() |
| 157 | } |
| 158 | |
| 159 | const finish = (fn: () => void) => { |
| 160 | if (settled) return |
| 161 | settled = true |
| 162 | cleanup() |
| 163 | fn() |
| 164 | } |
| 165 | |
| 166 | const onMessage = (message: unknown) => { |
| 167 | if (!isRecord(message)) { |
| 168 | return |
| 169 | } |
| 170 | |
| 171 | let result: T | undefined |
| 172 | try { |
| 173 | result = extract(message) |
| 174 | } catch (error) { |
| 175 | finish(() => reject(error instanceof Error ? error : new Error(String(error)))) |
| 176 | return |
| 177 | } |
| 178 | |
| 179 | if (result !== undefined) { |
| 180 | finish(() => resolve(result)) |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | const offError = host.client.on("error", (error) => { |
| 185 | finish(() => reject(error)) |
| 186 | }) |
| 187 | |
| 188 | const timeoutId = setTimeout(() => { |
| 189 | finish(() => |
| 190 | reject(new Error(`Timed out waiting for ${request.type} response after ${REQUEST_TIMEOUT_MS}ms`)), |
| 191 | ) |
| 192 | }, REQUEST_TIMEOUT_MS) |
| 193 | |
| 194 | host.on("extensionWebviewMessage", onMessage) |
| 195 | host.sendToExtension(request) |
| 196 | }) |
| 197 | } |
| 198 | |
| 199 | function requestCommands(host: ExtensionHost): Promise<CommandLike[]> { |
| 200 | return requestFromExtension(host, { type: "requestCommands" }, (message) => { |
no test coverage detected