1
+ import { AxiosInstance } from "axios"
1
2
import { spawn } from "child_process"
2
3
import { Api } from "coder/site/src/api/api"
3
4
import { ProvisionerJobLog , Workspace } from "coder/site/src/api/typesGenerated"
5
+ import { FetchLikeInit } from "eventsource"
4
6
import fs from "fs/promises"
5
7
import { ProxyAgent } from "proxy-agent"
6
8
import * as vscode from "vscode"
@@ -120,6 +122,60 @@ export async function makeCoderSdk(baseUrl: string, token: string | undefined, s
120
122
return restClient
121
123
}
122
124
125
+ /**
126
+ * Creates a fetch adapter using an Axios instance that returns streaming responses.
127
+ * This can be used with APIs that accept fetch-like interfaces.
128
+ */
129
+ export function createStreamingFetchAdapter ( axiosInstance : AxiosInstance ) {
130
+ return async ( url : string | URL , init ?: FetchLikeInit ) => {
131
+ const urlStr = url . toString ( )
132
+
133
+ const response = await axiosInstance . request ( {
134
+ url : urlStr ,
135
+ headers : init ?. headers as Record < string , string > ,
136
+ responseType : "stream" ,
137
+ validateStatus : ( ) => true , // Don't throw on any status code
138
+ } )
139
+ const stream = new ReadableStream ( {
140
+ start ( controller ) {
141
+ response . data . on ( "data" , ( chunk : Buffer ) => {
142
+ controller . enqueue ( chunk )
143
+ } )
144
+
145
+ response . data . on ( "end" , ( ) => {
146
+ controller . close ( )
147
+ } )
148
+
149
+ response . data . on ( "error" , ( err : Error ) => {
150
+ controller . error ( err )
151
+ } )
152
+ } ,
153
+
154
+ cancel ( ) {
155
+ response . data . destroy ( )
156
+ return Promise . resolve ( )
157
+ } ,
158
+ } )
159
+
160
+ const createReader = ( ) => stream . getReader ( )
161
+
162
+ return {
163
+ body : {
164
+ getReader : ( ) => createReader ( ) ,
165
+ } ,
166
+ url : urlStr ,
167
+ status : response . status ,
168
+ redirected : response . request . res . responseUrl !== urlStr ,
169
+ headers : {
170
+ get : ( name : string ) => {
171
+ const value = response . headers [ name . toLowerCase ( ) ]
172
+ return value === undefined ? null : String ( value )
173
+ } ,
174
+ } ,
175
+ }
176
+ }
177
+ }
178
+
123
179
/**
124
180
* Start or update a workspace and return the updated workspace.
125
181
*/
@@ -212,6 +268,7 @@ export async function waitForBuild(
212
268
path += `&after=${ logs [ logs . length - 1 ] . id } `
213
269
}
214
270
271
+ const agent = await createHttpAgent ( )
215
272
await new Promise < void > ( ( resolve , reject ) => {
216
273
try {
217
274
const baseUrl = new URL ( baseUrlRaw )
@@ -224,6 +281,7 @@ export async function waitForBuild(
224
281
| undefined ,
225
282
} ,
226
283
followRedirects : true ,
284
+ agent : agent ,
227
285
} )
228
286
socket . binaryType = "nodebuffer"
229
287
socket . on ( "message" , ( data ) => {
0 commit comments