"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Client = void 0;
exports.isAWSError = isAWSError;
const client_sts_1 = require("@aws-sdk/client-sts");
const client_s3_1 = require("@aws-sdk/client-s3");
const uuid_1 = require("@lukeed/uuid");
const process = __importStar(require("process"));
const actions_core_1 = require("@segment/actions-core");
class Client {
    constructor(region, roleArn, externalId) {
        this.region = region;
        this.roleSessionName = (0, uuid_1.v4)();
        this.roleArn = roleArn;
        this.externalId = externalId;
    }
    async assumeRole() {
        const intermediaryARN = process.env.AMAZON_S3_ACTIONS_ROLE_ADDRESS;
        const intermediaryExternalId = process.env.AMAZON_S3_ACTIONS_EXTERNAL_ID;
        const intermediaryCreds = await this.getSTSCredentials(intermediaryARN, intermediaryExternalId);
        return this.getSTSCredentials(this.roleArn, this.externalId, intermediaryCreds);
    }
    async getSTSCredentials(roleId, externalId, credentials) {
        const options = { region: this.region, credentials };
        const stsClient = new client_sts_1.STSClient(options);
        const command = new client_sts_1.AssumeRoleCommand({
            RoleArn: roleId,
            RoleSessionName: this.roleSessionName,
            ExternalId: externalId
        });
        const result = await stsClient.send(command);
        if (!result.Credentials ||
            !result.Credentials.AccessKeyId ||
            !result.Credentials.SecretAccessKey ||
            !result.Credentials.SessionToken) {
            throw new actions_core_1.IntegrationError('Failed to assume role', actions_core_1.ErrorCodes.INVALID_AUTHENTICATION, 403);
        }
        return {
            accessKeyId: result.Credentials.AccessKeyId,
            secretAccessKey: result.Credentials.SecretAccessKey,
            sessionToken: result.Credentials.SessionToken
        };
    }
    async uploadS3(settings, fileContent, filename_prefix, s3_aws_folder_name, fileExtension, signal) {
        const dateSuffix = new Date().toISOString().replace(/[:.]/g, '-');
        if (filename_prefix.endsWith('.csv') || filename_prefix.endsWith('.txt')) {
            filename_prefix = filename_prefix.replace(fileExtension, `_${dateSuffix}.${fileExtension}`);
        }
        else {
            filename_prefix = filename_prefix
                ? `${filename_prefix}_${dateSuffix}.${fileExtension}`
                : `${dateSuffix}.${fileExtension}`;
        }
        const bucketName = settings.s3_aws_bucket_name;
        const folderName = ['', null, undefined].includes(s3_aws_folder_name)
            ? ''
            : s3_aws_folder_name?.endsWith('/')
                ? s3_aws_folder_name
                : `${s3_aws_folder_name}/`;
        const credentials = await this.assumeRole();
        const s3Client = new client_s3_1.S3Client({
            region: this.region,
            credentials: {
                accessKeyId: credentials.accessKeyId,
                secretAccessKey: credentials.secretAccessKey,
                sessionToken: credentials.sessionToken
            }
        });
        const contentType = fileExtension === 'csv' ? 'text/csv' : 'text/plain';
        const objectKey = folderName ? `${folderName}${filename_prefix}` : filename_prefix;
        const uploadParams = {
            Bucket: bucketName,
            Key: objectKey,
            Body: fileContent,
            ContentType: contentType
        };
        try {
            await s3Client.send(new client_s3_1.PutObjectCommand(uploadParams), { abortSignal: signal });
            return { statusCode: 200, message: 'Upload successful' };
        }
        catch (err) {
            if (err.name === 'AbortError') {
                throw new actions_core_1.RequestTimeoutError();
            }
            if (isAWSError(err)) {
                if (err.Code && accessDeniedCodes.has(err.Code)) {
                    throw new actions_core_1.APIError(err.Message || err.Code, 403);
                }
                else if (err.Code === 'NoSuchBucket') {
                    throw new actions_core_1.APIError(err.Message || err.Code, 404);
                }
                else if (err.Code === 'SlowDown') {
                    throw new actions_core_1.APIError(err.Message || err.Code, 429);
                }
                else {
                    throw new actions_core_1.RetryableError(err.Message || err.Code || 'Unknown AWS Put error: ' + err);
                }
            }
            else {
                throw new actions_core_1.APIError('Unknown error during AWS PUT: ' + err, 500);
            }
        }
    }
}
exports.Client = Client;
const accessDeniedCodes = new Set([
    'AccessDenied',
    'AccountProblem',
    'AllAccessDisabled',
    'InvalidAccessKeyId',
    'InvalidSecurity',
    'NotSignedUp',
    'AmbiguousGrantByEmailAddress',
    'AuthorizationHeaderMalformed',
    'RequestExpired'
]);
function isAWSError(err) {
    return typeof err === 'object' && err !== null && 'Code' in err && 'Message' in err;
}
//# sourceMappingURL=client.js.map