"use strict";
/**
 * Timeout protection for async operations
 * Prevents operations from hanging indefinitely
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.AggregateTimeoutError = exports.allWithTimeout = exports.createTimeoutWrapper = exports.TimeoutError = exports.withTimeout = void 0;
/**
 * Wrap an async operation with a timeout
 */
async function withTimeout(promise, options) {
    const { timeout, operation, errorMessage } = options;
    let timeoutId;
    const timeoutPromise = new Promise((_, reject) => {
        timeoutId = setTimeout(() => {
            const defaultMessage = operation
                ? `Operation '${operation}' timed out after ${timeout}ms`
                : `Operation timed out after ${timeout}ms`;
            reject(new TimeoutError(errorMessage || defaultMessage, timeout, operation));
        }, timeout);
    });
    try {
        const result = await Promise.race([promise, timeoutPromise]);
        return result;
    }
    finally {
        if (timeoutId !== undefined) {
            clearTimeout(timeoutId);
        }
    }
}
exports.withTimeout = withTimeout;
/**
 * Custom error for timeout operations
 */
class TimeoutError extends Error {
    constructor(message, timeout, // eslint-disable-line no-unused-vars
    operation // eslint-disable-line no-unused-vars
    ) {
        super(message);
        this.timeout = timeout;
        this.operation = operation;
        this.name = 'TimeoutError';
        // Maintain proper stack trace in V8
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, TimeoutError);
        }
    }
}
exports.TimeoutError = TimeoutError;
/**
 * Create a timeout wrapper function for repeated use
 */
function createTimeoutWrapper(defaultTimeout) {
    return (promise, options) => {
        return withTimeout(promise, {
            timeout: options?.timeout ?? defaultTimeout,
            operation: options?.operation,
            errorMessage: options?.errorMessage,
        });
    };
}
exports.createTimeoutWrapper = createTimeoutWrapper;
/**
 * Wrap multiple promises with individual timeouts
 */
async function allWithTimeout(promises, options) {
    const wrappedPromises = promises.map(({ promise, options: opts }) => withTimeout(promise, opts));
    if (options?.failFast) {
        return Promise.all(wrappedPromises);
    }
    else {
        const results = await Promise.allSettled(wrappedPromises);
        const failures = results.filter(r => r.status === 'rejected');
        if (failures.length > 0) {
            const errors = failures.map(f => f.reason);
            throw new AggregateTimeoutError(errors);
        }
        return results.map(r => r.value);
    }
}
exports.allWithTimeout = allWithTimeout;
/**
 * Aggregate error for multiple timeout failures
 */
class AggregateTimeoutError extends Error {
    constructor(errors) {
        super(`Multiple operations timed out: ${errors.length} failures`);
        this.errors = errors;
        this.name = 'AggregateTimeoutError';
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, AggregateTimeoutError);
        }
    }
}
exports.AggregateTimeoutError = AggregateTimeoutError;
//# sourceMappingURL=async-timeout.js.map