| 25 | } |
| 26 | |
| 27 | export function parsePktLines( |
| 28 | buf: Uint8Array, |
| 29 | options: { readonly requireComplete?: boolean } = {}, |
| 30 | ): { tokens: PktToken[]; consumed: number } { |
| 31 | const tokens: PktToken[] = []; |
| 32 | let off = 0; |
| 33 | while (off + 4 <= buf.length) { |
| 34 | const lenHex = td.decode(buf.subarray(off, off + 4)); |
| 35 | const len = parseInt(lenHex, 16); |
| 36 | if (Number.isNaN(len)) throw new Error(`bad pkt-line length: ${lenHex}`); |
| 37 | if (len === 0) { |
| 38 | tokens.push({ kind: "flush" }); |
| 39 | off += 4; |
| 40 | continue; |
| 41 | } |
| 42 | if (len === 1) { |
| 43 | tokens.push({ kind: "delim" }); |
| 44 | off += 4; |
| 45 | continue; |
| 46 | } |
| 47 | if (len < 4) throw new Error(`bad pkt-line length: ${lenHex}`); |
| 48 | if (off + len > buf.length) break; // incomplete; caller supplies more |
| 49 | const data = buf.subarray(off + 4, off + len); |
| 50 | tokens.push({ kind: "line", data }); |
| 51 | off += len; |
| 52 | } |
| 53 | if (options.requireComplete === true && off !== buf.length) { |
| 54 | throw new Error("truncated pkt-line response"); |
| 55 | } |
| 56 | return { tokens, consumed: off }; |
| 57 | } |
| 58 | |
| 59 | // --- Refs advertisement (protocol v1 dumb-ish smart-http info/refs) --- |
| 60 | |