"use strict";;
const {
    __DEV__
} = require("@apollo/client/utilities/environment");

Object.defineProperty(exports, "__esModule", { value: true });
exports.ApolloClient = void 0;
const graphql_1 = require("graphql");
const rxjs_1 = require("rxjs");
const incremental_1 = require("@apollo/client/incremental");
const link_1 = require("@apollo/client/link");
const environment_1 = require("@apollo/client/utilities/environment");
const internal_1 = require("@apollo/client/utilities/internal");
const invariant_1 = require("@apollo/client/utilities/invariant");
const version_js_1 = require("../version.cjs");
const QueryManager_js_1 = require("./QueryManager.cjs");
let hasSuggestedDevtools = false;
/**
 * This is the primary Apollo Client class. It is used to send GraphQL documents (i.e. queries
 * and mutations) to a GraphQL spec-compliant server over an `ApolloLink` instance,
 * receive results from the server and cache the results in a store. It also delivers updates
 * to GraphQL queries through `Observable` instances.
 */
class ApolloClient {
    link;
    cache;
    /**
     * @deprecated `disableNetworkFetches` has been renamed to `prioritizeCacheValues`.
     */
    disableNetworkFetches;
    set prioritizeCacheValues(value) {
        this.queryManager.prioritizeCacheValues = value;
    }
    /**
     * Whether to prioritize cache values over network results when `query` or `watchQuery` is called.
     * This will essentially turn a `"network-only"` or `"cache-and-network"` fetchPolicy into a `"cache-first"` fetchPolicy,
     * but without influencing the `fetchPolicy` of the created `ObservableQuery` long-term.
     *
     * This can e.g. be used to prioritize the cache during the first render after SSR.
     */
    get prioritizeCacheValues() {
        return this.queryManager.prioritizeCacheValues;
    }
    version;
    queryDeduplication;
    defaultOptions;
    devtoolsConfig;
    queryManager;
    devToolsHookCb;
    resetStoreCallbacks = [];
    clearStoreCallbacks = [];
    /**
     * Constructs an instance of `ApolloClient`.
     *
     * @example
     * ```js
     * import { ApolloClient, InMemoryCache } from '@apollo/client';
     *
     * const cache = new InMemoryCache();
     *
     * const client = new ApolloClient({
     *   // Provide required constructor fields
     *   cache: cache,
     *   uri: 'http://localhost:4000/',
     *
     *   // Provide some optional constructor fields
     *   name: 'react-web-client',
     *   version: '1.3',
     *   queryDeduplication: false,
     *   defaultOptions: {
     *     watchQuery: {
     *       fetchPolicy: 'cache-and-network',
     *     },
     *   },
     * });
     * ```
     */
    constructor(options) {
        if (environment_1.__DEV__) {
            (0, invariant_1.invariant)(options.cache, 66);
            (0, invariant_1.invariant)(options.link, 67);
        }
        const { cache, documentTransform, ssrMode = false, ssrForceFetchDelay = 0, queryDeduplication = true, defaultOptions, defaultContext, assumeImmutableResults = cache.assumeImmutableResults, localState, devtools, dataMasking, link, incrementalHandler = new incremental_1.NotImplementedHandler(), } = options;
        this.link = link;
        this.cache = cache;
        this.queryDeduplication = queryDeduplication;
        this.defaultOptions = defaultOptions || {};
        this.devtoolsConfig = {
            ...devtools,
            enabled: devtools?.enabled ?? environment_1.__DEV__,
        };
        this.watchQuery = this.watchQuery.bind(this);
        this.query = this.query.bind(this);
        this.mutate = this.mutate.bind(this);
        this.watchFragment = this.watchFragment.bind(this);
        this.resetStore = this.resetStore.bind(this);
        this.reFetchObservableQueries = this.reFetchObservableQueries.bind(this);
        this.version = version_js_1.version;
        this.queryManager = new QueryManager_js_1.QueryManager({
            client: this,
            defaultOptions: this.defaultOptions,
            defaultContext,
            documentTransform,
            queryDeduplication,
            ssrMode,
            dataMasking: !!dataMasking,
            clientOptions: options,
            incrementalHandler,
            assumeImmutableResults,
            onBroadcast: this.devtoolsConfig.enabled ?
                () => {
                    if (this.devToolsHookCb) {
                        this.devToolsHookCb();
                    }
                }
                : void 0,
            localState,
        });
        this.prioritizeCacheValues = ssrMode || ssrForceFetchDelay > 0;
        if (ssrForceFetchDelay) {
            setTimeout(() => {
                this.prioritizeCacheValues = false;
            }, ssrForceFetchDelay);
        }
        if (this.devtoolsConfig.enabled)
            this.connectToDevTools();
    }
    connectToDevTools() {
        if (typeof window === "undefined") {
            return;
        }
        const windowWithDevTools = window;
        const devtoolsSymbol = Symbol.for("apollo.devtools");
        (windowWithDevTools[devtoolsSymbol] =
            windowWithDevTools[devtoolsSymbol] || []).push(this);
        windowWithDevTools.__APOLLO_CLIENT__ = this;
        /**
         * Suggest installing the devtools for developers who don't have them
         */
        if (!hasSuggestedDevtools && environment_1.__DEV__) {
            hasSuggestedDevtools = true;
            if (window.document &&
                window.top === window.self &&
                /^(https?|file):$/.test(window.location.protocol)) {
                setTimeout(() => {
                    if (!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__) {
                        const nav = window.navigator;
                        const ua = nav && nav.userAgent;
                        let url;
                        if (typeof ua === "string") {
                            if (ua.indexOf("Chrome/") > -1) {
                                url =
                                    "https://chrome.google.com/webstore/detail/" +
                                        "apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm";
                            }
                            else if (ua.indexOf("Firefox/") > -1) {
                                url =
                                    "https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/";
                            }
                        }
                        if (url) {
                            __DEV__ && invariant_1.invariant.log("Download the Apollo DevTools for a better development " +
                                "experience: %s", url);
                        }
                    }
                }, 10000);
            }
        }
    }
    /**
     * The `DocumentTransform` used to modify GraphQL documents before a request
     * is made. If a custom `DocumentTransform` is not provided, this will be the
     * default document transform.
     */
    get documentTransform() {
        return this.queryManager.documentTransform;
    }
    /**
     * The configured `LocalState` instance used to enable the use of `@client`
     * fields.
     */
    get localState() {
        return this.queryManager.localState;
    }
    set localState(localState) {
        this.queryManager.localState = localState;
    }
    /**
     * Call this method to terminate any active client processes, making it safe
     * to dispose of this `ApolloClient` instance.
     */
    stop() {
        this.queryManager.stop();
    }
    /**
     * This watches the cache store of the query according to the options specified and
     * returns an `ObservableQuery`. We can subscribe to this `ObservableQuery` and
     * receive updated results through an observer when the cache store changes.
     *
     * Note that this method is not an implementation of GraphQL subscriptions. Rather,
     * it uses Apollo's store in order to reactively deliver updates to your query results.
     *
     * For example, suppose you call watchQuery on a GraphQL query that fetches a person's
     * first and last name and this person has a particular object identifier, provided by
     * dataIdFromObject. Later, a different query fetches that same person's
     * first and last name and the first name has now changed. Then, any observers associated
     * with the results of the first query will be updated with a new result object.
     *
     * Note that if the cache does not change, the subscriber will *not* be notified.
     *
     * See [here](https://medium.com/apollo-stack/the-concepts-of-graphql-bc68bd819be3#.3mb0cbcmc) for
     * a description of store reactivity.
     */
    watchQuery(options) {
        if (this.defaultOptions.watchQuery) {
            options = (0, internal_1.mergeOptions)(this.defaultOptions.watchQuery, options);
        }
        return this.queryManager.watchQuery(options);
    }
    /**
     * This resolves a single query according to the options specified and
     * returns a `Promise` which is either resolved with the resulting data
     * or rejected with an error.
     *
     * @param options - An object of type `QueryOptions` that allows us to
     * describe how this query should be treated e.g. whether it should hit the
     * server at all or just resolve from the cache, etc.
     */
    query(options) {
        if (this.defaultOptions.query) {
            options = (0, internal_1.mergeOptions)(this.defaultOptions.query, options);
        }
        if (environment_1.__DEV__) {
            (0, invariant_1.invariant)(options.fetchPolicy !== "cache-and-network", 68);
            (0, invariant_1.invariant)(options.fetchPolicy !== "standby", 69);
            (0, invariant_1.invariant)(options.query, 70);
            (0, invariant_1.invariant)(options.query.kind === "Document", 71);
            (0, invariant_1.invariant)(!options.returnPartialData, 72);
            (0, invariant_1.invariant)(!options.pollInterval, 73);
            (0, invariant_1.invariant)(!options.notifyOnNetworkStatusChange, 74);
        }
        return this.queryManager.query(options);
    }
    /**
     * This resolves a single mutation according to the options specified and returns a
     * Promise which is either resolved with the resulting data or rejected with an
     * error. In some cases both `data` and `errors` might be undefined, for example
     * when `errorPolicy` is set to `'ignore'`.
     *
     * It takes options as an object with the following keys and values:
     */
    mutate(options) {
        const optionsWithDefaults = (0, internal_1.mergeOptions)((0, internal_1.compact)({
            fetchPolicy: "network-only",
            errorPolicy: "none",
        }, this.defaultOptions.mutate), options);
        if (environment_1.__DEV__) {
            (0, invariant_1.invariant)(optionsWithDefaults.mutation, 75);
            (0, invariant_1.invariant)(optionsWithDefaults.fetchPolicy === "network-only" ||
                optionsWithDefaults.fetchPolicy === "no-cache", 76);
        }
        (0, internal_1.checkDocument)(optionsWithDefaults.mutation, graphql_1.OperationTypeNode.MUTATION);
        return this.queryManager.mutate(optionsWithDefaults);
    }
    /**
     * This subscribes to a graphql subscription according to the options specified and returns an
     * `Observable` which either emits received data or an error.
     */
    subscribe(options) {
        const cause = {};
        const observable = this.queryManager.startGraphQLSubscription(options);
        const mapped = observable.pipe((0, rxjs_1.map)((result) => ({
            ...result,
            data: this.queryManager.maskOperation({
                document: options.query,
                data: result.data,
                fetchPolicy: options.fetchPolicy,
                cause,
            }),
        })));
        return Object.assign(mapped, { restart: observable.restart });
    }
    /**
     * Tries to read some data from the store in the shape of the provided
     * GraphQL query without making a network request. This method will start at
     * the root query. To start at a specific id returned by `dataIdFromObject`
     * use `readFragment`.
     *
     * @param optimistic - Set to `true` to allow `readQuery` to return
     * optimistic results. Is `false` by default.
     */
    readQuery(options, optimistic = false) {
        return this.cache.readQuery(options, optimistic);
    }
    /**
     * Watches the cache store of the fragment according to the options specified
     * and returns an `Observable`. We can subscribe to this
     * `Observable` and receive updated results through an
     * observer when the cache store changes.
     *
     * You must pass in a GraphQL document with a single fragment or a document
     * with multiple fragments that represent what you are reading. If you pass
     * in a document with multiple fragments then you must also specify a
     * `fragmentName`.
     *
     * @since 3.10.0
     * @param options - An object of type `WatchFragmentOptions` that allows
     * the cache to identify the fragment and optionally specify whether to react
     * to optimistic updates.
     */
    watchFragment(options) {
        return this.cache.watchFragment({
            ...options,
            [Symbol.for("apollo.dataMasking")]: this.queryManager.dataMasking,
        });
    }
    /**
     * Tries to read some data from the store in the shape of the provided
     * GraphQL fragment without making a network request. This method will read a
     * GraphQL fragment from any arbitrary id that is currently cached, unlike
     * `readQuery` which will only read from the root query.
     *
     * You must pass in a GraphQL document with a single fragment or a document
     * with multiple fragments that represent what you are reading. If you pass
     * in a document with multiple fragments then you must also specify a
     * `fragmentName`.
     *
     * @param optimistic - Set to `true` to allow `readFragment` to return
     * optimistic results. Is `false` by default.
     */
    readFragment(options, optimistic = false) {
        return this.cache.readFragment(options, optimistic);
    }
    /**
     * Writes some data in the shape of the provided GraphQL query directly to
     * the store. This method will start at the root query. To start at a
     * specific id returned by `dataIdFromObject` then use `writeFragment`.
     */
    writeQuery(options) {
        const ref = this.cache.writeQuery(options);
        if (options.broadcast !== false) {
            this.queryManager.broadcastQueries();
        }
        return ref;
    }
    /**
     * Writes some data in the shape of the provided GraphQL fragment directly to
     * the store. This method will write to a GraphQL fragment from any arbitrary
     * id that is currently cached, unlike `writeQuery` which will only write
     * from the root query.
     *
     * You must pass in a GraphQL document with a single fragment or a document
     * with multiple fragments that represent what you are writing. If you pass
     * in a document with multiple fragments then you must also specify a
     * `fragmentName`.
     */
    writeFragment(options) {
        const ref = this.cache.writeFragment(options);
        if (options.broadcast !== false) {
            this.queryManager.broadcastQueries();
        }
        return ref;
    }
    __actionHookForDevTools(cb) {
        this.devToolsHookCb = cb;
    }
    __requestRaw(payload) {
        return (0, link_1.execute)(this.link, payload, { client: this });
    }
    /**
     * Resets your entire store by clearing out your cache and then re-executing
     * all of your active queries. This makes it so that you may guarantee that
     * there is no data left in your store from a time before you called this
     * method.
     *
     * `resetStore()` is useful when your user just logged out. You’ve removed the
     * user session, and you now want to make sure that any references to data you
     * might have fetched while the user session was active is gone.
     *
     * It is important to remember that `resetStore()` *will* refetch any active
     * queries. This means that any components that might be mounted will execute
     * their queries again using your network interface. If you do not want to
     * re-execute any queries then you should make sure to stop watching any
     * active queries.
     */
    resetStore() {
        return Promise.resolve()
            .then(() => this.queryManager.clearStore({
            discardWatches: false,
        }))
            .then(() => Promise.all(this.resetStoreCallbacks.map((fn) => fn())))
            .then(() => this.reFetchObservableQueries());
    }
    /**
     * Remove all data from the store. Unlike `resetStore`, `clearStore` will
     * not refetch any active queries.
     */
    clearStore() {
        return Promise.resolve()
            .then(() => this.queryManager.clearStore({
            discardWatches: true,
        }))
            .then(() => Promise.all(this.clearStoreCallbacks.map((fn) => fn())));
    }
    /**
     * Allows callbacks to be registered that are executed when the store is
     * reset. `onResetStore` returns an unsubscribe function that can be used
     * to remove registered callbacks.
     */
    onResetStore(cb) {
        this.resetStoreCallbacks.push(cb);
        return () => {
            this.resetStoreCallbacks = this.resetStoreCallbacks.filter((c) => c !== cb);
        };
    }
    /**
     * Allows callbacks to be registered that are executed when the store is
     * cleared. `onClearStore` returns an unsubscribe function that can be used
     * to remove registered callbacks.
     */
    onClearStore(cb) {
        this.clearStoreCallbacks.push(cb);
        return () => {
            this.clearStoreCallbacks = this.clearStoreCallbacks.filter((c) => c !== cb);
        };
    }
    /**
     * Refetches all of your active queries.
     *
     * `reFetchObservableQueries()` is useful if you want to bring the client back to proper state in case of a network outage
     *
     * It is important to remember that `reFetchObservableQueries()` *will* refetch any active
     * queries. This means that any components that might be mounted will execute
     * their queries again using your network interface. If you do not want to
     * re-execute any queries then you should make sure to stop watching any
     * active queries.
     * Takes optional parameter `includeStandby` which will include queries in standby-mode when refetching.
     */
    reFetchObservableQueries(includeStandby) {
        return this.queryManager.refetchObservableQueries(includeStandby);
    }
    /**
     * Refetches specified active queries. Similar to "reFetchObservableQueries()" but with a specific list of queries.
     *
     * `refetchQueries()` is useful for use cases to imperatively refresh a selection of queries.
     *
     * It is important to remember that `refetchQueries()` *will* refetch specified active
     * queries. This means that any components that might be mounted will execute
     * their queries again using your network interface. If you do not want to
     * re-execute any queries then you should make sure to stop watching any
     * active queries.
     */
    refetchQueries(options) {
        const map = this.queryManager.refetchQueries(options);
        const queries = [];
        const results = [];
        map.forEach((result, obsQuery) => {
            queries.push(obsQuery);
            results.push(result);
        });
        const result = Promise.all(results);
        // In case you need the raw results immediately, without awaiting
        // Promise.all(results):
        result.queries = queries;
        result.results = results;
        // If you decide to ignore the result Promise because you're using
        // result.queries and result.results instead, you shouldn't have to worry
        // about preventing uncaught rejections for the Promise.all result.
        result.catch((error) => {
            __DEV__ && invariant_1.invariant.debug(77, error);
        });
        return result;
    }
    /**
     * Get all currently active `ObservableQuery` objects, in a `Map` keyed by
     * query ID strings.
     *
     * An "active" query is one that has observers and a `fetchPolicy` other than
     * "standby" or "cache-only".
     *
     * You can include all `ObservableQuery` objects (including the inactive ones)
     * by passing "all" instead of "active", or you can include just a subset of
     * active queries by passing an array of query names or DocumentNode objects.
     */
    getObservableQueries(include = "active") {
        return this.queryManager.getObservableQueries(include);
    }
    /**
     * Exposes the cache's complete state, in a serializable format for later restoration.
     */
    extract(optimistic) {
        return this.cache.extract(optimistic);
    }
    /**
     * Replaces existing state in the cache (if any) with the values expressed by
     * `serializedState`.
     *
     * Called when hydrating a cache (server side rendering, or offline storage),
     * and also (potentially) during hot reloads.
     */
    restore(serializedState) {
        return this.cache.restore(serializedState);
    }
    /**
     * Define a new ApolloLink (or link chain) that Apollo Client will use.
     */
    setLink(newLink) {
        this.link = newLink;
    }
    get defaultContext() {
        return this.queryManager.defaultContext;
    }
    /**
     * @experimental
     * This is not a stable API - it is used in development builds to expose
     * information to the DevTools.
     * Use at your own risk!
     * For more details, see [Memory Management](https://www.apollographql.com/docs/react/caching/memory-management/#measuring-cache-usage)
     *
     * @example
     * ```ts
     * console.log(client.getMemoryInternals())
     * ```
     * Logs output in the following JSON format:
     * @example
     * ```json
     *{
     *  limits:     {
     *    canonicalStringify: 1000,
     *    print: 2000,
     *    'documentTransform.cache': 2000,
     *    'queryManager.getDocumentInfo': 2000,
     *    'PersistedQueryLink.persistedQueryHashes': 2000,
     *    'fragmentRegistry.transform': 2000,
     *    'fragmentRegistry.lookup': 1000,
     *    'fragmentRegistry.findFragmentSpreads': 4000,
     *    'cache.fragmentQueryDocuments': 1000,
     *    'removeTypenameFromVariables.getVariableDefinitions': 2000,
     *    'inMemoryCache.maybeBroadcastWatch': 5000,
     *    'inMemoryCache.executeSelectionSet': 10000,
     *    'inMemoryCache.executeSubSelectedArray': 5000
     *  },
     *  sizes: {
     *    canonicalStringify: 4,
     *    print: 14,
     *    addTypenameDocumentTransform: [
     *      {
     *        cache: 14,
     *      },
     *    ],
     *    queryManager: {
     *      getDocumentInfo: 14,
     *      documentTransforms: [
     *        {
     *          cache: 14,
     *        },
     *        {
     *          cache: 14,
     *        },
     *      ],
     *    },
     *    fragmentRegistry: {
     *      findFragmentSpreads: 34,
     *      lookup: 20,
     *      transform: 14,
     *    },
     *    cache: {
     *      fragmentQueryDocuments: 22,
     *    },
     *    inMemoryCache: {
     *      executeSelectionSet: 4345,
     *      executeSubSelectedArray: 1206,
     *      maybeBroadcastWatch: 32,
     *    },
     *    links: [
     *      {
     *        PersistedQueryLink: {
     *          persistedQueryHashes: 14,
     *        },
     *      },
     *      {
     *        removeTypenameFromVariables: {
     *          getVariableDefinitions: 14,
     *        },
     *      },
     *    ],
     *  },
     * }
     *```
     */
    getMemoryInternals;
}
exports.ApolloClient = ApolloClient;
if (environment_1.__DEV__) {
    ApolloClient.prototype.getMemoryInternals = internal_1.getApolloClientMemoryInternals;
}
//# sourceMappingURL=ApolloClient.cjs.map
