'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var trie = require('@wry/trie');
var utilities = require('../../utilities');
var tslib = require('tslib');
var equality = require('@wry/equality');
var tsInvariant = require('ts-invariant');
var optimism = require('optimism');
require('../../utilities/globals');

var version = "3.14.0-rc.0";

function maybe(thunk) {
    try {
        return thunk();
    }
    catch (_a) { }
}

var global$1 = (maybe(function () { return globalThis; }) ||
    maybe(function () { return window; }) ||
    maybe(function () { return self; }) ||
    maybe(function () { return global; }) ||
maybe(function () {
    return maybe.constructor("return this")();
}));

var prefixCounts = new Map();
function makeUniqueId(prefix) {
    var count = prefixCounts.get(prefix) || 1;
    prefixCounts.set(prefix, count + 1);
    return "".concat(prefix, ":").concat(count, ":").concat(Math.random().toString(36).slice(2));
}

function stringifyForDisplay(value, space) {
    if (space === void 0) { space = 0; }
    var undefId = makeUniqueId("stringifyForDisplay");
    return JSON.stringify(value, function (key, value) {
        return value === void 0 ? undefId : value;
    }, space)
        .split(JSON.stringify(undefId))
        .join("<undefined>");
}

function wrap(fn) {
    return function (message) {
        var args = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            args[_i - 1] = arguments[_i];
        }
        if (typeof message === "number") {
            var arg0 = message;
            message = getHandledErrorMsg(arg0);
            if (!message) {
                message = getFallbackErrorMsg(arg0, args);
                args = [];
            }
        }
        fn.apply(void 0, [message].concat(args));
    };
}
var invariant = Object.assign(function invariant(condition, message) {
    var args = [];
    for (var _i = 2; _i < arguments.length; _i++) {
        args[_i - 2] = arguments[_i];
    }
    if (!condition) {
        tsInvariant.invariant(condition, getHandledErrorMsg(message, args) || getFallbackErrorMsg(message, args));
    }
}, {
    debug: wrap(tsInvariant.invariant.debug),
    log: wrap(tsInvariant.invariant.log),
    warn: wrap(tsInvariant.invariant.warn),
    error: wrap(tsInvariant.invariant.error),
});
var ApolloErrorMessageHandler = Symbol.for("ApolloErrorMessageHandler_" + version);
function stringify(arg) {
    if (typeof arg == "string") {
        return arg;
    }
    try {
        return stringifyForDisplay(arg, 2).slice(0, 1000);
    }
    catch (_a) {
        return "<non-serializable>";
    }
}
function getHandledErrorMsg(message, messageArgs) {
    if (messageArgs === void 0) { messageArgs = []; }
    if (!message)
        return;
    return (global$1[ApolloErrorMessageHandler] &&
        global$1[ApolloErrorMessageHandler](message, messageArgs.map(stringify)));
}
function getFallbackErrorMsg(message, messageArgs) {
    if (messageArgs === void 0) { messageArgs = []; }
    if (!message)
        return;
    return "An error occurred! For more details, see the full error text at https://go.apollo.dev/c/err#".concat(encodeURIComponent(JSON.stringify({
        version: version,
        message: message,
        args: messageArgs.map(stringify),
    })));
}

var slot = new optimism.Slot();
function muteDeprecations(name) {
    var args = [];
    for (var _i = 1; _i < arguments.length; _i++) {
        args[_i - 1] = arguments[_i];
    }
    return slot.withValue.apply(slot, tslib.__spreadArray([Array.isArray(name) ? name : [name]], args, false));
}

var QUERY_REFERENCE_SYMBOL = Symbol.for("apollo.internal.queryRef");
var PROMISE_SYMBOL = Symbol.for("apollo.internal.refPromise");
function wrapQueryRef(internalQueryRef) {
    var _a;
    var ref = (_a = {
            toPromise: function () {
                return getWrappedPromise(ref).then(function () { return ref; });
            }
        },
        _a[QUERY_REFERENCE_SYMBOL] = internalQueryRef,
        _a[PROMISE_SYMBOL] = internalQueryRef.promise,
        _a);
    return ref;
}
function assertWrappedQueryRef(queryRef) {
    invariant(!queryRef || QUERY_REFERENCE_SYMBOL in queryRef, 93);
}
function getWrappedPromise(queryRef) {
    var internalQueryRef = unwrapQueryRef(queryRef);
    return internalQueryRef.promise.status === "fulfilled" ?
        internalQueryRef.promise
        : queryRef[PROMISE_SYMBOL];
}
function unwrapQueryRef(queryRef) {
    return queryRef[QUERY_REFERENCE_SYMBOL];
}
function updateWrappedQueryRef(queryRef, promise) {
    queryRef[PROMISE_SYMBOL] = promise;
}
var OBSERVED_CHANGED_OPTIONS = [
    "canonizeResults",
    "context",
    "errorPolicy",
    "fetchPolicy",
    "refetchWritePolicy",
    "returnPartialData",
];
var InternalQueryReference =  (function () {
    function InternalQueryReference(observable, options) {
        var _this = this;
        this.key = {};
        this.listeners = new Set();
        this.references = 0;
        this.softReferences = 0;
        this.handleNext = this.handleNext.bind(this);
        this.handleError = this.handleError.bind(this);
        this.dispose = this.dispose.bind(this);
        this.observable = observable;
        if (options.onDispose) {
            this.onDispose = options.onDispose;
        }
        this.setResult();
        this.subscribeToQuery();
        var startDisposeTimer = function () {
            var _a;
            if (!_this.references) {
                _this.autoDisposeTimeoutId = setTimeout(_this.dispose, (_a = options.autoDisposeTimeoutMs) !== null && _a !== void 0 ? _a : 30000);
            }
        };
        this.promise.then(startDisposeTimer, startDisposeTimer);
    }
    Object.defineProperty(InternalQueryReference.prototype, "disposed", {
        get: function () {
            return this.subscription.closed;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(InternalQueryReference.prototype, "watchQueryOptions", {
        get: function () {
            return this.observable.options;
        },
        enumerable: false,
        configurable: true
    });
    InternalQueryReference.prototype.reinitialize = function () {
        var observable = this.observable;
        var originalFetchPolicy = this.watchQueryOptions.fetchPolicy;
        var avoidNetworkRequests = originalFetchPolicy === "no-cache" || originalFetchPolicy === "standby";
        try {
            if (avoidNetworkRequests) {
                observable.silentSetOptions({ fetchPolicy: "standby" });
            }
            else {
                muteDeprecations("resetLastResults", function () {
                    return observable.resetLastResults();
                });
                observable.silentSetOptions({ fetchPolicy: "cache-first" });
            }
            this.subscribeToQuery();
            if (avoidNetworkRequests) {
                return;
            }
            observable.resetDiff();
            this.setResult();
        }
        finally {
            observable.silentSetOptions({ fetchPolicy: originalFetchPolicy });
        }
    };
    InternalQueryReference.prototype.retain = function () {
        var _this = this;
        this.references++;
        clearTimeout(this.autoDisposeTimeoutId);
        var disposed = false;
        return function () {
            if (disposed) {
                return;
            }
            disposed = true;
            _this.references--;
            setTimeout(function () {
                if (!_this.references) {
                    _this.dispose();
                }
            });
        };
    };
    InternalQueryReference.prototype.softRetain = function () {
        var _this = this;
        this.softReferences++;
        var disposed = false;
        return function () {
            if (disposed) {
                return;
            }
            disposed = true;
            _this.softReferences--;
            setTimeout(function () {
                if (!_this.softReferences && !_this.references) {
                    _this.dispose();
                }
            });
        };
    };
    InternalQueryReference.prototype.didChangeOptions = function (watchQueryOptions) {
        var _this = this;
        return OBSERVED_CHANGED_OPTIONS.some(function (option) {
            return option in watchQueryOptions &&
                !equality.equal(_this.watchQueryOptions[option], watchQueryOptions[option]);
        });
    };
    InternalQueryReference.prototype.applyOptions = function (watchQueryOptions) {
        var _a = this.watchQueryOptions, currentFetchPolicy = _a.fetchPolicy, currentCanonizeResults = _a.canonizeResults;
        if (currentFetchPolicy === "standby" &&
            currentFetchPolicy !== watchQueryOptions.fetchPolicy) {
            this.initiateFetch(this.observable.reobserve(watchQueryOptions));
        }
        else {
            this.observable.silentSetOptions(watchQueryOptions);
            if (currentCanonizeResults !== watchQueryOptions.canonizeResults) {
                this.result = tslib.__assign(tslib.__assign({}, this.result), this.observable.getCurrentResult());
                this.promise = utilities.createFulfilledPromise(this.result);
            }
        }
        return this.promise;
    };
    InternalQueryReference.prototype.listen = function (listener) {
        var _this = this;
        this.listeners.add(listener);
        return function () {
            _this.listeners.delete(listener);
        };
    };
    InternalQueryReference.prototype.refetch = function (variables) {
        return this.initiateFetch(this.observable.refetch(variables));
    };
    InternalQueryReference.prototype.fetchMore = function (options) {
        return this.initiateFetch(this.observable.fetchMore(options));
    };
    InternalQueryReference.prototype.dispose = function () {
        this.subscription.unsubscribe();
        this.onDispose();
    };
    InternalQueryReference.prototype.onDispose = function () {
    };
    InternalQueryReference.prototype.handleNext = function (result) {
        var _a;
        switch (this.promise.status) {
            case "pending": {
                if (result.data === void 0) {
                    result.data = this.result.data;
                }
                this.result = result;
                (_a = this.resolve) === null || _a === void 0 ? void 0 : _a.call(this, result);
                break;
            }
            default: {
                if (result.data === this.result.data &&
                    result.networkStatus === this.result.networkStatus) {
                    return;
                }
                if (result.data === void 0) {
                    result.data = this.result.data;
                }
                this.result = result;
                this.promise = utilities.createFulfilledPromise(result);
                this.deliver(this.promise);
                break;
            }
        }
    };
    InternalQueryReference.prototype.handleError = function (error) {
        var _a;
        this.subscription.unsubscribe();
        this.subscription = this.observable.resubscribeAfterError(this.handleNext, this.handleError);
        switch (this.promise.status) {
            case "pending": {
                (_a = this.reject) === null || _a === void 0 ? void 0 : _a.call(this, error);
                break;
            }
            default: {
                this.promise = utilities.createRejectedPromise(error);
                this.deliver(this.promise);
            }
        }
    };
    InternalQueryReference.prototype.deliver = function (promise) {
        this.listeners.forEach(function (listener) { return listener(promise); });
    };
    InternalQueryReference.prototype.initiateFetch = function (returnedPromise) {
        var _this = this;
        this.promise = this.createPendingPromise();
        this.promise.catch(function () { });
        returnedPromise
            .then(function () {
            setTimeout(function () {
                var _a;
                if (_this.promise.status === "pending") {
                    _this.result = _this.observable.getCurrentResult();
                    (_a = _this.resolve) === null || _a === void 0 ? void 0 : _a.call(_this, _this.result);
                }
            });
        })
            .catch(function (error) { var _a; return (_a = _this.reject) === null || _a === void 0 ? void 0 : _a.call(_this, error); });
        return returnedPromise;
    };
    InternalQueryReference.prototype.subscribeToQuery = function () {
        var _this = this;
        this.subscription = this.observable
            .filter(function (result) { return !equality.equal(result.data, {}) && !equality.equal(result, _this.result); })
            .subscribe(this.handleNext, this.handleError);
    };
    InternalQueryReference.prototype.setResult = function () {
        var result = this.observable.getCurrentResult(false);
        if (equality.equal(result, this.result)) {
            return;
        }
        this.result = result;
        this.promise =
            (result.data &&
                (!result.partial || this.watchQueryOptions.returnPartialData)) ?
                utilities.createFulfilledPromise(result)
                : this.createPendingPromise();
    };
    InternalQueryReference.prototype.createPendingPromise = function () {
        var _this = this;
        return utilities.wrapPromiseWithState(new Promise(function (resolve, reject) {
            _this.resolve = resolve;
            _this.reject = reject;
        }));
    };
    return InternalQueryReference;
}());

var FragmentReference =  (function () {
    function FragmentReference(client, watchFragmentOptions, options) {
        var _this = this;
        this.key = {};
        this.listeners = new Set();
        this.references = 0;
        this.dispose = this.dispose.bind(this);
        this.handleNext = this.handleNext.bind(this);
        this.handleError = this.handleError.bind(this);
        this.observable = client.watchFragment(watchFragmentOptions);
        if (options.onDispose) {
            this.onDispose = options.onDispose;
        }
        var diff = this.getDiff(client, watchFragmentOptions);
        var startDisposeTimer = function () {
            var _a;
            if (!_this.references) {
                _this.autoDisposeTimeoutId = setTimeout(_this.dispose, (_a = options.autoDisposeTimeoutMs) !== null && _a !== void 0 ? _a : 30000);
            }
        };
        this.promise =
            diff.complete ?
                utilities.createFulfilledPromise(diff.result)
                : this.createPendingPromise();
        this.subscribeToFragment();
        this.promise.then(startDisposeTimer, startDisposeTimer);
    }
    FragmentReference.prototype.listen = function (listener) {
        var _this = this;
        this.listeners.add(listener);
        return function () {
            _this.listeners.delete(listener);
        };
    };
    FragmentReference.prototype.retain = function () {
        var _this = this;
        this.references++;
        clearTimeout(this.autoDisposeTimeoutId);
        var disposed = false;
        return function () {
            if (disposed) {
                return;
            }
            disposed = true;
            _this.references--;
            setTimeout(function () {
                if (!_this.references) {
                    _this.dispose();
                }
            });
        };
    };
    FragmentReference.prototype.dispose = function () {
        this.subscription.unsubscribe();
        this.onDispose();
    };
    FragmentReference.prototype.onDispose = function () {
    };
    FragmentReference.prototype.subscribeToFragment = function () {
        this.subscription = this.observable.subscribe(this.handleNext.bind(this), this.handleError.bind(this));
    };
    FragmentReference.prototype.handleNext = function (result) {
        var _a;
        switch (this.promise.status) {
            case "pending": {
                if (result.complete) {
                    return (_a = this.resolve) === null || _a === void 0 ? void 0 : _a.call(this, result.data);
                }
                this.deliver(this.promise);
                break;
            }
            case "fulfilled": {
                if (equality.equal(this.promise.value, result.data)) {
                    return;
                }
                this.promise =
                    result.complete ?
                        utilities.createFulfilledPromise(result.data)
                        : this.createPendingPromise();
                this.deliver(this.promise);
            }
        }
    };
    FragmentReference.prototype.handleError = function (error) {
        var _a;
        (_a = this.reject) === null || _a === void 0 ? void 0 : _a.call(this, error);
    };
    FragmentReference.prototype.deliver = function (promise) {
        this.listeners.forEach(function (listener) { return listener(promise); });
    };
    FragmentReference.prototype.createPendingPromise = function () {
        var _this = this;
        return utilities.wrapPromiseWithState(new Promise(function (resolve, reject) {
            _this.resolve = resolve;
            _this.reject = reject;
        }));
    };
    FragmentReference.prototype.getDiff = function (client, options) {
        var cache = client.cache;
        var from = options.from, fragment = options.fragment, fragmentName = options.fragmentName;
        var diff = cache.diff(tslib.__assign(tslib.__assign({}, options), { query: cache["getFragmentDoc"](fragment, fragmentName), returnPartialData: true, id: from, optimistic: true }));
        return tslib.__assign(tslib.__assign({}, diff), { result: client["queryManager"].maskFragment({
                fragment: fragment,
                fragmentName: fragmentName,
                data: diff.result,
            }) });
    };
    return FragmentReference;
}());

var SuspenseCache =  (function () {
    function SuspenseCache(options) {
        if (options === void 0) { options = Object.create(null); }
        this.queryRefs = new trie.Trie(utilities.canUseWeakMap);
        this.fragmentRefs = new trie.Trie(utilities.canUseWeakMap);
        this.options = options;
    }
    SuspenseCache.prototype.getQueryRef = function (cacheKey, createObservable) {
        var ref = this.queryRefs.lookupArray(cacheKey);
        if (!ref.current) {
            ref.current = new InternalQueryReference(createObservable(), {
                autoDisposeTimeoutMs: this.options.autoDisposeTimeoutMs,
                onDispose: function () {
                    delete ref.current;
                },
            });
        }
        return ref.current;
    };
    SuspenseCache.prototype.getFragmentRef = function (cacheKey, client, options) {
        var ref = this.fragmentRefs.lookupArray(cacheKey);
        if (!ref.current) {
            ref.current = new FragmentReference(client, options, {
                autoDisposeTimeoutMs: this.options.autoDisposeTimeoutMs,
                onDispose: function () {
                    delete ref.current;
                },
            });
        }
        return ref.current;
    };
    SuspenseCache.prototype.add = function (cacheKey, queryRef) {
        var ref = this.queryRefs.lookupArray(cacheKey);
        ref.current = queryRef;
    };
    return SuspenseCache;
}());

var suspenseCacheSymbol = Symbol.for("apollo.suspenseCache");
function getSuspenseCache(client) {
    var _a;
    if (!client[suspenseCacheSymbol]) {
        client[suspenseCacheSymbol] = new SuspenseCache((_a = client.defaultOptions.react) === null || _a === void 0 ? void 0 : _a.suspense);
    }
    return client[suspenseCacheSymbol];
}

exports.InternalQueryReference = InternalQueryReference;
exports.assertWrappedQueryRef = assertWrappedQueryRef;
exports.getSuspenseCache = getSuspenseCache;
exports.getWrappedPromise = getWrappedPromise;
exports.unwrapQueryRef = unwrapQueryRef;
exports.updateWrappedQueryRef = updateWrappedQueryRef;
exports.wrapQueryRef = wrapQueryRef;
//# sourceMappingURL=internal.cjs.map
