import type { IoDefaultMessages } from './io-default-messages';
import type { IoHelper } from './io-helper';
import type * as make from './message-maker';
import type { Duration } from '../../../payloads/types';
import type { IActionAwareIoHost } from '../io-host';
/**
 * These data fields are automatically added by ending a span
 */
export interface SpanEnd {
    readonly duration: number;
    readonly counters?: Record<string, number>;
}
/**
 * Describes a specific span
 *
 * A span definition is a pair of `IoMessageMaker`s to create a start and end message of the span respectively.
 * It also has a display name, that is used for auto-generated message text when they are not provided.
 */
export interface SpanDefinition<S extends object, E extends SpanEnd> {
    readonly name: string;
    readonly start: make.IoMessageMaker<S>;
    readonly end: make.IoMessageMaker<E>;
}
/**
 * Arguments to the span.end() function
 *
 * `SpanEndArguments<T>` are the fields that a user still needs to supply, it
 * fields in the type `T` that aren't also in `SpanEnd`. `SpanEnd` represents
 * fields that are automatically added by the underlying `end` function.
 *
 * Fields that are already in `SpanEnd` are still rendered as optionals, so you
 * can override them (but you don't have to).
 *
 * - Does the following: fields that are shared between `T` and `SpanEnd` are
 *   made optional, and the rest of the keys of `T` are required.
 *
 * - If `T` is fully subsumed by the `SpanEnd` type, then an object type with
 *   all fields optional, OR 'void' so you can avoid passing an argument at all.
 */
type SpanEndArguments<T> = keyof T extends keyof SpanEnd ? (Pick<Partial<SpanEnd>, keyof T & keyof SpanEnd> | void) : Optional<T, keyof T & keyof SpanEnd>;
/**
 * Used in conditional types to check if a type (e.g. after omitting fields) is an empty object
 * This is needed because counter-intuitive neither `object` nor `{}` represent that.
 */
type EmptyObject = Record<string, never>;
/**
 * Helper type to force a parameter to be not present of the computed type is an empty object
 */
type VoidWhenEmpty<T> = T extends EmptyObject ? void : T;
/**
 * Make some properties optional
 */
type Optional<T, K extends keyof T> = Omit<T, K> & Pick<Partial<T>, K>;
/**
 * Ending the span returns the observed duration
 */
export interface ElapsedTime {
    readonly asMs: number;
    readonly asSec: number;
}
/**
 * A message span that can be ended and read times from
 */
export interface IMessageSpan<E extends SpanEnd> extends IActionAwareIoHost {
    /**
     * An IoHelper wrapped around the span.
     */
    readonly asHelper: IoHelper;
    /**
     * An IoDefaultMessages wrapped around the span.
     */
    readonly defaults: IoDefaultMessages;
    /**
     * Get the time elapsed since the start
     */
    elapsedTime(): Promise<ElapsedTime>;
    /**
     * Sends a simple, generic message with the current timing
     * For more complex intermediate messages, get the `elapsedTime` and use `notify`
     */
    timing(maker: make.IoMessageMaker<Duration>, message?: string): Promise<ElapsedTime>;
    /**
     * End the span with a payload
     */
    end(payload: SpanEndArguments<E>): Promise<ElapsedTime>;
    /**
     * End the span with a message and payload
     */
    end(message: string, payload: SpanEndArguments<E>): Promise<ElapsedTime>;
    /**
     * Increment a counter
     */
    incCounter(name: string, delta?: number): void;
    /**
     * Return a new timer object
     *
     * It will be added into the span data when it's stopped. All open timers are
     * automatically stopped when the span is ended.
     *
     * Timers are ultimately added to the `counters` array with `<name>_ms` and
     * `<name>_cnt` keys.
     */
    startTimer(name: string): ITimer;
}
/**
 * A timer to time an operation in a span.
 */
export interface ITimer {
    stop(): void;
}
/**
 * Helper class to make spans around blocks of work
 *
 * Blocks are enclosed by a start and end message.
 * All messages of the span share a unique id.
 * The end message contains the time passed between start and end.
 */
export declare class SpanMaker<S extends object, E extends SpanEnd> {
    private readonly definition;
    private readonly ioHelper;
    private makeHelper;
    constructor(ioHelper: IoHelper, definition: SpanDefinition<S, E>, makeHelper: (ioHost: IActionAwareIoHost) => IoHelper);
    /**
     * Starts the span and initially notifies the IoHost
     * @returns a message span
     */
    begin(payload: VoidWhenEmpty<S>): Promise<IMessageSpan<E>>;
    begin(message: string, payload: S): Promise<IMessageSpan<E>>;
}
export {};
//# sourceMappingURL=span.d.ts.map