| 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 }; |