"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bedrock = bedrock;
const tslib_1 = require("../../internal/tslib.js");
const credential_provider_node_1 = require("@aws-sdk/credential-provider-node");
const hash_node_1 = require("@smithy/hash-node");
const signature_v4_1 = require("@smithy/signature-v4");
const Errors = tslib_1.__importStar(require("../../error.js"));
const bedrock_1 = require("../../internal/bedrock.js");
const provider_1 = require("../../internal/provider.js");
const BEDROCK_SERVICE = 'bedrock-mantle';
function validateStaticCredentials(options) {
    const hasAccessKey = options.accessKeyId !== undefined;
    const hasSecretKey = options.secretAccessKey !== undefined;
    if (hasAccessKey !== hasSecretKey || (options.sessionToken !== undefined && !hasAccessKey)) {
        throw new Errors.OpenAIError('The `accessKeyId` and `secretAccessKey` options must be provided together. A `sessionToken` may only be used with both.');
    }
    if (!hasAccessKey)
        return undefined;
    if (typeof options.accessKeyId !== 'string' ||
        !options.accessKeyId.trim() ||
        typeof options.secretAccessKey !== 'string' ||
        !options.secretAccessKey.trim()) {
        throw new Errors.OpenAIError('Static AWS credentials require non-empty `accessKeyId` and `secretAccessKey` values.');
    }
    if (options.sessionToken !== undefined &&
        (typeof options.sessionToken !== 'string' || !options.sessionToken.trim())) {
        throw new Errors.OpenAIError('A static AWS `sessionToken` must not be empty when provided.');
    }
    return {
        accessKeyId: options.accessKeyId,
        secretAccessKey: options.secretAccessKey,
        ...(options.sessionToken ? { sessionToken: options.sessionToken } : {}),
    };
}
function requestTarget(parsedURL) {
    const query = {};
    for (const [name, value] of parsedURL.searchParams) {
        const existing = query[name];
        query[name] =
            existing === undefined ? value
                : typeof existing === 'string' ? [existing, value]
                    : [...existing, value];
    }
    return { path: parsedURL.pathname, query };
}
function signableBody(body) {
    if (body === undefined || body === null)
        return undefined;
    if (typeof body === 'string' || body instanceof ArrayBuffer || ArrayBuffer.isView(body))
        return body;
    throw new Errors.OpenAIError("The SDK's Bedrock SigV4 mode requires a replayable request body. Buffer the body before sending or use bearer authentication.");
}
function validateCredentialIdentity(identity) {
    if (typeof identity?.accessKeyId !== 'string' ||
        !identity.accessKeyId.trim() ||
        typeof identity.secretAccessKey !== 'string' ||
        !identity.secretAccessKey.trim() ||
        (identity.sessionToken !== undefined &&
            (typeof identity.sessionToken !== 'string' || !identity.sessionToken.trim()))) {
        throw new Errors.OpenAIError('Failed to resolve AWS credentials for Bedrock. Verify your AWS profile, environment variables, or runtime identity configuration and try again.');
    }
    return identity;
}
class BedrockSigV4Auth {
    constructor(options) {
        this.options = options;
    }
    credentialsProvider() {
        if (this.resolvedCredentialsProvider)
            return this.resolvedCredentialsProvider;
        if (this.options.staticCredentials) {
            const credentials = this.options.staticCredentials;
            return (this.resolvedCredentialsProvider = async () => credentials);
        }
        if (this.options.credentialProvider) {
            const provider = this.options.credentialProvider;
            return (this.resolvedCredentialsProvider = async () => validateCredentialIdentity(await provider()));
        }
        const provider = (0, credential_provider_node_1.defaultProvider)(this.options.profile ? { profile: this.options.profile } : {});
        return (this.resolvedCredentialsProvider = async () => validateCredentialIdentity(await provider()));
    }
    signatureV4() {
        return (this.signer ?? (this.signer = new signature_v4_1.SignatureV4({
            credentials: this.credentialsProvider(),
            region: this.options.region,
            service: BEDROCK_SERVICE,
            sha256: hash_node_1.Hash.bind(null, 'sha256'),
        })));
    }
    async prepareRequest(request, { url }) {
        if (Object.prototype.toString.call(globalThis.process) !== '[object process]') {
            throw new Errors.OpenAIError('Bedrock AWS credential authentication is only supported in Node.js and compatible server runtimes. Use bearer authentication in this runtime.');
        }
        const parsedURL = new URL(url);
        const canonicalRegion = /^bedrock-mantle\.([a-z0-9-]+)\.api\.aws$/i.exec(parsedURL.hostname)?.[1];
        if (canonicalRegion && canonicalRegion !== this.options.region) {
            throw new Errors.OpenAIError(`The Bedrock endpoint region \`${canonicalRegion}\` does not match the SigV4 region \`${this.options.region}\`.`);
        }
        const headers = new Headers(request.headers);
        (0, bedrock_1.assertProviderOwnsAuthorization)(headers);
        headers.delete('x-amz-date');
        headers.delete('x-amz-security-token');
        headers.delete('x-amz-content-sha256');
        headers.set('host', parsedURL.host);
        const method = (request.method ?? 'GET').toUpperCase();
        const body = signableBody(request.body);
        let signed;
        try {
            signed = await this.signatureV4().sign({
                protocol: parsedURL.protocol,
                hostname: parsedURL.hostname,
                ...(parsedURL.port ? { port: Number(parsedURL.port) } : {}),
                method,
                ...requestTarget(parsedURL),
                headers: Object.fromEntries(headers.entries()),
                ...(body !== undefined ? { body } : {}),
            });
        }
        catch (cause) {
            const message = this.options.usesDefaultChain ?
                'Could not find credentials for Bedrock. Pass AWS credentials to `bedrock(...)` or configure the default AWS credential chain.'
                : 'Failed to resolve AWS credentials for Bedrock. Verify your AWS profile, environment variables, or runtime identity configuration and try again.';
            throw (0, bedrock_1.errorWithCause)(message, cause);
        }
        request.method = method;
        request.redirect = 'manual';
        request.headers = new Headers(signed.headers);
    }
}
/** Configure the standard OpenAI client for Amazon Bedrock using bearer or AWS authentication. */
function bedrock(options = {}) {
    const staticCredentials = validateStaticCredentials(options);
    const profile = (0, bedrock_1.normalizeOptionalString)(options.profile);
    if (options.profile !== undefined && !profile) {
        throw new Errors.OpenAIError('The Bedrock AWS `profile` must not be empty.');
    }
    const awsModes = [!!staticCredentials, !!profile, !!options.credentialProvider].filter(Boolean).length;
    if (awsModes > 1) {
        throw new Errors.OpenAIError('Bedrock authentication is ambiguous. Configure exactly one explicit AWS mode: static credentials, profile, or credential provider.');
    }
    const explicitAwsAuth = awsModes === 1;
    const bearerAuth = (0, bedrock_1.resolveBedrockBearerAuth)(options, { allowEnvironment: !explicitAwsAuth });
    if (bearerAuth.explicit && explicitAwsAuth) {
        throw new Errors.OpenAIError('Bearer and AWS credential authentication are mutually exclusive. Configure exactly one explicit mode: bearer credential, static AWS credentials, profile, or credential provider.');
    }
    const { region, baseURL } = (0, bedrock_1.resolveBedrockEndpoint)(options);
    if (!bearerAuth.factory && !region) {
        throw new Errors.OpenAIError('Bedrock requires an AWS region. Pass `region` to `bedrock(...)`, or set `AWS_REGION` or `AWS_DEFAULT_REGION`.');
    }
    const credentialProvider = options.credentialProvider;
    return (0, provider_1.createProvider)({
        configure() {
            const auth = bearerAuth.factory?.() ??
                new BedrockSigV4Auth({
                    region: region,
                    staticCredentials,
                    profile,
                    credentialProvider,
                    usesDefaultChain: !explicitAwsAuth,
                });
            return {
                name: 'bedrock',
                baseURL,
                prepareRequest: auth.prepareRequest.bind(auth),
            };
        },
    });
}
//# sourceMappingURL=aws.js.map