function decodeJWTPayload(token) {
    var _a = token.split('.'), payloadStr = _a[1];
    return JSON.parse(atob(payloadStr));
}
function isExpiredJWT(token) {
    var exp = decodeJWTPayload(token).exp;
    return isExpiredInSeconds(exp || 0, 60); // exp or always, and 1 minute earlier
}
function isExpiredInSeconds(expiredTime, costMore) {
    if (costMore === void 0) { costMore = 0; }
    var time = Math.ceil(new Date().getTime() / 1000) + costMore;
    return time >= expiredTime;
}
// create popup
function createPopup(config) {
    var url = config.url || '/';
    var name = config.name || 'SheetbaseOAuthLogin'; // no space for IE
    var options = config.options || ('location=0,status=0' +
        ',width=' + window.innerWidth +
        ',height=' + window.innerHeight);
    var callback = config.callback || (function () { return true; });
    // launch window
    var oauthWindow = window.open(url, name, options);
    // cackback
    var oauthInterval = window.setInterval(function () {
        if (oauthWindow.closed) {
            window.clearInterval(oauthInterval);
            callback();
        }
    }, 1000);
}
// get app host
function getHost() {
    var host;
    // get from base tag
    // else from window.location.href
    var baseHref = ((document.getElementsByTagName('base')[0] || {})['href'] || '').slice(0, -1);
    if (!!baseHref) {
        host = baseHref;
    }
    else {
        var hrefSplit = window.location.href.split('/').filter(Boolean);
        host = hrefSplit[0] + '//' + hrefSplit[1];
    }
    return host;
}

var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (undefined && undefined.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var User = /** @class */ (function () {
    function User(Api, info, idToken, refreshToken) {
        this.Api = Api;
        this.idToken = idToken;
        this.refreshToken = refreshToken;
        this.setInfo(info);
    }
    User.prototype.setInfo = function (info) {
        var uid = info.uid, providerId = info.providerId, email = info.email, emailVerified = info.emailVerified, createdAt = info.createdAt, lastLogin = info.lastLogin, username = info.username, phoneNumber = info.phoneNumber, displayName = info.displayName, photoURL = info.photoURL, bio = info.bio, url = info.url, address = info.address, additionalData = info.additionalData, claims = info.claims, settings = info.settings, isAnonymous = info.isAnonymous, isNewUser = info.isNewUser;
        this.uid = uid;
        this.providerId = providerId;
        this.email = email;
        this.emailVerified = emailVerified;
        this.createdAt = createdAt;
        this.lastLogin = lastLogin;
        this.username = username;
        this.displayName = displayName;
        this.phoneNumber = phoneNumber;
        this.photoURL = photoURL;
        this.bio = bio;
        this.url = url;
        this.address = address;
        this.additionalData = additionalData;
        this.claims = claims;
        this.settings = settings;
        this.isAnonymous = isAnonymous;
        this.isNewUser = isNewUser;
        return info;
    };
    User.prototype.toJSON = function () {
        var uid = this.uid;
        var providerId = this.providerId;
        var email = this.email;
        var emailVerified = this.emailVerified;
        var createdAt = this.createdAt;
        var lastLogin = this.lastLogin;
        var username = this.username;
        var phoneNumber = this.phoneNumber;
        var displayName = this.displayName;
        var photoURL = this.photoURL;
        var bio = this.bio;
        var url = this.url;
        var address = this.address;
        var additionalData = this.additionalData;
        var claims = this.claims;
        var settings = this.settings;
        var isAnonymous = this.isAnonymous;
        var isNewUser = this.isNewUser;
        return {
            uid: uid,
            providerId: providerId,
            email: email,
            emailVerified: emailVerified,
            createdAt: createdAt,
            lastLogin: lastLogin,
            username: username,
            phoneNumber: phoneNumber,
            displayName: displayName,
            photoURL: photoURL,
            bio: bio,
            url: url,
            address: address,
            additionalData: additionalData,
            claims: claims,
            settings: settings,
            isAnonymous: isAnonymous,
            isNewUser: isNewUser,
        };
    };
    User.prototype.getIdToken = function (forceRefresh) {
        if (forceRefresh === void 0) { forceRefresh = false; }
        return __awaiter(this, void 0, void 0, function () {
            var idToken;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!(isExpiredJWT(this.idToken) || forceRefresh)) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.Api.get('/token', {
                                refreshToken: this.refreshToken,
                            })];
                    case 1:
                        idToken = (_a.sent()).idToken;
                        this.idToken = idToken;
                        _a.label = 2;
                    case 2: return [2 /*return*/, this.idToken];
                }
            });
        });
    };
    User.prototype.getIdTokenResult = function (forceRefresh) {
        if (forceRefresh === void 0) { forceRefresh = false; }
        return __awaiter(this, void 0, void 0, function () {
            var idToken;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.getIdToken(forceRefresh)];
                    case 1:
                        idToken = _a.sent();
                        return [2 /*return*/, decodeJWTPayload(idToken)];
                }
            });
        });
    };
    User.prototype.sendEmailVerification = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!!this.emailVerified) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.Api.put('/oob', {}, {
                                mode: 'verifyEmail',
                                email: this.email,
                            })];
                    case 1: return [2 /*return*/, _a.sent()];
                    case 2: return [2 /*return*/];
                }
            });
        });
    };
    User.prototype.updateProfile = function (profile) {
        return __awaiter(this, void 0, void 0, function () {
            var newInfo;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/user', {}, {
                            profile: profile,
                        })];
                    case 1:
                        newInfo = _a.sent();
                        return [2 /*return*/, this.setInfo(newInfo)];
                }
            });
        });
    };
    User.prototype.setAdditionalData = function (data) {
        return __awaiter(this, void 0, void 0, function () {
            var newInfo;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/user/additional', {}, {
                            additionalData: data,
                        })];
                    case 1:
                        newInfo = _a.sent();
                        return [2 /*return*/, this.setInfo(newInfo)];
                }
            });
        });
    };
    User.prototype.setSettings = function (data) {
        return __awaiter(this, void 0, void 0, function () {
            var newInfo;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/user/settings', {}, {
                            settings: data,
                        })];
                    case 1:
                        newInfo = _a.sent();
                        return [2 /*return*/, this.setInfo(newInfo)];
                }
            });
        });
    };
    User.prototype.setProfilePublicly = function (props) {
        return __awaiter(this, void 0, void 0, function () {
            var newInfo;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/user/publicly', {}, {
                            publicly: props,
                        })];
                    case 1:
                        newInfo = _a.sent();
                        return [2 /*return*/, this.setInfo(newInfo)];
                }
            });
        });
    };
    User.prototype.setProfilePrivately = function (props) {
        return __awaiter(this, void 0, void 0, function () {
            var newInfo;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/user/privately', {}, {
                            privately: props,
                        })];
                    case 1:
                        newInfo = _a.sent();
                        return [2 /*return*/, this.setInfo(newInfo)];
                }
            });
        });
    };
    User.prototype.setUsername = function (username) {
        return __awaiter(this, void 0, void 0, function () {
            var newInfo;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/user/username', {}, {
                            username: username,
                        })];
                    case 1:
                        newInfo = _a.sent();
                        return [2 /*return*/, this.setInfo(newInfo)];
                }
            });
        });
    };
    User.prototype.changePassword = function (currentPassword, newPassword) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/user/password', {}, {
                            currentPassword: currentPassword,
                            newPassword: newPassword,
                        })];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    User.prototype.logout = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.delete('/')];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    User.prototype.delete = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.delete('/cancel', {}, {
                            refreshToken: this.refreshToken,
                        })];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    return User;
}());

var AuthProvider = /** @class */ (function () {
    function AuthProvider(providerId, endpoint, scopes) {
        this.providerId = providerId;
        this.endpoint = endpoint;
        this.scopes = scopes;
    }
    AuthProvider.prototype.addScope = function (scope) {
        this.scopes = this.scopes + ' ' + scope;
    };
    AuthProvider.prototype.setCustomParameters = function (customOAuthParameters) {
        this.customParameters = customOAuthParameters;
    };
    AuthProvider.prototype.url = function (clientId, redirectUri) {
        var params = '';
        if (!!this.customParameters) {
            for (var _i = 0, _a = Object.keys(this.customParameters); _i < _a.length; _i++) {
                var key = _a[_i];
                params += '&' + key + '=' + this.customParameters[key];
            }
        }
        return this.endpoint + '?' +
            "response_type=token&" +
            ("client_id=" + clientId + "&") +
            ("redirect_uri=" + redirectUri + "&") +
            ("scope=" + this.scopes) +
            params;
    };
    return AuthProvider;
}());

var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

function createCommonjsModule(fn, module) {
	return module = { exports: {} }, fn(module, module.exports), module.exports;
}

var pubsub = createCommonjsModule(function (module, exports) {
/**
 * Copyright (c) 2010,2011,2012,2013,2014 Morgan Roderick http://roderick.dk
 * License: MIT - http://mrgnrdrck.mit-license.org
 *
 * https://github.com/mroderick/PubSubJS
 */

(function (root, factory){

    var PubSub = {};
    root.PubSub = PubSub;

    var define = root.define;

    factory(PubSub);

    // AMD support
    if (typeof define === 'function' && define.amd){
        define(function() { return PubSub; });

        // CommonJS and Node.js module support
    } else {
        if (module !== undefined && module.exports) {
            exports = module.exports = PubSub; // Node.js specific `module.exports`
        }
        exports.PubSub = PubSub; // CommonJS module 1.1.1 spec
        module.exports = exports = PubSub; // CommonJS
    }

}(( typeof window === 'object' && window ) || commonjsGlobal, function (PubSub){

    var messages = {},
        lastUid = -1;

    function hasKeys(obj){
        var key;

        for (key in obj){
            if ( obj.hasOwnProperty(key) ){
                return true;
            }
        }
        return false;
    }

    /**
     * Returns a function that throws the passed exception, for use as argument for setTimeout
     * @alias throwException
     * @function
     * @param { Object } ex An Error object
     */
    function throwException( ex ){
        return function reThrowException(){
            throw ex;
        };
    }

    function callSubscriberWithDelayedExceptions( subscriber, message, data ){
        try {
            subscriber( message, data );
        } catch( ex ){
            setTimeout( throwException( ex ), 0);
        }
    }

    function callSubscriberWithImmediateExceptions( subscriber, message, data ){
        subscriber( message, data );
    }

    function deliverMessage( originalMessage, matchedMessage, data, immediateExceptions ){
        var subscribers = messages[matchedMessage],
            callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions,
            s;

        if ( !messages.hasOwnProperty( matchedMessage ) ) {
            return;
        }

        for (s in subscribers){
            if ( subscribers.hasOwnProperty(s)){
                callSubscriber( subscribers[s], originalMessage, data );
            }
        }
    }

    function createDeliveryFunction( message, data, immediateExceptions ){
        return function deliverNamespaced(){
            var topic = String( message ),
                position = topic.lastIndexOf( '.' );

            // deliver the message as it is now
            deliverMessage(message, message, data, immediateExceptions);

            // trim the hierarchy and deliver message to each level
            while( position !== -1 ){
                topic = topic.substr( 0, position );
                position = topic.lastIndexOf('.');
                deliverMessage( message, topic, data, immediateExceptions );
            }
        };
    }

    function messageHasSubscribers( message ){
        var topic = String( message ),
            found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic])),
            position = topic.lastIndexOf( '.' );

        while ( !found && position !== -1 ){
            topic = topic.substr( 0, position );
            position = topic.lastIndexOf( '.' );
            found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic]));
        }

        return found;
    }

    function publish( message, data, sync, immediateExceptions ){
        message = (typeof message === 'symbol') ? message.toString() : message;

        var deliver = createDeliveryFunction( message, data, immediateExceptions ),
            hasSubscribers = messageHasSubscribers( message );

        if ( !hasSubscribers ){
            return false;
        }

        if ( sync === true ){
            deliver();
        } else {
            setTimeout( deliver, 0 );
        }
        return true;
    }

    /**
     * Publishes the message, passing the data to it's subscribers
     * @function
     * @alias publish
     * @param { String } message The message to publish
     * @param {} data The data to pass to subscribers
     * @return { Boolean }
     */
    PubSub.publish = function( message, data ){
        return publish( message, data, false, PubSub.immediateExceptions );
    };

    /**
     * Publishes the the message synchronously, passing the data to it's subscribers
     * @function
     * @alias publishSync
     * @param { String } message The message to publish
     * @param {} data The data to pass to subscribers
     * @return { Boolean }
     */
    PubSub.publishSync = function( message, data ){
        return publish( message, data, true, PubSub.immediateExceptions );
    };

    /**
     * Subscribes the passed function to the passed message. Every returned token is unique and should be stored if you need to unsubscribe
     * @function
     * @alias subscribe
     * @param { String } message The message to subscribe to
     * @param { Function } func The function to call when a new message is published
     * @return { String }
     */
    PubSub.subscribe = function( message, func ){
        if ( typeof func !== 'function'){
            return false;
        }

        message = (typeof message === 'symbol') ? message.toString() : message;

        // message is not registered yet
        if ( !messages.hasOwnProperty( message ) ){
            messages[message] = {};
        }

        // forcing token as String, to allow for future expansions without breaking usage
        // and allow for easy use as key names for the 'messages' object
        var token = 'uid_' + String(++lastUid);
        messages[message][token] = func;
        
        // return token for unsubscribing
        return token;
    };

    /**
     * Subscribes the passed function to the passed message once
     * @function
     * @alias subscribeOnce
     * @param { String } message The message to subscribe to
     * @param { Function } func The function to call when a new message is published
     * @return { PubSub }
     */
    PubSub.subscribeOnce = function( message, func ){
        var token = PubSub.subscribe( message, function(){
            // before func apply, unsubscribe message
            PubSub.unsubscribe( token );
            func.apply( this, arguments );
        });
        return PubSub;
    };

    /**
     * Clears all subscriptions
     * @function
     * @public
     * @alias clearAllSubscriptions
     */
    PubSub.clearAllSubscriptions = function clearAllSubscriptions(){
        messages = {};
    };

    /**
     * Clear subscriptions by the topic
     * @function
     * @public
     * @alias clearAllSubscriptions
     */
    PubSub.clearSubscriptions = function clearSubscriptions(topic){
        var m;
        for (m in messages){
            if (messages.hasOwnProperty(m) && m.indexOf(topic) === 0){
                delete messages[m];
            }
        }
    };

    /**
     * Removes subscriptions
     *
     * - When passed a token, removes a specific subscription.
     *
	 * - When passed a function, removes all subscriptions for that function
     *
	 * - When passed a topic, removes all subscriptions for that topic (hierarchy)
     * @function
     * @public
     * @alias subscribeOnce
     * @param { String | Function } value A token, function or topic to unsubscribe from
     * @example // Unsubscribing with a token
     * var token = PubSub.subscribe('mytopic', myFunc);
     * PubSub.unsubscribe(token);
     * @example // Unsubscribing with a function
     * PubSub.unsubscribe(myFunc);
     * @example // Unsubscribing from a topic
     * PubSub.unsubscribe('mytopic');
     */
    PubSub.unsubscribe = function(value){
        var descendantTopicExists = function(topic) {
                var m;
                for ( m in messages ){
                    if ( messages.hasOwnProperty(m) && m.indexOf(topic) === 0 ){
                        // a descendant of the topic exists:
                        return true;
                    }
                }

                return false;
            },
            isTopic    = typeof value === 'string' && ( messages.hasOwnProperty(value) || descendantTopicExists(value) ),
            isToken    = !isTopic && typeof value === 'string',
            isFunction = typeof value === 'function',
            result = false,
            m, message, t;

        if (isTopic){
            PubSub.clearSubscriptions(value);
            return;
        }

        for ( m in messages ){
            if ( messages.hasOwnProperty( m ) ){
                message = messages[m];

                if ( isToken && message[value] ){
                    delete message[value];
                    result = value;
                    // tokens are unique, so we can just stop here
                    break;
                }

                if (isFunction) {
                    for ( t in message ){
                        if (message.hasOwnProperty(t) && message[t] === value){
                            delete message[t];
                            result = true;
                        }
                    }
                }
            }
        }

        return result;
    };
}));
});
var pubsub_1 = pubsub.publish;
var pubsub_2 = pubsub.subscribe;
var pubsub_3 = pubsub.PubSub;

var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator$1 = (undefined && undefined.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var AuthService = /** @class */ (function () {
    function AuthService(app) {
        var _this = this;
        this.SHEETBASE_USER_CHANGED = 'SHEETBASE_USER_CHANGED';
        this.SHEETBASE_USER_INFO = 'user_info';
        this.SHEETBASE_USER_CREDS = 'user_creds';
        this.currentUser = null;
        this.app = app;
        this.Api = this.app.Api
            .addBeforeHooks(function (data) { return __awaiter$1(_this, void 0, void 0, function () {
            var _a, _b;
            return __generator$1(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        if (!!!this.currentUser) return [3 /*break*/, 2];
                        _a = data.query;
                        _b = 'idToken';
                        return [4 /*yield*/, this.currentUser.getIdToken()];
                    case 1:
                        _a[_b] = _c.sent();
                        _c.label = 2;
                    case 2: return [2 /*return*/, data];
                }
            });
        }); })
            .extend()
            .setEndpoint(this.app.options.authEndpoint || 'auth');
        // initial change state (signin locally)
        setTimeout(function () { return _this.signInWithLocalUser(); }, 1000);
    }
    AuthService.prototype.onAuthStateChanged = function (next) {
        pubsub_2(this.SHEETBASE_USER_CHANGED, function (msg, user) { return next(user); });
    };
    AuthService.prototype.checkActionCode = function (code) {
        return __awaiter$1(this, void 0, void 0, function () {
            return __generator$1(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.get('/oob', { oobCode: code })];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    AuthService.prototype.createUserWithEmailAndPassword = function (email, password) {
        return __awaiter$1(this, void 0, void 0, function () {
            var _a, info, idToken, refreshToken, user;
            return __generator$1(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, this.Api.put('/', {}, {
                            email: email, password: password, offlineAccess: true,
                        })];
                    case 1:
                        _a = _b.sent(), info = _a.info, idToken = _a.idToken, refreshToken = _a.refreshToken;
                        return [4 /*yield*/, this.signIn(info, idToken, refreshToken)];
                    case 2:
                        user = _b.sent();
                        return [2 /*return*/, { user: user }];
                }
            });
        });
    };
    AuthService.prototype.signInWithEmailAndPassword = function (email, password) {
        return __awaiter$1(this, void 0, void 0, function () {
            var user, _a, info, idToken, refreshToken;
            return __generator$1(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (!!!this.currentUser) return [3 /*break*/, 1];
                        user = this.currentUser;
                        return [3 /*break*/, 4];
                    case 1: return [4 /*yield*/, this.Api.post('/', {}, {
                            email: email, password: password, offlineAccess: true,
                        })];
                    case 2:
                        _a = _b.sent(), info = _a.info, idToken = _a.idToken, refreshToken = _a.refreshToken;
                        return [4 /*yield*/, this.signIn(info, idToken, refreshToken)];
                    case 3:
                        user = _b.sent();
                        _b.label = 4;
                    case 4: return [2 /*return*/, { user: user }];
                }
            });
        });
    };
    AuthService.prototype.signInWithCustomToken = function (token) {
        return __awaiter$1(this, void 0, void 0, function () {
            var user, _a, info, idToken, refreshToken;
            return __generator$1(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (!!!this.currentUser) return [3 /*break*/, 1];
                        user = this.currentUser;
                        return [3 /*break*/, 4];
                    case 1: return [4 /*yield*/, this.Api.post('/', {}, {
                            customToken: token, offlineAccess: true,
                        })];
                    case 2:
                        _a = _b.sent(), info = _a.info, idToken = _a.idToken, refreshToken = _a.refreshToken;
                        return [4 /*yield*/, this.signIn(info, idToken, refreshToken)];
                    case 3:
                        user = _b.sent();
                        _b.label = 4;
                    case 4: return [2 /*return*/, { user: user }];
                }
            });
        });
    };
    AuthService.prototype.signInAnonymously = function () {
        return __awaiter$1(this, void 0, void 0, function () {
            var user, _a, info, idToken, refreshToken;
            return __generator$1(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (!!!this.currentUser) return [3 /*break*/, 1];
                        user = this.currentUser;
                        return [3 /*break*/, 4];
                    case 1: return [4 /*yield*/, this.Api.put('/', {}, {
                            offlineAccess: true,
                        })];
                    case 2:
                        _a = _b.sent(), info = _a.info, idToken = _a.idToken, refreshToken = _a.refreshToken;
                        return [4 /*yield*/, this.signIn(info, idToken, refreshToken)];
                    case 3:
                        user = _b.sent();
                        _b.label = 4;
                    case 4: return [2 /*return*/, { user: user }];
                }
            });
        });
    };
    AuthService.prototype.sendPasswordResetEmail = function (email) {
        return __awaiter$1(this, void 0, void 0, function () {
            return __generator$1(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.put('/oob', {}, { mode: 'resetPassword', email: email })];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    AuthService.prototype.verifyPasswordResetCode = function (code) {
        return __awaiter$1(this, void 0, void 0, function () {
            return __generator$1(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.get('/oob', { oobCode: code, mode: 'resetPassword' })];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    AuthService.prototype.confirmPasswordReset = function (code, newPassword) {
        return __awaiter$1(this, void 0, void 0, function () {
            return __generator$1(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.Api.post('/oob', {}, {
                            oobCode: code,
                            mode: 'resetPassword',
                            newPassword: newPassword,
                        })];
                    case 1: return [2 /*return*/, _a.sent()];
                }
            });
        });
    };
    AuthService.prototype.signInWithPopup = function (provider) {
        return __awaiter$1(this, void 0, void 0, function () {
            var providerConfig, clientId, redirectUri;
            var _this = this;
            return __generator$1(this, function (_a) {
                if (!this.currentUser) {
                    providerConfig = !!this.app.options.authProviders ?
                        this.app.options.authProviders[provider.providerId] : null;
                    if (!!providerConfig) {
                        // remember provider
                        this.oauthProvider = provider;
                        // add handler to parent window
                        window['handleOauthResult'] = function (fragment) { return _this.handleOauthResult(fragment); };
                        clientId = providerConfig.clientId, redirectUri = providerConfig.redirectUri;
                        return [2 /*return*/, createPopup({
                                url: provider.url(clientId, redirectUri || (getHost() + '/__/auth/handler')),
                            })];
                    }
                }
                return [2 /*return*/];
            });
        });
    };
    AuthService.prototype.googleAuthProvider = function () {
        return new AuthProvider('google.com', 'https://accounts.google.com/o/oauth2/v2/auth', 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile');
    };
    AuthService.prototype.facebookAuthProvider = function () {
        return new AuthProvider('facebook.com', 'https://www.facebook.com/v3.2/dialog/oauth', 'email');
    };
    AuthService.prototype.signOut = function () {
        return __awaiter$1(this, void 0, void 0, function () {
            return __generator$1(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        this.currentUser = null;
                        // notify user change
                        pubsub_1(this.SHEETBASE_USER_CHANGED, null);
                        // remove user info & id token & refresh token from local
                        return [4 /*yield*/, this.app.Localstorage.remove(this.SHEETBASE_USER_INFO)];
                    case 1:
                        // remove user info & id token & refresh token from local
                        _a.sent();
                        return [4 /*yield*/, this.app.Localstorage.remove(this.SHEETBASE_USER_CREDS)];
                    case 2:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    AuthService.prototype.signIn = function (info, idToken, refreshToken) {
        return __awaiter$1(this, void 0, void 0, function () {
            var uid;
            return __generator$1(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        uid = info.uid;
                        this.currentUser = new User(this.Api, info, idToken, refreshToken);
                        // notify user change
                        pubsub_1(this.SHEETBASE_USER_CHANGED, this.currentUser);
                        // save user info & id token & refresh token to local
                        return [4 /*yield*/, this.app.Localstorage.set(this.SHEETBASE_USER_INFO, info)];
                    case 1:
                        // save user info & id token & refresh token to local
                        _a.sent();
                        return [4 /*yield*/, this.app.Localstorage.set(this.SHEETBASE_USER_CREDS, { uid: uid, idToken: idToken, refreshToken: refreshToken })];
                    case 2:
                        _a.sent();
                        return [2 /*return*/, this.currentUser];
                }
            });
        });
    };
    AuthService.prototype.signInWithLocalUser = function () {
        return __awaiter$1(this, void 0, void 0, function () {
            var creds, info, idToken, beenSeconds, expiredUser;
            return __generator$1(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.app.Localstorage.get(this.SHEETBASE_USER_CREDS)];
                    case 1:
                        creds = _a.sent();
                        return [4 /*yield*/, this.app.Localstorage.get(this.SHEETBASE_USER_INFO)];
                    case 2:
                        info = _a.sent();
                        if (!(!!creds && !!info && creds.uid === info.uid)) return [3 /*break*/, 7];
                        idToken = creds.idToken;
                        beenSeconds = (new Date().getTime() - new Date(info.lastLogin).getTime()) / 1000;
                        if (!(beenSeconds > 86400)) return [3 /*break*/, 6];
                        if (!isExpiredJWT(idToken)) return [3 /*break*/, 4];
                        expiredUser = new User(this.Api, info, idToken, creds.refreshToken);
                        return [4 /*yield*/, expiredUser.getIdToken()];
                    case 3:
                        idToken = _a.sent();
                        _a.label = 4;
                    case 4: return [4 /*yield*/, this.Api.get('/user', { idToken: idToken })];
                    case 5:
                        // fetch new info
                        info = _a.sent();
                        _a.label = 6;
                    case 6:
                        // sign user in
                        this.signIn(info, idToken, creds.refreshToken);
                        return [3 /*break*/, 8];
                    case 7:
                        // notify initial state changed
                        pubsub_1(this.SHEETBASE_USER_CHANGED, null);
                        _a.label = 8;
                    case 8: return [2 /*return*/];
                }
            });
        });
    };
    AuthService.prototype.handleOauthResult = function (result) {
        return __awaiter$1(this, void 0, void 0, function () {
            var query, credential, i, _a, key, _b, value, finalValue;
            return __generator$1(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        if (!(result !== '')) return [3 /*break*/, 3];
                        query = result.substr(1).split('&');
                        credential = {};
                        for (i = 0; i < query.length; i++) {
                            _a = query[i].split('='), key = _a[0], _b = _a[1], value = _b === void 0 ? null : _b;
                            finalValue = value;
                            if (key === 'scope') {
                                finalValue = value.split('%20');
                            }
                            else if (key === 'expires_in') {
                                finalValue = +value;
                            }
                            credential[key] = finalValue;
                        }
                        if (!!credential.access_token) return [3 /*break*/, 1];
                        throw new Error('Sheetbase oauth error!'); // no access token
                    case 1: return [4 /*yield*/, this.processOauthResult(credential)];
                    case 2: return [2 /*return*/, _c.sent()];
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    AuthService.prototype.processOauthResult = function (credential) {
        return __awaiter$1(this, void 0, void 0, function () {
            var accessToken, providerId, _a, info, idToken, refreshToken, user;
            return __generator$1(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        accessToken = credential.access_token;
                        providerId = this.oauthProvider.providerId;
                        return [4 /*yield*/, this.Api.get('/oauth', { providerId: providerId, accessToken: accessToken })];
                    case 1:
                        _a = _b.sent(), info = _a.info, idToken = _a.idToken, refreshToken = _a.refreshToken;
                        return [4 /*yield*/, this.signIn(info, idToken, refreshToken)];
                    case 2:
                        user = _b.sent();
                        return [2 /*return*/, { user: user }];
                }
            });
        });
    };
    return AuthService;
}());

function auth(app) {
    // get the default app
    if (!app) {
        if (!window['$$$SHEETBASE_APPS']) {
            throw new Error('No app for auth component.');
        }
        app = window['$$$SHEETBASE_APPS'].getApp();
    }
    // return the instance
    if (!!app.Auth) {
        return app.Auth;
    }
    else {
        return new AuthService(app);
    }
}
window['$$$SHEETBASE_COMPONENTS'].Auth = AuthService;

export { AuthService as Auth, AuthProvider, User, auth };
//# sourceMappingURL=sheetbase-auth.js.map
