"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.streamPackagedDirectory = streamPackagedDirectory;
exports.getPackagedDirectorySize = getPackagedDirectorySize;
exports.packageDirectory = packageDirectory;
const path_1 = require("path");
const promises_1 = require("node:fs/promises");
const tar_fs_1 = __importDefault(require("tar-fs"));
const node_zlib_1 = require("node:zlib");
const DEFAULT_OPTIONS = { skip_node_modules: false, skip_symlinks: false };
/**
 * Package a directory into a tar+gzip stream. The returned Readable can be
 * piped directly into an HTTP request body, avoiding the Node.js 2GB Buffer
 * cap that the buffered variant runs into for large components.
 *
 * @param onBytes - Optional callback invoked with the byte length of each raw
 *   tar chunk *before* gzip compression. Useful for tracking upload progress
 *   against an uncompressed-size total (e.g. from `getPackagedDirectorySize`).
 */
function streamPackagedDirectory(directory, options = DEFAULT_OPTIONS, onBytes) {
    const packStream = tar_fs_1.default.pack(directory, {
        dereference: !options.skip_symlinks,
        ignore: options.skip_node_modules
            ? (name) => {
                return name.includes('node_modules') || name.includes((0, path_1.join)('cache', 'webpack'));
            }
            : undefined,
        map: (header) => {
            if (header.type === 'directory') {
                header.mode = 0o755;
            }
            return header;
        },
    });
    const gzip = (0, node_zlib_1.createGzip)();
    // Propagate pack errors onto the gzip stream so a single consumer can listen
    packStream.on('error', (err) => gzip.destroy(err));
    if (onBytes) {
        // Attaching a 'data' listener after pipe() is safe — the stream is already
        // in flowing mode and Node's EventEmitter supports multiple listeners.
        packStream.on('data', (chunk) => onBytes(chunk.length));
    }
    return packStream.pipe(gzip);
}
/**
 * Walk `directory` and return the total uncompressed size of all files that
 * `streamPackagedDirectory` would include with the same options. Used by the
 * CLI to give the upload progress bar a realistic total. The uncompressed size
 * won't equal the gzipped wire size, but it gives the bar a steady trajectory:
 * the bar moves as bytes are sent and snaps to 100% when the upload finishes.
 */
async function getPackagedDirectorySize(directory, options = DEFAULT_OPTIONS) {
    let total = 0;
    const walk = async (dir) => {
        let entries;
        try {
            entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
        }
        catch {
            return; // unreadable directory — skip
        }
        for (const entry of entries) {
            const fullPath = (0, path_1.join)(dir, entry.name);
            if (options.skip_node_modules && (entry.name === 'node_modules' || fullPath.includes((0, path_1.join)('cache', 'webpack')))) {
                continue;
            }
            if (entry.isDirectory()) {
                await walk(fullPath);
            }
            else {
                if (options.skip_symlinks && entry.isSymbolicLink())
                    continue;
                try {
                    const s = await (0, promises_1.stat)(fullPath); // follows symlinks, matching tar dereference
                    total += s.size;
                }
                catch {
                    // inaccessible file — skip
                }
            }
        }
    };
    await walk(directory);
    return total;
}
/**
 * Package a directory into a tar+gzip buffer. Retained for callers that need
 * an in-memory payload (small deploys, tests). For large directories prefer
 * `streamPackagedDirectory` to avoid the Buffer size ceiling.
 */
function packageDirectory(directory, options = DEFAULT_OPTIONS) {
    return new Promise((resolve, reject) => {
        const chunks = [];
        const stream = streamPackagedDirectory(directory, options);
        stream.on('data', (chunk) => chunks.push(chunk));
        stream.on('end', () => resolve(Buffer.concat(chunks)));
        stream.on('error', reject);
    });
}
//# sourceMappingURL=packageComponent.js.map