(
url: string,
sha: string,
opts: UploadPackOptions = {},
)
| 156 | // POST /git-upload-pack, parse side-band, extract raw packfile bytes. |
| 157 | // Handles side-band-64k: band 1 = pack data, band 2 = progress, band 3 = error. |
| 158 | export async function uploadPack( |
| 159 | url: string, |
| 160 | sha: string, |
| 161 | opts: UploadPackOptions = {}, |
| 162 | ): Promise<UploadPackResult> { |
| 163 | const fetchImpl = opts.fetchImpl ?? fetch; |
| 164 | const repo = normalizeRepoUrl(url); |
| 165 | const upUrl = `${repo}/git-upload-pack`; |
| 166 | const body = buildV1Request(sha); |
| 167 | const t0 = Date.now(); |
| 168 | const res = await fetchGit( |
| 169 | upUrl, |
| 170 | { |
| 171 | method: "POST", |
| 172 | headers: { |
| 173 | ...baseHeaders(opts.auth ?? {}), |
| 174 | "content-type": "application/x-git-upload-pack-request", |
| 175 | accept: "application/x-git-upload-pack-result", |
| 176 | "git-protocol": "version=1", |
| 177 | }, |
| 178 | body: new Uint8Array(body).buffer, |
| 179 | }, |
| 180 | fetchImpl, |
| 181 | { allowPrivateHosts: opts.allowPrivateHosts }, |
| 182 | ); |
| 183 | if (!res.ok) { |
| 184 | const errText = await res.text(); |
| 185 | throw new Error(`upload-pack ${res.status}: ${errText.slice(0, 200)}`); |
| 186 | } |
| 187 | |
| 188 | // Stream + demux side-band pkt-lines, with a byte cap on total downloaded. |
| 189 | const reader = res.body!.getReader(); |
| 190 | const maxBytes = opts.maxBytes ?? Infinity; |
| 191 | let downloaded = 0; |
| 192 | let truncated = false; |
| 193 | |
| 194 | // Accumulate raw bytes, then demux pkt-lines. We buffer because pkt-lines can |
| 195 | // straddle chunk boundaries; we cap the RAW download. |
| 196 | const chunks: Uint8Array[] = []; |
| 197 | while (true) { |
| 198 | const { done, value } = await reader.read(); |
| 199 | if (done) break; |
| 200 | if (value) { |
| 201 | downloaded += value.length; |
| 202 | chunks.push(value); |
| 203 | if (downloaded >= maxBytes) { |
| 204 | truncated = true; |
| 205 | await reader.cancel(); |
| 206 | break; |
| 207 | } |
| 208 | } |
| 209 | } |
| 210 | const wallMs = Date.now() - t0; |
| 211 | |
| 212 | // concat |
| 213 | const raw = new Uint8Array(downloaded); |
| 214 | { |
| 215 | let off = 0; |
no test coverage detected