import { a as normalizeBody, i as isBodyless, n as createTarPacker$1, r as transformHeader, t as createUnpacker } from "../unpacker-CPCEF5CT.js"; //#region src/web/compression.ts function createGzipEncoder() { return new CompressionStream("gzip"); } function createGzipDecoder() { return new DecompressionStream("gzip"); } //#endregion //#region src/web/pack.ts function createTarPacker() { let streamController; let packer; return { readable: new ReadableStream({ start(controller) { streamController = controller; packer = createTarPacker$1(controller.enqueue.bind(controller), controller.error.bind(controller), controller.close.bind(controller)); } }), controller: { add(header) { const bodyless = isBodyless(header); packer.add(header); if (bodyless) packer.endEntry(); return new WritableStream({ write(chunk) { packer.write(chunk); }, close() { if (!bodyless) packer.endEntry(); }, abort(reason) { streamController.error(reason); } }); }, finalize() { packer.finalize(); }, error(err) { streamController.error(err); } } }; } //#endregion //#region src/web/stream-utils.ts async function streamToBuffer(stream) { const chunks = []; const reader = stream.getReader(); let totalLength = 0; try { while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); totalLength += value.length; } const result = new Uint8Array(totalLength); let offset = 0; for (const chunk of chunks) { result.set(chunk, offset); offset += chunk.length; } return result; } finally { reader.releaseLock(); } } const drain = (stream) => stream.pipeTo(new WritableStream()); //#endregion //#region src/web/unpack.ts function createTarDecoder(options = {}) { const unpacker = createUnpacker(options); const strict = options.strict ?? false; let controller = null; let bodyController = null; let pumping = false; let eofReached = false; let sourceEnded = false; let closed = false; const closeBody = () => { try { bodyController?.close(); } catch {} bodyController = null; }; const fail = (reason) => { if (closed) return; closed = true; try { bodyController?.error(reason); } catch {} bodyController = null; try { controller.error(reason); } catch {} controller = null; }; const finish = () => { if (closed) return; closed = true; closeBody(); try { controller.close(); } catch {} controller = null; }; const truncateOrFinish = () => { if (strict) throw new Error("Tar archive is truncated."); finish(); }; const pump = () => { if (pumping || closed || !controller) return; pumping = true; try { while (true) { if (eofReached) { if (sourceEnded) { unpacker.validateEOF(); finish(); } break; } if (unpacker.isEntryActive()) { if (sourceEnded && !unpacker.canFinish()) { truncateOrFinish(); break; } if (bodyController) { if ((bodyController.desiredSize ?? 1) <= 0) break; if (unpacker.streamBody((c) => (bodyController.enqueue(c), (bodyController.desiredSize ?? 1) > 0)) === 0 && !unpacker.isBodyComplete()) { if (sourceEnded) truncateOrFinish(); break; } } else if (!unpacker.skipEntry()) { if (sourceEnded) truncateOrFinish(); break; } if (unpacker.isBodyComplete()) { closeBody(); if (!unpacker.skipPadding()) { if (sourceEnded) truncateOrFinish(); break; } } } else { if ((controller.desiredSize ?? 0) < 0) break; const header = unpacker.readHeader(); if (header === null) { if (sourceEnded) finish(); break; } if (header === void 0) { if (sourceEnded) { unpacker.validateEOF(); finish(); break; } eofReached = true; break; } controller.enqueue({ header, body: new ReadableStream({ start(c) { if (header.size === 0) c.close(); else bodyController = c; }, pull: pump, cancel() { bodyController = null; pump(); } }) }); } } } catch (error) { fail(error); throw error; } finally { pumping = false; } }; return { readable: new ReadableStream({ start(c) { controller = c; }, pull: pump, cancel(reason) { if (reason !== void 0) fail(reason); else finish(); } }, { highWaterMark: 2 }), writable: new WritableStream({ write(chunk) { try { if (eofReached && strict && chunk.some((byte) => byte !== 0)) throw new Error("Invalid EOF."); unpacker.write(chunk); pump(); } catch (error) { fail(error); throw error; } }, close() { try { sourceEnded = true; unpacker.end(); pump(); } catch (error) { fail(error); throw error; } }, abort(reason) { fail(reason); } }) }; } //#endregion //#region src/web/helpers.ts async function packTar(entries) { const { readable, controller } = createTarPacker(); await (async () => { for (const entry of entries) { const entryStream = controller.add(entry.header); const body = "body" in entry ? entry.body : entry.data; if (!body) { await entryStream.close(); continue; } if (body instanceof ReadableStream) await body.pipeTo(entryStream); else if (body instanceof Blob) await body.stream().pipeTo(entryStream); else try { const chunk = await normalizeBody(body); if (chunk.length > 0) { const writer = entryStream.getWriter(); await writer.write(chunk); await writer.close(); } else await entryStream.close(); } catch { throw new TypeError(`Unsupported content type for entry "${entry.header.name}".`); } } })().then(() => controller.finalize()).catch((err) => controller.error(err)); return new Uint8Array(await streamToBuffer(readable)); } async function unpackTar(archive, options = {}) { const sourceStream = archive instanceof ReadableStream ? archive : new ReadableStream({ start(controller) { controller.enqueue(archive instanceof Uint8Array ? archive : new Uint8Array(archive)); controller.close(); } }); const results = []; const entryStream = sourceStream.pipeThrough(createTarDecoder(options)); for await (const entry of entryStream) { let processedHeader; try { processedHeader = transformHeader(entry.header, options); } catch (error) { await entry.body.cancel(); throw error; } if (processedHeader === null) { await drain(entry.body); continue; } if (isBodyless(processedHeader)) { await drain(entry.body); results.push({ header: processedHeader }); } else results.push({ header: processedHeader, data: await streamToBuffer(entry.body) }); } return results; } //#endregion export { createGzipDecoder, createGzipEncoder, createTarDecoder, createTarPacker, packTar, unpackTar };