"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResourceTracker = exports.PipeError = void 0;
exports.safePipe = safePipe;
exports.withResourceCleanup = withResourceCleanup;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const promises_1 = require("node:fs/promises");
const __tsf_metadata_type = _a.createCompactMetadataRegistryV1("[1,[{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"input\"},{\"kind\":10,\"literal\":\"output\"}]},{\"kind\":14,\"type\":{\"kind\":6}},{\"kind\":3},{\"kind\":6},{\"kind\":2},{\"kind\":22,\"type\":{\"kind\":3}}]]", []);
let _PipeErrorMetadata_1;
class PipeError extends Error {
    cause;
    side;
    constructor(cause, side) {
        super(cause.message);
        this.cause = cause;
        this.side = side;
        this.name = 'PipeError';
    }
    static __tsfType = _PipeErrorMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"PipeError\",\"typeName\":\"PipeError\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[],\"hasConstructor\":true,\"constructorParameters\":[{\"name\":\"cause\",\"type\":{\"kind\":16,\"typeName\":\"Error\",\"classType\":{\"$tsf\":1}},\"optional\":false,\"default\":false},{\"name\":\"side\",\"type\":{\"$tsfType\":0},\"optional\":false,\"default\":false}]}]", [() => PipeError, () => (typeof Error !== "undefined" ? Error : (typeof exports !== "undefined" ? exports.Error : undefined))], __tsf_metadata_type);
}
exports.PipeError = PipeError;
_PipeErrorMetadata_1.classType = PipeError;
PipeError.__tsfType = _PipeErrorMetadata_1;
function safePipe(input, output) {
    return new Promise((resolve, reject) => {
        let settled = false;
        const fail = (error, side) => {
            if (settled)
                return;
            settled = true;
            if (side === 'input' && !output.destroyed)
                output.destroy();
            if (side === 'output' && !input.destroyed)
                input.destroy();
            reject(new PipeError(error, side));
        };
        const finish = () => {
            if (settled)
                return;
            settled = true;
            resolve();
        };
        input.on('close', () => {
            if (!input.readableEnded)
                fail(new Error('Input stream aborted'), 'input');
        });
        input.on('error', error => fail(error, 'input'));
        output.on('close', () => {
            if (!output.writableEnded)
                fail(new Error('Output stream aborted'), 'output');
        });
        output.on('error', error => fail(error, 'output'));
        output.on('finish', finish);
        input.pipe(output);
    });
}
let _ResourceTrackerMetadata_1;
class ResourceTracker {
    files = [];
    streams = [];
    failure;
    addStream(stream) {
        stream.on('error', error => {
            this.failure ??= error;
        });
        this.streams.push(stream);
    }
    addFile(file) {
        this.files.push(file);
    }
    getFailure() {
        return this.failure;
    }
    async cleanup() {
        await Promise.all(this.files.map(file => (0, promises_1.unlink)(file).catch(() => { })));
        for (const stream of this.streams) {
            if (!stream.destroyed)
                stream.destroy();
        }
    }
    static __tsfType = _ResourceTrackerMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"ResourceTracker\",\"typeName\":\"ResourceTracker\",\"classType\":{\"$tsf\":0},\"properties\":[{\"name\":\"files\",\"type\":{\"$tsfType\":1},\"optional\":false},{\"name\":\"streams\",\"type\":{\"kind\":14,\"type\":{\"kind\":12,\"types\":[{\"$tsfAlias\":[1,\"node:stream\",\"Readable\",\"Readable\"]},{\"$tsfAlias\":[1,\"node:stream\",\"Writable\",\"Writable\"]}]}},\"optional\":false}],\"methods\":[{\"name\":\"addStream\",\"parameters\":[{\"name\":\"stream\",\"type\":{\"kind\":12,\"types\":[{\"$tsfAlias\":[1,\"node:stream\",\"Readable\",\"Readable\"]},{\"$tsfAlias\":[1,\"node:stream\",\"Writable\",\"Writable\"]}]},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":2}},{\"name\":\"addFile\",\"parameters\":[{\"name\":\"file\",\"type\":{\"$tsfType\":3},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":2}},{\"name\":\"getFailure\",\"parameters\":[],\"returnType\":{\"$tsfType\":4}},{\"name\":\"cleanup\",\"parameters\":[],\"returnType\":{\"$tsfType\":5}}],\"hasConstructor\":false,\"constructorParameters\":[]}]", [() => ResourceTracker, require], __tsf_metadata_type);
}
exports.ResourceTracker = ResourceTracker;
_ResourceTrackerMetadata_1.classType = ResourceTracker;
ResourceTracker.__tsfType = _ResourceTrackerMetadata_1;
function withResourceCleanup(fn, onError) {
    const tracker = new ResourceTracker();
    return (async () => {
        try {
            const result = await fn(tracker);
            const failure = tracker.getFailure();
            if (failure !== undefined)
                throw failure;
            return result;
        }
        catch (error) {
            onError?.(error);
            throw error;
        }
        finally {
            await tracker.cleanup();
        }
    })();
}
//# sourceMappingURL=stream.js.map