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