( response: Response, spinner: ReturnType<typeof p.spinner>, )
| 48 | | { type: "error"; message: string } |
| 49 | |
| 50 | async function readDeployStream( |
| 51 | response: Response, |
| 52 | spinner: ReturnType<typeof p.spinner>, |
| 53 | ): Promise<Extract<DeployEvent, { type: "result" }>["result"]> { |
| 54 | if (!response.body) { |
| 55 | throw new Error("Deploy response did not include a stream") |
| 56 | } |
| 57 | |
| 58 | const reader = response.body.getReader() |
| 59 | const decoder = new TextDecoder() |
| 60 | let buffer = "" |
| 61 | let result: Extract<DeployEvent, { type: "result" }>["result"] | null = null |
| 62 | |
| 63 | const handleLine = (line: string) => { |
| 64 | let event: DeployEvent |
| 65 | try { |
| 66 | event = JSON.parse(line) as DeployEvent |
| 67 | } catch { |
| 68 | throw new Error(`Invalid deploy stream response: ${line}`) |
| 69 | } |
| 70 | |
| 71 | if (event.type === "status") { |
| 72 | spinner.message(event.message) |
| 73 | return |
| 74 | } |
| 75 | |
| 76 | if (event.type === "error") { |
| 77 | throw new Error(event.message) |
| 78 | } |
| 79 | |
| 80 | result = event.result |
| 81 | } |
| 82 | |
| 83 | while (true) { |
| 84 | const { done, value } = await reader.read() |
| 85 | buffer += decoder.decode(value ?? new Uint8Array(), { stream: !done }) |
| 86 | |
| 87 | let newlineIndex = buffer.indexOf("\n") |
| 88 | while (newlineIndex !== -1) { |
| 89 | const line = buffer.slice(0, newlineIndex).trim() |
| 90 | buffer = buffer.slice(newlineIndex + 1) |
| 91 | if (line) handleLine(line) |
| 92 | newlineIndex = buffer.indexOf("\n") |
| 93 | } |
| 94 | |
| 95 | if (done) break |
| 96 | } |
| 97 | |
| 98 | const tail = buffer.trim() |
| 99 | if (tail) handleLine(tail) |
| 100 | |
| 101 | if (!result) { |
| 102 | throw new Error("Deploy stream ended without a result") |
| 103 | } |
| 104 | |
| 105 | return result |
| 106 | } |
| 107 |
no test coverage detected