/**
 * {@link Laika | `Laika`} is the place where most of the magic happens.
 * All the operations are routed through its Apollo Link, and Laika can decide what happens to them along the way.
 * By default every connection is passed through and no additional action is taken.
 *
 * If you're using createGlobalLaikaLink, an instance of Laika is by default installed as `laika` property
 * on the global object (most likely `window`), accessible as `window.laika`
 * or simply as `laika`.
 *
 * Key functionality:
 *
 * - {@link Laika.intercept | `laika.intercept()`}:
 *
 *   If you use `jest`, you can think of laika like the `jest` global,
 *   where the equivalent of `jest.fn()` is {@link Laika.intercept | `laika.intercept()`}
 * - {@link Laika.LogApi | `laika.log`}
 *
 *   The other thing laika is responsible for is logging.
 *
 *   Logging functionality is behind a separate API available under {@link Laika.LogApi | `laika.log`}.
 *
 * @packageDocumentation
 * @module Laika
 */
import type { FetchResult, Operation } from '@apollo/client/core';
import { ApolloLink } from '@apollo/client/core';
import type { GenerateCodeOptions } from './codeGenerator';
import type { EventFilterFn, FetchResultSubscriptionObserver, InferResultData, InterceptorFn, ManInTheMiddleFn, Matcher, MatcherObject, NextLink, NoInfer, OnSubscribeCallback, OperationDocument, ResultOrFn, Variables } from './typedefs';
/**
 * Class responsible for managing interceptions.
 * By default a singleton is installed on `globalThis` (usually `window`) under `laika`.
 *
 * Read more in the {@link Laika | module page} or scroll down to see it's functionality.
 *
 * @example
 * ```js
 * laika.log.startLogging();
 * ```
 */
export declare class Laika {
    private readonly referenceName;
    constructor({ referenceName, }?: {
        referenceName?: string;
    });
    /**
     * Provides functionality to intercept, and optionally mock or modify each operation's subscription.
     * The API returned is heavily inspired on jest's mocking functionality (`jest.fn()`)
     * and is described in length here: {@link InterceptApi}.
     *
     * Every interceptor you create should be as specific as needed in a given session.
     * At the very least, ensure the order of creating interceptors is from most specific, to least specific.
     *
     * This is because any operations that are executed by your client will end up
     * being intercepted by the **first** interceptor that matches
     * the constraints of the {@link Matcher}.
     *
     * See [*Pitfalls*](pathname:///docs/pitfalls) for more information.
     *
     * @param matcher Leave undefined if you want to intercept every operation. Otherwise provide either a {@link MatcherFn | matcher function} or a `MatcherObject` with properties like `clientName` and/or a partial set of `variables` that have to match for a given operation to be intercepted.
     * @param connectFutureLinksOrMitmFn If true, future links will still be called (e.g. reach the backend) and return responses. If set to a function, can serve for man-in-the-middle tinkering with the result.
     * @param keepNonSubscriptionConnectionsOpen If true, queries and mutations will behave a little like subscriptions, in that you will be able to fire updates even after the initial response. Experimental.
     * @example
     * ```js
     * const getActiveUsersInterceptor = laika.intercept({
     *   clientName: 'users',
     *   operationName: 'getActiveUsers',
     * });
     * ```
     */
    intercept<TDocument extends OperationDocument<unknown, Variables>>(matcher: MatcherObject & {
        operation: TDocument;
    }, connectFutureLinksOrMitmFn?: (ManInTheMiddleFn | boolean) | undefined, keepNonSubscriptionConnectionsOpen?: boolean): InterceptApi<InferResultData<TDocument>>;
    intercept<TData = unknown>(matcher?: Matcher | undefined, connectFutureLinksOrMitmFn?: (ManInTheMiddleFn | boolean) | undefined, keepNonSubscriptionConnectionsOpen?: boolean): InterceptApi<TData>;
    /**
     * Modify backend (or mocked) responses before they reach subscribers.
     *
     * @param matcher Leave undefined if you want to intercept every operation. Otherwise provide either a {@link MatcherFn | matcher function} or a `MatcherObject` with properties like `clientName` and/or a partial set of `variables` that have to match for a given operation to be intercepted.
     * @param mapFn Mapping function to alter the responses.
     */
    modifyRemote(matcher: Matcher | undefined, mapFn: (result: FetchResult, operation: Operation) => FetchResult): {
        restore: () => void;
    };
    /**
     * Removes every intercept created by this {@link Laika | Laika} instance.
     * Useful in `afterEach` hooks to keep browser and component tests isolated.
     *
     * Restoring intercepts re-enables passthrough for active observers, but existing
     * Apollo subscriptions may still need to be remounted by the test harness before
     * they can be intercepted again with a different scenario.
     */
    mockRestoreAll(): void;
    /**
     * A set of functions that controls logging and recording of all (or selected) operations.
     *
     * Read more on the {@link Laika.LogApi | LogApi} page.
     *
     * @example
     * ```js
     * laika.log.startLogging();
     * ```
     */
    log: LogApi;
    /**
     * Use this function to create an Apollo Link that uses this Laika instance.
     * Useful in unit tests.
     * @param onRequest
     */
    createLink(onRequest?: (operation: Operation, forward: NextLink) => void): ApolloLink;
    /**
     * @internal
     * */
    interceptor: InterceptorFn;
    private readonly behaviors;
    private readonly interceptRestoreFns;
    private readonly unmatchedOperationOptions;
    private readonly cleanupFnPerSubscribeMeta;
    /**
     * @param input
     */
    private getLogFunction;
    /**
     * @param data
     */
    private logSubscribe;
    private loggingMatcher;
    private firstCaptureTimestamp;
    private recording;
    private actionName;
    private isRecording;
}
export declare abstract class LogApi {
    /** @ignore */
    constructor();
    /**
     * Starts logging every matching operation and subscription to the console.
     * If you did not provide a matcher, it will log everything.
     * You will see queries, mutations, and subscription pushes along with their data.
     *
     * ![Example logging output](pathname:///img/example-logging.png)
     */
    startLogging(matcher?: Matcher | undefined): void;
    /**
     * Stops logging to the console.
     */
    stopLogging(): void;
    /**
     * Starts the recording process. Every result will be saved until you run `log.stopRecording()`.
     *
     * ![Example recording output](pathname:///img/example-recording.png)
     *
     * @param startingActionName Name what you are about to do. For example "opening a new ticket".
     * @param matcher A matcher object or function to record only the events that you are interested in, for example `{operationName: 'getColors', clientName: 'backend1'}` will record only `'getColors'` operations.
     */
    startRecording(startingActionName?: string | undefined, matcher?: Matcher | undefined): void;
    /**
     * Pauses recording without clearing what was recorded so far.
     */
    stopRecording(): void;
    /**
     * Resets the recording in preparation of another one.
     */
    resetRecording(): void;
    /**
     * Use this function to mark a new action if recording a sequence of events.
     *
     * These will show up when you generate mock code as comments,
     * so you can more easily orient yourself in it.
     *
     * @param actionName Describe what action you will be performing, e.g. 'opening the ticket'
     * @example
     * ```js
     * log.markAction('opening the ticket');
     * // click around the site
     * log.markAction('changing the assignee');
     * ```
     */
    markAction(actionName: string): void;
    /**
     * Returns a code snippet that will help you reproduce your recording without hitting actual backends.
     * @param eventFilter Optionally provide a function that will only keep the events you are interested in.
     * @param options Optionally provide code generation options to customize the output.
     */
    generateMockCode(eventFilter?: EventFilterFn, options?: GenerateCodeOptions): string;
}
/**
 * This is the mocking API that is returned after running {@link Laika.intercept | `intercept()`} on the {@link Laika | Laika}.
 *
 * The API is chainable, with the exception of `mockRestore()`.
 *
 * Inspired by `jest.fn()`.
 */
export declare abstract class InterceptApi<TData = unknown> {
    /** @ignore */
    constructor();
    /**
     * An array containing the `variables` from subsequent operations that passed through this intercept.
     *
     * Similar to `jest.fn().mock.calls`.
     */
    readonly calls: readonly Variables[];
    /**
     * Sets the mock data that will be used as a default response to intercepted queries and mutations.
     * If used for subscriptions, will push data immediately.
     *
     * Similar to `jest.fn().mockReturnValue(...)`.
     *
     * @param resultOrFn The object to be used as response in the shape of `{result: {}, error: {}, delay?: number}`. Can be a function that takes operation as the first argument and returns that object synchronously or asynchronously. This may be useful when you wish to customize the mocked response based on the variables from the query.
     * @param matcher Refine when this mock will fire with an additional {@link Matcher | matcher} (e.g. only when specific variables are matched).
     * @example
     * Always respond with the mock to all queries/mutations intercepted
     * ```js
     * const intercept = laika.intercept({operationName: 'getUsers'});
     * intercept.mockResult(
     *   {result: {data: {users: [{id: 1, name: 'Mouse'}, {id: 2, name: 'Bamboo'}]}}},
     * );
     * ```
     * @example
     * Respond with an error, but only when the operations's variables contain `{userGroup: 'elephants'}`
     * ```js
     * const intercept = laika.intercept({operationName: 'getUsers'});
     * intercept.mockResult(
     *   {error: new Error(`oops, server blew up from all the elephants stomping!`)},
     *   {variables: {userGroup: 'elephants'}}
     * );
     * ```
     * @example
     * Respond with a customized error based on the variables:
     * ```js
     * const intercept = laika.intercept({operationName: 'getUsers'});
     * intercept.mockResult(
     *   ({variables}) => ({error: new Error(`oops, server blew up from all the ${variables.userGroup} stomping!`)})
     * );
     * ```
     */
    mockResult<TNextData = TData>(resultOrFn: ResultOrFn<NoInfer<TNextData>>, matcher?: Matcher | undefined): InterceptApi<TNextData>;
    /**
     * Sets the mock data that will be used as the *next* response to matching intercepted queries/mutations.
     * If used for subscription operations, will immediately push provided data to the next matching request.
     * Works the same as {@link InterceptApi.mockResult | `mockResult`},
     * except that as soon as a matching result is found in the queue of mocks, it will not be sent again.
     *
     * Can be run multiple times and will send responses in order in which `mockResultOnce` was called.
     *
     * @param resultOrFn The object to be used as response in the shape of `{result: {}, error: {}, delay?: number}`. Can be a function that takes operation as the first argument and returns that object synchronously or asynchronously. This may be useful when you wish to customize the mocked response based on the variables from the query.
     * @param matcher Refine when this mock will fire with an additional {@link Matcher | matcher} (e.g. only when specific variables are matched).
     * @example
     * Respond with the mock to the first intercepted operation with the name `getUsers`,
     * then with a different mock the second time that operation is intercepted.
     * ```js
     * const intercept = laika.intercept({operationName: 'getUsers'});
     * intercept
     *   .mockResultOnce(
     *     {result: {data: {users: [{id: 1, name: 'Mouse'}, {id: 2, name: 'Bamboo'}]}}},
     *   );
     *   .mockResultOnce(
     *     {result: {data: {users: [{id: 9, name: 'Ox'}, {id: 10, name: 'Fox'}]}}},
     *   );
     * ```
     */
    mockResultOnce<TNextData = TData>(resultOrFn: ResultOrFn<NoInfer<TNextData>>, matcher?: Matcher | undefined): InterceptApi<TNextData>;
    /**
     * In case of GraphQL subscriptions, will return synchronously if at least
     * one intercepted subscription is already active.
     * In other cases returns a `Promise` and behaves the same way as {@link InterceptApi.waitForNextSubscription | `waitForNextSubscription()`}.
     */
    waitForActiveSubscription(): Promise<void> | undefined;
    /**
     * Returns a Promise that will resolve when the *next* operation is run.
     * This translates to whenever a query/mutation is run, or whenever the *next* subscription is made.
     */
    waitForNextSubscription(): Promise<{
        operation: Operation;
        observer: FetchResultSubscriptionObserver;
    }>;
    /**
     * Push data to an already active `subscription`-type operation.
     * Will throw if there are no subscribers (e.g. active `useQuery` hooks).
     *
     * Works similarly to {@link InterceptApi.mockResult | `mockResult(...)`}, but the listener
     * is being fed the new data upon execution.
     *
     * Combine with {@link InterceptApi.waitForActiveSubscription | `waitForActiveSubscription()`}
     * to ensure a subscription is active before calling.
     *
     * @param resultOrFn The object to be used as response in the shape of `{result: {}, error: {}, delay?: number}`. Can be a function that takes operation as the first argument and returns that object synchronously or asynchronously. This may be useful when you wish to customize the mocked response based on the variables from the query.
     * @param fireMatcher Refine when this mock will fire with an additional {@link Matcher | matcher} (e.g. only when specific variables are matched).
     * @example
     * Push new information to a live feed:
     * ```js
     * const intercept = laika.intercept({operationName: 'getActiveUsersCount'});
     * await intercept.waitForActiveSubscription();
     * intercept.fireSubscriptionUpdate(
     *   {result: {data: {count: 10}}},
     * );
     * // e.g. assert the count displayed on the page is in fact 10
     * intercept.fireSubscriptionUpdate(
     *   {result: {data: {count: 0}}},
     * );
     * // e.g. assert the page shows "there are no active users currently on the page"
     * ```
     */
    fireSubscriptionUpdate<TNextData = TData>(resultOrFn: ResultOrFn<NoInfer<TNextData>>, fireMatcher?: Matcher): InterceptApi<TNextData>;
    /**
     * Add a callback that will fire every time a component connects to the query (i.e. mounts).
     * You may return a clean-up function which will be run when the query disconnects.
     */
    onSubscribe(callback: OnSubscribeCallback): (() => void) | void;
    /**
     * If you invoke this and do not setup any mocked results, your intercepted queries will not respond,
     * i.e. hang in a "loading" state, until you fire the data event manually
     * (e.g. in a custom callback defined in {@link InterceptApi.onSubscribe `onSubscribe(callback)`}.
     *
     * Does not affect `subscription` operations which will not reach the backend regardless of this setting (unless the `connectFutureLinksOrMitmFn` argument was set).
     *
     * Opposite of {@link InterceptApi.allowNetworkFallback `allowNetworkFallback()`}.
     */
    disableNetworkFallback(): void;
    /**
     * This restores the default behavior: both queries and mutations
     * will be passed to future links (e.g. your backend) and back to the components.
     *
     * Does not affect `subscription` operations which will not reach the backend regardless of this setting (unless the `connectFutureLinksOrMitmFn` argument was set).
     *
     * Opposite of {@link InterceptApi.disableNetworkFallback `disableNetworkFallback()`}.
     */
    allowNetworkFallback(): void;
    /**
     * Resets the mock configuration to its initial state and reenables the intercept if disabled by {@link InterceptApi.mockRestore `mockRestore()`}.
     */
    mockReset(): InterceptApi<TData>;
    /**
     * Removes the intercept completely and re-establishes connectivity in current and _future_ intercepted operations.
     * Note the word _future_. Any connections that were established prior to running this command,
     * will not automatically switch over to other mocks. This will mostly affect subscriptions.
     * Ideally, keep a reference to the original intercept throughout the duration of your session
     * and simply `intercept.reset()` if you need to restore connectivity or setup a different scenario.
     */
    mockRestore(): void;
}
