/// <reference types="node" />
import EventEmitter from "events";
import { Consumer } from "sqs-consumer";
import { MessageAttributeValue, SQSClientConfig, Message, SendMessageRequest, SendMessageBatchRequest } from "@aws-sdk/client-sqs";
import { PublishBatchInput, PublishInput, SNSClientConfig } from "@aws-sdk/client-sns";
import { LambdaClientConfig } from "@aws-sdk/client-lambda";
import { OutboxConfig } from "./outbox/types";
import { DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
export interface Logger {
    error(error: any): void;
    warn(message: any): void;
    debug(message: any): void;
    info(message: any): void;
}
export type MessageAttributes = {
    [key: string]: MessageAttributeValue;
};
export interface IMessage<T> {
    data: T;
    eventName: string;
    messageGroupId?: string;
    messageAttributes?: MessageAttributes;
    deduplicationId?: string;
    id?: string;
    delay?: number;
    compressed?: boolean;
}
export type ISQSMessage = IMessage<any>;
export interface ISQSMessageOptions {
    delay: number;
}
export interface IMessageAttributes {
    DataType: "String" | "Number" | "Binary" | "String.Array";
    StringValue?: string;
    BinaryValue?: Uint8Array;
    StringListValues?: string[];
    BinaryListValues?: Uint8Array[];
}
export type ConsumerOptions = Omit<Topic, "separateConsumerGroup" | "exchangeType" | "consumerGroup">;
export interface IEmitOptions {
    /**
     * Set to true when emitting to fifo topic
     *
     * Default is false
     */
    isFifo: boolean;
    /**
     * Use with FIFO Topic/Queue to ensure the ordering of events
     *
     * Refer to https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html
     */
    partitionKey?: string;
    /**
     * For Queue type, message is sent directly to queue.
     * This means that the quotas for SQS apply here for throttling
     *
     * For Fanout, message is sent from Topic to queues.
     * This means that the quotas for SNS apply here for throttling
     *
     * Default is Fanout
     */
    exchangeType: ExchangeType;
    /**
     * Use to identify separate queue
     */
    consumerGroup?: string;
    /**
     * Delay receiving the message on consumer
     * This overrides the delay set on the topic in case of non fifo
     *
     * Unit: s
     */
    delay?: number;
    /**
     * Message attributes to be sent along with the message
     */
    MessageAttributes?: MessageAttributes;
    /**
     * Set to a unique id if you want to avoid duplications in
     * a FIFO queue. The same deduplicationId sent within a 5
     * minite interval will be discarded.
     */
    deduplicationId?: string;
    /**
     * Anything that is required by the save function to save the outbox events to the consumer service outbox table
     * e.g transaction, entity manager etc
     */
    outboxData?: Record<string, any>;
    /**
     * Should compress the message before sending
     */
    compressed?: boolean;
}
export type IBatchEmitOptions = Pick<IEmitOptions, "isFifo" | "exchangeType" | "consumerGroup" | "outboxData">;
export type IBatchMessage<T = any> = Omit<IEmitOptions, "isFifo" | "exchangeType" | "consumerGroup"> & {
    data: T;
    /**
     * A batch-level unique id. Used for reporting the result
     * of the batch api
     */
    id: string;
};
export interface IFailedEmitBatchMessage {
    /**
     * The batch-level unique id of the failed message
     */
    id?: string;
    /**
     * An error code representing why the message failed
     */
    code?: string;
    /**
     * An optional message explaining the failure
     */
    message?: string;
    /**
     * A boolean indicating wether the message failed due to sender
     */
    wasSenderFault?: boolean;
}
export interface IFailedConsumerMessages {
    batchItemFailures: {
        itemIdentifier: string;
    }[];
}
export interface IFailedEventMessage {
    topic?: string;
    topicReference?: string;
    event: any;
    error?: any;
    failureType: FailedEventCategory;
    executionContext?: ProcessMessageContext;
}
export interface Queue {
    name: string;
    isFifo: boolean;
    consumers?: Consumer[];
    url?: string;
    arn?: string;
    isDLQ?: boolean;
    visibilityTimeout?: number;
    delay?: number;
    retentionPeriod?: number;
    maxRetryCount?: number;
    tags?: Record<string, string>;
    batchSize?: number;
    /**
     * @deprecated
     */
    listenerIsLambda?: boolean;
    topic: Topic;
    allTopics: Topic[];
    workers?: number;
    consumerIdempotencyOptions?: ConsumerIdempotencyOptions;
}
export declare enum ConsumerIdempotencyStrategy {
    DeduplicationId = "DeduplicationId",
    PayloadHash = "PayloadHash",
    Custom = "Custom"
}
export interface ConsumerIdempotencyOptions {
    /**
     * The strategy to use for idempotency
     */
    strategy: ConsumerIdempotencyStrategy;
    /**
     * The key to use for idempotency if strategy is Custom
     */
    key?<T>(payload: T, metadata: MessageMetaData): string;
    /**
     * The time for which the idempotency should be maintained
     *
     * Default: 5 min
     *
     * Unit: s
     */
    expiry?: number;
}
export interface Topic {
    name: string;
    /**
     * Set to true if topic is FIFO, default is false
     */
    isFifo?: boolean;
    /**
     * The time for which message won't be available to other
     * consumers when it is received by a consumer
     *
     * Unit: s
     *
     * Default: 360s
     */
    visibilityTimeout?: number;
    /**
     * Default: 10 for consumption
     */
    batchSize?: number;
    /**
     * Maximum number the broker will attempt to retry the message
     * before which it is added to the related DLQ if deadLetterQueueEnabled
     * is true in emitter options
     *
     * Default: 3
     */
    maxRetryCount?: number;
    /**
     * Topic level DLQ specification
     *
     * Set to true to create a corresponding DLQ
     */
    deadLetterQueueEnabled?: boolean;
    /**
     * An optional consumer group name
     *
     * Set if you want to use a separate consumer group
     *
     * Used to identify the queue from which the consumer
     * will consume the messages from this topic. When not provided,
     * the broker will subscribe the default queue to this topic. If
     * the default queue is not specified, an error will be thrown.
     * @deprecated Use consumerGroup instead
     */
    separateConsumerGroup?: string;
    /**
     * An optional consumer group specification
     * Use this when consumer configuration is different from the topic
     *
     * When specified, the broker will consume the messages from this
     * otherwise the broker will subscribe the default queue to this topic
     */
    consumerGroup?: ConsumerOptions;
    /**
     * An optional Lambda function specification
     *
     * When specified, the broker will create an event source
     * mapping for the lambda and consumer
     */
    lambdaHandler?: ILambdaHandler;
    /**
     * For Queue type, message is sent directly to queue.
     * This means that the quotas for SQS apply here for throttling
     *
     * For Fanout, message is sent from Topic to queues.
     * This means that the quotas for SNS apply here for throttling
     *
     * Queue exchange type is always consumed via a separate consumer group (queue)
     */
    exchangeType: ExchangeType;
    /**
     * An optional filter policy
     *
     * When specified, the broker will create an event source
     * mapping for the lambda and consumer
     */
    filterPolicy?: {
        [key: string]: string[];
    };
    /**
     * Set to true to enable high throughput on FIFO queues
     */
    enableHighThroughput?: boolean;
    /**
     * Retention time for messages in the queue of this topic
     *
     * Valid Values: An integer from 60 seconds (1 minute) to 1,209,600 seconds (14 days)
     *
     * Default is 1 Day
     *
     * Unit: s
     */
    retentionPeriod?: number;
    /**
     * Enable content based deduplication. Enabling it means that for messages that
     * are sent without an explicit DeduplicationId AWS will generate it based on the
     * message body using SHA 256 and use it for deduplication. Enabling this is required
     * for interacting with some AWS services like dropping messages from the event bridge
     * scheduler into the sqs queue
     *
     * Is only effective for Fifo queues
     *
     * Default value is false (off)
     */
    contentBasedDeduplication?: boolean;
    /**
     * Delay receiving the message on consumer
     *
     * Unit: s
     */
    delay?: number;
    /**
     * The number of workers attached to this queue
     */
    workers?: number;
    /**
     * tags for queue identification
     * should be less than 50
     * each tag should be less than 128 characters
     */
    tags?: Record<string, string>;
    /**
     * Optional consumer level idempotency options
     */
    consumerIdempotencyOptions?: ConsumerIdempotencyOptions;
}
export interface Hooks {
    /**
     *
     * @param topicName name of the topic on which beforeEmit was
     * executed
     * @param data the data with which emit was called
     * @returns the data with any changes to be done before it's emitted
     */
    beforeEmit?<T>(topicName: string, data: T): Promise<T>;
    /**
     *
     * @param topicName name of the topic on which afterEmit was
     * executed
     * @param data the data with which emit was called
     */
    afterEmit?<T>(topicName: string, data: T): Promise<void>;
    /**
     *
     * @param topicName name of the topic on which beforeConsume was
     * executed
     * @param data the data with which the consumer function will be called
     * @returns the data with any changes to be done before calling the consumer
     * function
     */
    beforeConsume?<T>(topicName: string, data: T): Promise<T>;
    /**
     *
     * @param topicName name of the topic on which afterConsume will be
     * executed
     * @param data the data with which the consumer function was called
     */
    afterConsume?<T>(topicName: string, data: T): Promise<void>;
}
export interface ILambdaHandler {
    /**
     * The complete function name constructed as
     * serviceName-environment-functionName
     */
    functionName: string;
    maximumConcurrency?: number;
}
export type ConsumeOptions = Omit<Topic, "name" | "lambdaHandler"> & {
    useLocal?: boolean;
};
export interface IEmitterOptions {
    /**
     * Set to true if using external broker as client
     */
    useExternalBroker?: boolean;
    /**
     * local, dev, stag, prod etc
     */
    environment: string;
    /**
     * The local NodeJS Emitter used for logging failed events
     */
    localEmitter: EventEmitter;
    /**
     * An optional event on which failed events will be emitted
     *
     * These include failures when sending and consuming messages
     */
    eventOnFailure?: string;
    /**
     * Maximum number of times the broker will retry the message
     * in case of failure in consumption after which it will be
     * moved to a DLQ if deadLetterQueueEnabled is true
     *
     * Default: 3
     */
    maxRetries?: number;
    /**
     * Optional SQS Client config used by message producer
     */
    sqsConfig?: SQSClientConfig;
    /**
     * Optional SNS Client config used by message producer
     */
    snsConfig?: SNSClientConfig;
    /**
     * Optional Lambda Client config used by message producer
     */
    lambdaConfig?: LambdaClientConfig;
    /**
     * Optional DynamoDB Client config used by the broker to build consumer idempotency
     */
    dynamoConfig?: DynamoDBClientConfig;
    /**
     * Optional default queues options when consuming on a default queue
     *
     * When using default queues, Topics for which a separateConsumerGroup
     * is not specified are consumed from the default queues.
     */
    defaultQueueOptions?: {
        fifo: DefaultQueueOptions;
        standard: DefaultQueueOptions;
    };
    /**
     * Optional AWS Config used by the emitter when useExternalBroker is true
     */
    awsConfig?: {
        region: string;
        accountId: string;
    };
    /**
     * Set to true to enable logging
     */
    log?: boolean;
    /**
     * Set to true to enable local aws
     */
    isLocal?: boolean;
    /**
     * @description Provide this to override the default logger and control
     * log levels and mapping
     */
    logger?: Logger;
    /**
     * Optional global hooks that run on every topic
     * make sure to catch any errors since the broker will throw
     * if any of the hooks throws
     */
    hooks?: Hooks;
    /**
     * Optional global outbox options
     * If provided, the broker will save the events to the outbox table
     */
    outboxConfig?: OutboxConfig;
    /**
     * The name of your service
     */
    serviceName: string;
    /**
     * Optional idempotency flag to turn on idempotency feature for all consumers
     * If set to true, the broker will create a DynamoDB table to store the idempotency keys
     * and will use the idempotency options provided at the consumer level or the default
     * options provided at the global level
     *
     * Default is true
     */
    useIdempotency?: boolean;
    /**
     * Optional global level idempotency options
     */
    consumerIdempotencyOptions?: ConsumerIdempotencyOptions;
    /**
     * Optional mock emitter configuration
     * set useExternalBroker to false and use this for local testing
     * When enabled, the emitter will not send messages to AWS
     * but will instead emit them locally using the local EventEmitter2 using "emitAsync"
     * This is useful for testing and local development
     * Does not implement outbox
     */
    mockEmitter?: {
        throwErrors: boolean;
    };
}
export type DefaultQueueOptions = Omit<Topic, "separateConsumerGroup" | "isFifo" | "exchangeType">;
export interface MessageMetaData {
    executionContext: ProcessMessageContext;
    messageId?: string;
    messageAttributes?: MessageAttributes;
    approximateReceiveCount?: number;
}
export type EventListener<T> = (args: T, metadata?: MessageMetaData) => Promise<void>;
export interface IEmitter {
    /**
     * Call for creation of topics and queues
     * @param topics An optional array of topics.
     * Only required if Emitter.on is not used
     */
    bootstrap(topics?: Topic[]): Promise<void>;
    emit<T = any>(eventName: string, options?: IEmitOptions, payload?: T): Promise<void>;
    /**
     * @param eventName Name of the topic/event to emit in batch
     * @param messages A list of max 10 messages to send as a batch
     * @param options Optional batch emit options
     */
    emitBatch<T = any>(eventName: string, messages: IBatchMessage<T>[], options?: IBatchEmitOptions): Promise<IFailedEmitBatchMessage[]>;
    on<T>(eventName: string, listener: EventListener<T>, options?: ConsumeOptions): void;
    removeAllListener(): void;
    removeListener(eventName: string, listener: EventListener<any>, consumeOptions?: ConsumeOptions): void;
    /**
     * Use this method to when you need to consume messages by yourself
     * but use the routing logic defined in the broker.
     * This function throws if the consumer function fails
     * @param message The message received from topic
     * @param options ProcessMessageOptions
     */
    processMessage(message: Message, options?: ProcessMessageOptions): Promise<void>;
    /**
     * This function does not throw when the consumer function fails.
     * Instead, it returns a list of failed messages as IFailedConsumerMessages
     * @param messages A list of messages received from topic
     * @param options ProcessMessageOptions
     * @returns An object containing a list of the messages that failed.
     * This object is compatible with the return type required by lambda event
     * source mapping and thus can be returned from the lambda directly
     */
    processMessages(messages: Message[], options?: ProcessMessageOptions): Promise<IFailedConsumerMessages>;
    /**
     * @param topic A Topic object
     *
     * To get the correct arn, the following properties should be provided
     * if applicable
     *
     * name, isFifo
     * @returns ARN of Topic that the broker generates internally
     */
    getTopicReference(topic: Topic): string;
    /**
     * @param topic A Topic object
     *
     * To get the correct name, the following properties should be provided
     * if applicable
     *
     * name, isFifo
     * @returns Name of Topic that the broker generates internally
     */
    getInternalTopicName(topic: Topic): string;
    /**
     * @returns An array of all the queues being consumed
     * by the broker
     */
    getQueues(): Queue[];
    /**
     * @param topic A Topic object
     *
     * To get the correct queue, the following properties should be provided
     * if applicable
     *
     * name, isFifo, separateConsumerGroup, exchangeType
     * @returns The subscribed queue arn for the topic
     */
    getQueueReference(topic: Topic): string;
    /**
     * @param topic A Topic object
     *
     * To get the correct queue, the following properties should be provided
     * if applicable
     *
     * name, isFifo, separateConsumerGroup, exchangeType
     * @returns The subscribed queue internal name for the topic
     */
    getInternalQueueName(topic: Topic): string;
    /**
     * Start consuming the topics
     */
    startConsumers(): Promise<void>;
    /**
     * @return Returns an exact copy of payload handed to aws client for sending.
     */
    getEmitPayload(eventName: string, options?: IEmitOptions, payload?: any): EmitPayload;
    /**
     * @return Returns an exact copy of batch payload handed to aws client for sending.
     */
    getBatchEmitPayload(eventName: string, messages: IBatchMessage[], options?: IBatchEmitOptions): EmitBatchPayload;
    /**
     *
     * @param receivedMessage The message received from the consumer
     * @returns The expected parsed data in the message as provided by the producer
     */
    parseDataFromMessage<T>(receivedMessage: Message): IMessage<T>;
}
export type ISNSMessage = IMessage<any>;
export interface ISNSReceiveMessage {
    Message: string;
    MessageId: string;
    Signature: string;
    SignatureVersion: string;
    SigningCertURL: string;
    Timestamp: string;
    TopicArn: string;
    Type: string;
    UnsubscribeURL: string;
    MessageAttributes: MessageAttributes;
}
export type QueueEmitPayload = SendMessageRequest;
export type FanoutEmitPayload = PublishInput;
export type EmitPayload = QueueEmitPayload | FanoutEmitPayload;
export type EmitBatchPayload = SendMessageBatchRequest | PublishBatchInput;
export interface ICreateQueueLambdaEventSourceInput {
    functionName: string;
    queueARN: string;
    maximumConcurrency?: number;
    batchSize?: number;
}
export declare enum ExchangeType {
    Queue = "Queue",
    Fanout = "Fanout"
}
export declare enum FailedEventCategory {
    MessageProducingFailed = "MessageProducingFailed",
    QueueError = "QueueError",
    QueueProcessingError = "QueueProcessingError",
    QueueStopped = "QueueStopped",
    QueueTimedOut = "QueueTimedOut",
    IncomingMessageFailedToParse = "IncomingMessageFailedToParse",
    NoListenerFound = "NoListenerFound",
    MessageProcessingFailed = "MessageProcessingFailed"
}
export interface MessageDeleteOptions {
    /**
     * The unique ReceiptHandle of the message to delete
     */
    receiptHandle: string;
    /**
     * The url of the queue from which the message is received
     */
    queueUrl: string;
}
export interface ProcessMessageOptions {
    /**
     * Set to true if you want to delete the message after processing
     */
    shouldDeleteMessage?: boolean;
    /**
     * The queue ARN from which the message is received.
     * In case of Lambda, the received messages have the eventSourceARN,
     * so this property is optional. In all other cases, this must be
     * provided
     */
    queueReference?: string;
}
export interface ProcessMessageContext {
    /**
     * @description Uniquely generated for each attempt to process a pulled message
     * and run it through all the listeners
     */
    executionTraceId: string;
    /**
     * @description Unique identifier for this message. Stays consistent across
     * multiple attempts to process it
     */
    messageId?: string;
    /**
     * @description Similar to @see executionTraceId but provided by aws
     */
    receiptHandler?: string;
}
