UNPKG

built.io-browserify

Version:

SDK for Built.io Backend which is compatible with Browserify

1,539 lines (1,419 loc) 49.5 kB
var R = require('ramda'); var when = require('when'); var rawOptions = require('../config'); var Cls = require('./class'); var Upload = require('./upload'); var utility = require('./utilities/utility'); var User = require('./user'); var instanceMethodBuilder = require('./utilities/instanceMethodBuilder')(); var Built = require('./built'); var Role = require('./role'); var Installation = require('./installation'); var UserRoleMapper = require('./user-role-mapper') var Extension = require('./extension'); var Analytics = require('./analytics'); var cookie = require('./session/cookie'); var local_storage = require('./session/local_storage'); var constants = require('./constants'); var restfullAdaptor = require('./adaptors/RestfullAdaptor'); var socketAdaptor = require('./adaptors/SocketAdaptor'); var userMetrics = require('./utilities/user-metrics'); require('./realtime'); // This is so that realtime is included by browserify while browserifying /* Constants */ var ACCESS_TOKEN_COOKIE_NAME = "baccesstoken"; /** @class App @classdesc Represents an application @instance @param {String} apiKey Accepts Application's API key which Built.io Backend uses to identify each application. @param {object} options Accepts Application's Options which Built.io Backend uses (Optional). @description Use this constructor to get an instance of App @example // 'blt5d4sample2633b' is a dummy Application API key // app instance using only apikey var app = Built.App('blt5d4sample2633b'); // Setting options on app instance // currently it only accepts 6 options i.e host, protocol, port, rtHost, rtPort and rtProtocol var app = Built.App('blt5d4sample2633b',{ host: 'api.built.io', port: 443, protocol: 'https' }); @return {App} */ var appCons = module.exports = R.curry(function(options, apiKey, customOptions) { //app Constructor var app = {}; var persistSession = Built.Session[options.persistSession]; if(utility.isObject(apiKey) || !apiKey) throw new Error('Api Key not found'); // Persist session is NONE by default in node envirnoment. if(!utility.isBrowser()) persistSession = Built.Session.NONE; if (options.headers !== undefined) { // User already has an app and is using the same to create a new one app['options'] = options; } else { app['options'] = consOptions( customOptions.host || options.host, utility.isNumber(customOptions.port) && customOptions.port || options.port, customOptions.protocol || options.protocol, customOptions.rtHost || options.rtHost, utility.isNumber(customOptions.rtPort) && customOptions.rtPort || options.rtPort, customOptions.rtProtocol || options.rtProtocol, options.version, options.adaptor, R.mixin( accesstokenAndApiKeyHeaderWrap(options, apiKey), { extension_key: options.extension_key }), persistSession, Built.CachePolicy[options.cachePolicy], options.app_info, options.analyticsConfig, options.socketData, options.isSessionUpdated, options.userJSON, utility.isBoolean(customOptions.isUserMetricsEnabled) ? !!customOptions.isUserMetricsEnabled : options.isUserMetricsEnabled, options.metaData, options.persistRefreshToken ); } /** @memberof App @name Class @description Represents a {@link Class}. */ app.Class = Cls(app,{},{}); app.ClassCons = utility.wrapper(Cls(app, {}), [{}]) utility.copyProperties(app.Class,Cls); var appClsCurriedUser = User(app, app.Class(constants.APP_USER_CLS)); var curriedUser = User(app, app.Class(constants.APP_USER_CLS), {}, {}, {}); var curriedRole = Role(app, app.Class(constants.APP_ROLE_CLS), {}, {}, {}); var curriedInstallation = Installation(app, app.Class(constants.APP_INSTALLATION_CLS), {}, {}, {}); var curriedUpload = Upload(app, {}, {}); var curriedAnalytics = Analytics(app, {}, []); var curriedExtension = Extension(app); var curriedUserRoleMapper = UserRoleMapper(app, app.Class(constants.APP_USER_ROLE_MAPPER), {}, {}, {}); /* Upload constructor is curried only with app instance only as required in realtime */ var appCurriedUpload = Upload(app); /** @memberof App @name User @description Represents a {@link User}. */ app.User = utility.wrapper(curriedUser,[{}]); utility.copyProperties(app.User ,User); app.User.isAuthenticated = User.isAuthenticated(app); app.User.getSession = User.getSession(app); app.User.getCurrentUser = User.getSession(app); app.User.setSession = User.setSession(app); app.User.clearSession = User.clearSession(app); app.User.generateAccessToken = User.generateAccessToken(app); app.User.anyAuth = User.anyAuth(app); app.User.refreshAccessToken = User.refreshAccessToken(app); /** @memberof App @name Upload @description Represents a {@link Upload} */ app.Upload = utility.wrapper(curriedUpload,[{}]); utility.copyProperties(app.Upload ,Upload); app.UploadCons = utility.wrapper(appCurriedUpload,[{},{},{}]); utility.copyProperties(app.UploadCons ,Upload); /** @memberof App @name Role @description Represents a {@link Role} */ app.Role = utility.wrapper(curriedRole,[{}]); utility.copyProperties(app.Role ,Role); app.Role.getRoleQuery = app.Role.getRoleQuery(app); /** @memberof App @name Installation @description Represents a {@link Installation} */ app.Installation = utility.wrapper(curriedInstallation,[{}]); utility.copyProperties(app.Installation,Installation); /** @memberof App @name UserRoleMapper @description Represents a {@link UserRoleMapper} */ app.UserRoleMapper = utility.wrapper(curriedUserRoleMapper, [{}]); utility.copyProperties(app.UserRoleMapper, UserRoleMapper); /** @memberof App @name Extension @description Represents a {@link Extension} */ app.Extension = utility.wrapper(curriedExtension, [null]) utility.copyProperties(app.Extension, Extension); /** * @memberof App * @name Analytics * @description * Represents analytics on Built.io Backend * @example * // 'blt5d4sample2633b' is a dummy Application API key * // Returns an instance of {@link Analytics} * var analytics = Built.App('blt5d4sample2633b').Analytics(); */ app.Analytics = utility.wrapper(curriedAnalytics, [options.analyticsConfig.trackAnonymously, 1, { // Default 'trackAnonymously' for Analytics is same as App's current trackAnonymously static: {}, dynamic: function() { return {} } }]) var newApp = instanceMethodBuilder.build(module.exports, app); installPluginsOnInst(newApp); installPluginsOnCons(newApp); /* We send user metric required by Built.io Backend Analytics module */ newApp.sendUserMetrics(); return newApp; }); /* pluginsHelper is global variable declared in built.js */ function installPluginsOnInst(app){ pluginsHelper.plugins.map(function(plugin){ if(plugin.realtime && plugin.realtime.onAppInstance){ plugin.realtime.onAppInstance(app); } }); }; function installPluginsOnCons(app){ pluginsHelper.plugins.map(function(plugin){ if(plugin.realtime && plugin.realtime.onExtensionsCons){ plugin.realtime.onExtensionsCons(app); } if(plugin.realtime && plugin.realtime.onClassCons){ plugin.realtime.onClassCons(app); } if(plugin.realtime && plugin.realtime.onUploadCons){ plugin.realtime.onUploadCons(app); } if(plugin.realtime && plugin.realtime.onUserCons){ plugin.realtime.onUserCons(app); } if(plugin.realtime && plugin.realtime.onRoleCons){ plugin.realtime.onRoleCons(app); } if(plugin.realtime && plugin.realtime.onInstallationCons){ plugin.realtime.onInstallationCons(app); } }); } var consOptions = module.exports.consOptions = R.curry(function(host, port, protocol, rtHost, rtPort, rtProtocol, version, adaptor, headers, persistSession, cachePolicy, app_info, analyticsConfig, socketData, isSessionUpdated, userJSON, isUserMetricsEnabled, metaData, persistRefreshToken) { //options Constructor return { host : host, port : port, protocol : protocol, rtHost : rtHost, rtPort : rtPort, rtProtocol : rtProtocol, version : version, adaptor : adaptor, headers : headers, persistSession : persistSession, cachePolicy : cachePolicy, app_info : app_info, analyticsConfig : analyticsConfig, socketData : socketData, isSessionUpdated : isSessionUpdated, userJSON : userJSON , isUserMetricsEnabled : isUserMetricsEnabled, metaData : metaData, persistRefreshToken : persistRefreshToken } }); var setAppOptions = module.exports.setAppOptions = function(parameter, value, existingOptions) { var host = existingOptions.host; var port = existingOptions.port; var protocol = existingOptions.protocol; var rtHost = existingOptions.rtHost; var rtPort = existingOptions.rtPort; var rtProtocol = existingOptions.rtProtocol; var version = existingOptions.version; var adaptor = existingOptions.adaptor; var headers = existingOptions.headers; var persistSession = existingOptions.persistSession; var cachePolicy = existingOptions.cachePolicy; var app_info = existingOptions.app_info; var analyticsConfig = existingOptions.analyticsConfig; var socketData = existingOptions.socketData; var isSessionUpdated = existingOptions.isSessionUpdated; var userJSON = existingOptions.userJSON; var isUserMetricsEnabled = existingOptions.isUserMetricsEnabled; var metaData = existingOptions.metaData; var persistRefreshToken = existingOptions.persistRefreshToken; switch(parameter){ case "host": host = value; break; case "port": port = value; break; case "protocol": protocol = value; break; case "rtHost": rtHost = value; break; case "rtPort": rtPort = value; break; case "rtProtocol": rtProtocol = value; break; case "version": version = value; break; case "adaptor": adaptor = value; break; case "headers": headers = value; break; case "persistSession": persistSession = value; break; case "cachePolicy": cachePolicy = value; break; case "app_info": app_info = value; break; case "analyticsConfig": analyticsConfig = value; break; case "socketData": socketData = value; break; case "isSessionUpdated": isSessionUpdated = value; break; case "userJSON": userJSON = value; break; case "isUserMetricsEnabled": isUserMetricsEnabled = value; break; case "metaData": metaData = value; break; case "persistRefreshToken": persistRefreshToken = value; break; } return consOptions(host, port, protocol, rtHost, rtPort, rtProtocol, version, adaptor, headers , persistSession, cachePolicy, app_info, analyticsConfig, socketData, isSessionUpdated, userJSON, isUserMetricsEnabled, metaData, persistRefreshToken); } var getOptions = module.exports.getOptions = R.prop('options'); instanceMethodBuilder.define('getOptions',1); var getOption = module.exports.getOption = function(config, app){ return R.prop(config, getOptions(app)); } instanceMethodBuilder.define('getOption', 2); var setOptions = module.exports.setOptions = R.curry(function(options, app) { return appCons(options, getApiKey(app), {}) // return appCons(options, getApiKey(app)) }); instanceMethodBuilder.define('setOptions', 2); module.exports.setSession = function(userJSON, app) { if (!userJSON.auth.access_token) { throw new Error("Access_token not found in JSON"); } var persistSession = false var newUserJSON = R.cloneDeep(userJSON) /** * When persistRefreshToken is false, we do not maintain the refresh token for the user */ if(!app.getOption('persistRefreshToken')){ delete newUserJSON.auth.refresh_token } if (utility.isBrowser()) { if (app.getOption('persistSession') != Built.Session.NONE) persistSession = true persistSessionInBrowser(newUserJSON, app); } if (app.getOption('persistSession') === Built.Session.MEMORY) { persistSession = true } if (persistSession) { // sequence matters as setAccessToken clears previous userJSON if any exists app.setAccessToken(newUserJSON.auth.access_token); // sets user json in same app instance app.setUserJSON(newUserJSON); } // User logged in, so we send user metric again app.sendUserMetrics(true); Built.Events.trigger('user:save-session'); return app; }; instanceMethodBuilder.define('setSession',2); function persistSessionInBrowser (userJSON,app) { if(Built.Session.COOKIE === getOptions(app).persistSession){ cookie.set(generateSessionKey(getApiKey(app)), JSON.stringify(userJSON.auth)); }else if(Built.Session.LOCAL_STORAGE === getOptions(app).persistSession){ local_storage.set(generateSessionKey(getApiKey(app)),userJSON); } } module.exports.clearSession = function(app){ app.setUserJSON(null); app.removeAccessToken(); if(utility.isBrowser()){ if(Built.Session.COOKIE === getOptions(app).persistSession){ cookie.delete(generateSessionKey(getApiKey(app))); }else if(Built.Session.LOCAL_STORAGE === getOptions(app).persistSession){ local_storage.delete(generateSessionKey(getApiKey(app))); } } // User logged out, so we send user metric again app.sendUserMetrics(true) Built.Events.trigger('user:clear-session'); return app; }; instanceMethodBuilder.define('clearSession',1); module.exports.getSession = function(forceFetch, app){ var persistSession = getOptions(app).persistSession; //Localstorage session is not being updated so we need to force fetch the session for the first time if(!app.isSessionUpdated() || persistSession === Built.Session.NONE) forceFetch = true; if(forceFetch){ app.setSessionUpdate(true); return getSessionHelper(app); } //Checks if user details are present in memory var userJSON = app.getUserJSON(); if(userJSON){ return when(wrapInUserObject(userJSON, app)); } if(persistSession === Built.Session.COOKIE){ var accesstoken try{ accesstoken = JSON.parse(cookie.get(generateSessionKey(getApiKey(app)))).access_token } catch(e){} app = app.setAccessToken(accesstoken); // retrieves access_token from Cookie and sets it app return getSessionHelper(app); }else if(persistSession === Built.Session.LOCAL_STORAGE){ // forceFetch should be false and option should be local storage var deferred = when.defer(); var data = local_storage.get(generateSessionKey(getApiKey(app))); if(data) deferred.resolve(app.Class(constants.APP_USER_CLS).ObjectCons({},{},data,{})); else deferred.reject(); return deferred.promise; } } instanceMethodBuilder.define('getSession',2,[false]); function getSessionHelper(app){ var adaptor = app.options.adaptor; var requestObject = utility.getAdaptorObj('GET',module.exports.getURL(app)+'/application/users/current', module.exports.getHeaders(app),null,null); return adaptor.makeCall(requestObject) .then(function(response){ var userJSON = response.entity.application_user; userJSON["auth"] = getUserAuth(app); app.setSession(userJSON); return wrapInUserObject(userJSON, app); }) } function getUserAuth(app) { var persistSession = app.getOption('persistSession') // Persist session is set to NONE so session should be maintained if (persistSession === Built.Session.NONE) return {access_token: app.getAccessToken()} if (persistSession === Built.Session.MEMORY){ var userJSON = app.getUserJSON() || {} var auth = { access_token: userJSON.auth && userJSON.auth.access_token || app.getAccessToken() } if(userJSON.auth && userJSON.auth.refresh_token) auth["refresh_token"] = userJSON.auth.refresh_token return auth } if(persistSession === Built.Session.COOKIE){ var auth = {} try{ auth = JSON.parse(cookie.get(generateSessionKey(getApiKey(app)))) } catch(e){} return auth }else if(persistSession === Built.Session.LOCAL_STORAGE){ var userJSON = local_storage.get(generateSessionKey(getApiKey(app))); return userJSON.auth } } /** * Refresh the user access_token in backend using refresh_token * @function refreshAccessToken * @instance * @memberof User * @param {String} refresh_token refresh_token of the user * @example * // 'blt5d4sample2633b' is a dummy Application API key * var user = Built.App('blt5d4sample2633b').User(); * return user.refreshAccessToken(refresh_token) * .then(function(user){ * // logged in user * }); * OR * var builtApp = Built.App('blt5d4sample2633b').persistRefreshToken() * var user = builtApp.User(); * return user.refreshAccessToken() * .then(function(user){ * // logged in user * }); * @return {Promise<User>} */ module.exports.refreshAccessToken = function(refresh_token, app) { if(!refresh_token && app.getOption("persistRefreshToken")) { refresh_token = getUserAuth(app).refresh_token } var entity = { "refresh_token" : refresh_token }; var requestObject = utility.getAdaptorObj('POST', module.exports.getURL(app) + '/application/users/refresh_access_token', module.exports.getHeaders(app), entity, null); // return makeCallHelper(app,requestObject); var adaptor = app.options.adaptor; return adaptor.makeCall(requestObject) .then(function(response) { var userJSON = app.getUserJSON() || {} userJSON["auth"] = response.entity.auth var user = wrapInUserObject(userJSON, app); app.setSession(user.toJSON()); // Sets the session with the new user data return user; }); } instanceMethodBuilder.define('refreshAccessToken',2, [""]); module.exports.generateAccessToken = function(query, upsert, updateObject, app) { if(!R.prop('master_key',module.exports.getHeaders(app))) throw new Error('Master key not found in headers'); if(!utility.isQueryInstance(query)) throw new Error('Query instance inappropriate'); if(!utility.isBoolean(upsert)) throw new Error('Upsert argument should be a boolean value'); if(!utility.isObject(updateObject)) throw new Error('Update object inappropriate'); var entity = { "insert" : upsert , "query" : query.getQueryObj(), "application_user": updateObject }; var requestObject = utility.getAdaptorObj('POST', module.exports.getURL(app) + '/application/users/generate_access_token', module.exports.getHeaders(app), entity, null); return makeCallHelper(app,requestObject); } instanceMethodBuilder.define('generateAccessToken',4); function makeCallHelper(app, requestObject) { var adaptor = app.options.adaptor; return adaptor.makeCall(requestObject) .then(function(response) { var user = wrapInUserObject(response.entity.application_user, app); app.setSession(user.toJSON()); // Sets the session with the new user data return user; }); } function wrapInUserObject(object, app){ return wrapInObject(constants.APP_USER_CLS, object, app); } function wrapInObject(classUid, object, app){ return app.Class(classUid).ObjectCons({}, {}, object, {}); } module.exports.anyAuth = function(fnUrl, reqBody, reqHeaders, app){ //For analytics we require device_type to be set on login reqBody.device_type = utility.getDeviceTypeFromUA(); return app.Extension(app.getExtensionKey()) .post(fnUrl, reqBody, reqHeaders) .then(function(response){ var user = app.Class(constants.APP_USER_CLS).ObjectCons({}, {}, response.application_user, {}); app.setSession(user.toJSON()); // Sets the session with the new user data return user; }); } instanceMethodBuilder.define('anyAuth',4); /** * Sets an authentication token in the app header * @memberof App * @function setAccessToken * @param {String} access_token Logged-in user's access_token * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setAccessToken('abc123'); * @return {App} */ var setAccessToken = module.exports.setAccessToken = R.curry(function(access_token,app){ // Persist session is set to NONE so session should be maintained if (app.getOption('persistSession') === Built.Session.NONE) return app var existingHeaders = getHeaders(app); existingHeaders['access_token'] = access_token; app.getOptions().userJSON = null; // previous userJSON object becomes invalid for this new access_token return app; }); instanceMethodBuilder.define('setAccessToken',2); module.exports.setUserJSON = R.curry(function(userJSON,app){ var newOptions = setAppOptions('userJSON', userJSON, getOptions(app)); app.options = newOptions; return app; }); instanceMethodBuilder.define('setUserJSON',2); module.exports.getUserJSON = function (app) { return app.getOption('userJSON'); } instanceMethodBuilder.define('getUserJSON',1); /** * Returns access_token used by the app instance for authentication * @memberof App * @function getAccessToken * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var accesstoken = Built.App('blt5d4sample2633b').getAccessToken() // Returns access_token * @return {String} */ module.exports.getAccessToken = function(app){ return getHeaders(app).access_token; } instanceMethodBuilder.define('getAccessToken',1); /** * Removes authentication token from the app header * @memberof App * @function removeAccessToken * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').removeAccessToken() // Removes access_token from app headers * @return {App} */ module.exports.removeAccessToken = function(app){ var existingHeaders = getHeaders(app); delete existingHeaders['access_token']; return app; }; instanceMethodBuilder.define('removeAccessToken',1); var isAuthenticated = module.exports.isAuthenticated = function(app){ return !!getHeaders(app).access_token; } instanceMethodBuilder.define('isAuthenticated',1); /** * Sets the storage medium that should be used to maintain logged-in user's session. By default SDK tries to store session in Cookie. * @memberof App * @function persistSessionWith * @param {Constant} persistSession Accepts one of the persistance option * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * // Returns an app that would use localstorage to persist sessions * var app = Built.App('blt5d4sample2633b').persistSessionWith(Built.Session.LOCAL_STORAGE); * @return {App} */ module.exports.persistSessionWith = R.curry(function(persistSession,app){ if(persistSession === Built.Session.LOCAL_STORAGE && !localStorageEnabled()){ persistSession = Built.Session.COOKIE; } var existingOptions = getOptions(app); var newOptions = setAppOptions('persistSession', persistSession, existingOptions); var newHeader = R.mixin(accesstokenAndApiKeyHeaderWrap(newOptions,app.getApiKey(app)),existingOptions.headers); newOptions = setAppOptions('headers',newHeader,newOptions); return setOptions(newOptions, app); }); instanceMethodBuilder.define('persistSessionWith',2); function localStorageEnabled() { try { if (!window.localStorage) { throw new Error("Local Storage doesn't exist"); } local_storage.set('builttestkey', 'value'); local_storage.get('builttestkey'); local_storage.delete('builttestkey'); return true; } catch (err) { console.warn("Local storage was downgraded to cookie",err); return false; } } var validateCachePolicy = module.exports.validateCachePolicy = function(policy,app){ return !!Built.CachePolicy[policy]; } instanceMethodBuilder.define('validateCachePolicy',2); /** * Sets the cache policy to be used. By default no data is cached. * @memberof App * @function setCachePolicy * @param {Constant} cache_policy Cache Policy to be used by the application. Default to Built.CachePolicy.ONLY_NETWORK * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * // Returns an app which would use CACHE_ELSE_NETWORK as its cache policy * var app = Built * .App('blt5d4sample2633b') * .setCachePolicy(Built.CachePolicy.CACHE_ELSE_NETWORK); * @return {App} */ module.exports.setCachePolicy = R.curry(function(cachePolicy,app){ if(app.validateCachePolicy(cachePolicy)){ var existingOptions = getOptions(app); var newOptions = setAppOptions('cachePolicy',cachePolicy,existingOptions); var ret = setOptions(newOptions, app); return setOptions(newOptions, app); } else throw new Error('Invalid cache policy'); }); instanceMethodBuilder.define('setCachePolicy',2); /** * Returns the cache policy being followed by the app instance * @memberof App * @function getCachePolicy * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * Built.App('blt5d4sample2633b').getCachePolicy() === Built.CachePolicy.ONLY_NETWORK. * @return {String} */ module.exports.getCachePolicy = function(app){ return getOptions(app).cachePolicy; }; instanceMethodBuilder.define('getCachePolicy',1); /** * Sets a HTTP request header * @memberof App * @function setHeader * @param {String} header The header key * @param {String} value The header value * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setHeader('My-Custom-Header','MyValue'); * @return {App} */ var setHeader = module.exports.setHeader = R.curry(function(header, value, app) { //setHeader var existingOptions = getOptions(app); var newHeader = R.mixin({}, existingOptions.headers); newHeader[header] = value; var newOptions = setAppOptions('headers',newHeader,existingOptions); return setOptions(newOptions, app); }); instanceMethodBuilder.define('setHeader',3); /** * Removes a HTTP request header * @memberof App * @function removeHeader * @param {String} header The header key that needs to be removed * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').removeHeader('My-Custom-Header'); * @return {App} */ var removeHeader = module.exports.removeHeader = R.curry(function(header, app) { var existingOptions = getOptions(app); var newHeader = R.mixin({}, existingOptions.headers); if(header !== 'extension_key') delete newHeader[header]; else newHeader[header] = 'blt_ext_default'; var newOptions = setAppOptions('headers',newHeader,existingOptions); return setOptions(newOptions, app); }); instanceMethodBuilder.define('removeHeader',2); /** * Changes the host config * @memberof App * @function setHost * @param {String} host The host name * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setHost('api.built.io'); * @return {App} */ /* Calls the option constructor with the new host name and passing the result to app constructor */ module.exports.setHost = R.curry(function(host, app) { var existingOptions = getOptions(app); var newOptions = setAppOptions('host',host,existingOptions); /* If host of user metrics is changed we need to force send the user metrics again */ var newApp = setOptions(newOptions, app) newApp.sendUserMetrics(true) return newApp }); instanceMethodBuilder.define('setHost',2); /* Helper functions */ var changeRtOptions = R.curry(function(key, value ,app){ var existingOptions = getOptions(app); var newOptions = setAppOptions(key, value, existingOptions); return setOptions(newOptions, app); }); /** * Use this method to set the host that should be used for realtime connection * @memberof App * @function setRtHost * @param {String} host The host name * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built * .App('blt5d4sample2633b') * .setRtHost('realtime.built.io') * .enableRealtime() * @return {App} */ module.exports.setRtHost = changeRtOptions('rtHost'); instanceMethodBuilder.define('setRtHost',2); /** * Changes the port config * @memberof App * @function setPort * @param {Number} port The port number * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setPort(443); * @return {App} */ module.exports.setPort = R.curry(function(port, app) { if (typeof port !== 'number') { throw new Error('Port number should be number'); } var existingOptions = getOptions(app); var newOptions = setAppOptions('port',port,existingOptions); var newApp = setOptions(newOptions, app) newApp.sendUserMetrics(true) return newApp }); instanceMethodBuilder.define('setPort',2); /** * Changes the port number to be used for realtime connection * @memberof App * @function setRtPort * @param {Number} port The port number * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setRtPort(443); * @return {App} */ module.exports.setRtPort = R.curry(function(port, app){ if (typeof port !== 'number') { throw new Error('Port number should be number'); } return changeRtOptions('rtPort', port, app); }); instanceMethodBuilder.define('setRtPort',2); /** * Sets the protocol to be used. * @memberof App * @function setProtocol * @param {String} protocol The protocol to be used (Protocol should be either http or https) * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setProtocol('https') * @return {App} */ module.exports.setProtocol = R.curry(function(protocol, app) { if (protocol !== 'http' && protocol !== 'https') { throw new Error('Supported protocols are http and https'); } var existingOptions = getOptions(app); var newOptions = setAppOptions('protocol',protocol,existingOptions); var newApp = setOptions(newOptions, app) newApp.sendUserMetrics(true) return newApp }); instanceMethodBuilder.define('setProtocol',2); /** * Use this method to change the protocol that should be used for realtime connection * @memberof App * @function setRtProtocol * @param {String} port The port number * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setRtProtocol('https'); * @return {App} */ module.exports.setRtProtocol = R.curry(function(protocol, app) { if (protocol !== 'http' && protocol !== 'https') { throw new Error('Supported protocols are http and https'); } return changeRtOptions('rtProtocol', protocol, app); }); instanceMethodBuilder.define('setRtProtocol', 2); /** * Sets the extension key for an application * @memberof App * @function setExtensionKey * @param {String} extensionKey The Extension key * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setExtensionKey('bltdb28fsaMplEf1b8'); * @return {App} */ module.exports.setExtensionKey = setHeader('extension_key') instanceMethodBuilder.define('setExtensionKey',2); /** * Gets the extension key for an application * @memberof App * @function getExtensionKey * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setExtensionKey('bltdb28fsaMplEf1b8'); * console.log(app.getExtensionKey()); * @return {String} */ module.exports.getExtensionKey = function(app){ return app.getHeaders().extension_key; } instanceMethodBuilder.define('getExtensionKey',1); /** * Removes the extension key from application * @memberof App * @instance * @function removeExtensionKey * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').removeExtensionKey(); * @return {App} */ module.exports.removeExtensionKey = removeHeader('extension_key'); instanceMethodBuilder.define('removeExtensionKey',1); /** * Sets the master key for an application * @memberof App * @function setMasterKey * @param {String} masterKey The master key * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setMasterKey('bltdb28fsaMplEf1b8'); * @return {App} */ module.exports.setMasterKey = setHeader('master_key') instanceMethodBuilder.define('setMasterKey',2) /** * Sets the application api key * @memberof App * @function setApiKey * @param {String} applicationApiKey The application api key * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App().setApiKey('bltdb28fsaMplEf1b8'); * @return {App} */ module.exports.setApiKey = setHeader('application_api_key') instanceMethodBuilder.define('setApiKey',2) /** * Gets the master key for an application * @memberof App * @function getMasterKey * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setMasterKey('bltdb28fsaMplEf1b8'); * console.log(app.getMasterKey()); * @return {String} */ module.exports.getMasterKey = function(app){ return app.getHeaders().master_key; } instanceMethodBuilder.define('getMasterKey',1); /** * Removes the master key from application * @memberof App * @instance * @function removeMasterKey * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').removeMasterKey(); * @return {App} */ module.exports.removeMasterKey = removeHeader('master_key'); instanceMethodBuilder.define('removeMasterKey',1); /** * Sets the current tenant for this application * @memberof App * @function setTenant * @param {String} tenantUid The tenant uid value * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setTenant('samepl_tenant'); * @return {App} */ module.exports.setTenant = setHeader('tenant_uid') instanceMethodBuilder.define('setTenant',2); /** * Removes the tenant from application * @memberof App * @function removeTenant * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').removeTenant(); * @return {App} */ module.exports.removeTenant = removeHeader('tenant_uid'); instanceMethodBuilder.define('removeTenant',1); /** * Returns the headers set on this instance. * @memberof App * @function getHeaders * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var headers = Built.App('blt5d4sample2633b').getHeaders(); * console.log(headers) * @return {object} */ var getHeaders = module.exports.getHeaders = function(app) { return app.options.headers; } instanceMethodBuilder.define('getHeaders',1); /** * Returns the URL this application instance would use to make a HTTP request to Built.io Backend * @memberof App * @instance * @function getURL * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var url = Built.App('blt5d4sample2633b').getURL(); * console.log(url); * @return {String} */ var getURL = module.exports.getURL = function(app) { var options = getOptions(app); return options.protocol + '://' + options.host + ':' + options.port + '/' + options.version; } instanceMethodBuilder.define('getURL',1); /** * Returns the version of Built.io Backend * @memberof App * @instance * @function getVersion * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var version = Built.App('blt5d4sample2633b').getVersion(); * console.log(version); * @return {String} */ module.exports.getVersion = function(app) { return getOptions(app).version; } instanceMethodBuilder.define('getVersion',1); /** * Sets the version of Built.io Backend you want to communicate to. * @function setVersion * @memberof App * @instance * @param {String} version The version of Built.io Backend * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setVersion('v2'); * console.log(app.getURL()) * @return {App} */ module.exports.setVersion = R.curry(function(version, app) { var existingOptions = getOptions(app); var newOptions = setAppOptions('version',version,existingOptions); return setOptions(newOptions, app); }) instanceMethodBuilder.define('setVersion',2); /* * Built.io Backend supports both RESTful API and Socket connection. * Set the adaptor to 'Built.Adaptor.HTTP' or 'Built.Adaptor.SOCKET' as per you requirements * @function setAdaptor * @memberof App * @instance * @param {String} Adaptor Adaptor to be used for communication. Can be either 'Built.Adaptor.HTTP' or 'Built.Adaptor.SOCKET' * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setAdaptor(Built.Adaptor.HTTP); * @return {App} */ module.exports.setAdaptor = R.curry(function(adaptorPath,app){ var existingOptions = getOptions(app); var adaptor = R.mixin({},require(adaptorPath)); if(adaptorPath === Built.Adaptor.SOCKET){ adaptor.makeCall = adaptor.makeCall(app); // curring the make call method with app instance } var newOptions = setAppOptions('adaptor',adaptor,existingOptions); app.options = newOptions; return app; }); instanceMethodBuilder.define('setAdaptor',2); module.exports.setUserMetrics = R.curry(function(bool, app){ return setOptions(setAppOptions('isUserMetricsEnabled', bool, getOptions(app)), app) }) instanceMethodBuilder.define('setUserMetrics',2); /** * Tracking of user metrics is disabled by default. This method will enable the SDK to track user's information * @function enableUserMetrics * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').enableUserMetrics(); * @return {App} */ module.exports.enableUserMetrics = function(app){ var newApp = app.setUserMetrics(true) newApp.sendUserMetrics() return newApp } instanceMethodBuilder.define('enableUserMetrics', 1); /** * Use this method to disable SDK from tracking user metrics * @function disableUserMetrics * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').disableUserMetrics(); * @return {App} */ module.exports.disableUserMetrics = module.exports.setUserMetrics(false) instanceMethodBuilder.define('disableUserMetrics', 1); module.exports.setSessionUpdate = R.curry(function(isUpdated, app){ var existingOptions = getOptions(app); var newOptions = setAppOptions('isSessionUpdated', isUpdated, existingOptions); app.options = newOptions; return app; }) instanceMethodBuilder.define('setSessionUpdate', 2); module.exports.isSessionUpdated = function(app){ return getOption('isSessionUpdated',app) } instanceMethodBuilder.define('isSessionUpdated', 1); /** * Fetches the application info * @function fetch * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b'); * app.fetch() * .then(function(app){ * console.log(app); * }); * @return {Promise<App>} */ module.exports.fetch = function(app){ var existingOptions = getOptions(app); var adaptor = app.options.adaptor; var url = app.getURL()+"/applications/"+"abc"; // abc is just dummpy data as Built.io Backend now doesn't require uid var requestObject = utility.getAdaptorObj('GET',url, module.exports.getHeaders(app),null,null); return adaptor.makeCall(requestObject) .then(function(response) { response = response.entity.application; var app_info = { name : response.name, uid : response.uid, app_variables : response.application_variables }; return setOptions(setAppOptions('app_info',app_info,existingOptions),app); }); }; instanceMethodBuilder.define('fetch',1); /** * Gets the application name * @function getName * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b') * app.fetch() * .then(function(app){ * app.getName(); * }); * @return {String} */ module.exports.getName = function(app){ return getOptions(app).app_info.name; } instanceMethodBuilder.define('getName',1); /** * Gets the application's api key * @function getApiKey * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b') * app.fetch() * .then(function(app){ * app.getApiKey(); * }); * @return {String} */ var getApiKey = module.exports.getApiKey = function(app){ return getOptions(app).headers.application_api_key; } instanceMethodBuilder.define('getApiKey',1); /** * Gets' the schema of all classes on Built.io Backend * @function fetchApplicationClassesSchema * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b') * app.fetchApplicationClassesSchema() * .then(function(res){ * console.log(res); * }); * @return {object} */ module.exports.fetchApplicationClassesSchema = function(app) { var requestObject = utility.getAdaptorObj('GET',module.exports.getURL(app)+'/classes', module.exports.getHeaders(app),null,null); var adaptor = app.options.adaptor; return adaptor.makeCall(requestObject) } instanceMethodBuilder.define('fetchApplicationClassesSchema',1); /** * Gets the details about the last activities performed on this application * @function getLastActivities * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b') * app.getLastActivities() * .then(function(res){ * console.log(res); * }); * @return {object} */ module.exports.getLastActivities = function(app) { var entity = { only_last_activity:true } var requestObject = utility.getAdaptorObj('GET', module.exports.getURL(app) + '/classes', module.exports.getHeaders(app), entity, null); var adaptor = app.options.adaptor; return adaptor.makeCall(requestObject) } instanceMethodBuilder.define('getLastActivities',1); /** * Gets the application variables * @function getAppVariables * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b') * app.fetch() * .then(function(app){ * app.getAppVariables(); * }); * @return {object} */ module.exports.getAppVariables = function(app){ return getOptions(app).app_info.app_variables; } instanceMethodBuilder.define('getAppVariables',1); /* This method sends user metric when a app is initialized. Mutates the app instance */ module.exports.sendUserMetrics = function(forceSend, app){ var user_uid = ""; var uuid // User metric can be disabled as whole if(!app.getOption('isUserMetricsEnabled')) return // User metrics is already sent. if(app.getOption('metaData').isUserMetricsSent && !forceSend){ return; } // User metrics is stored in cookie or localStorage. if(utility.isBrowser()){ try { uuid = local_storage.get(app.getApiKey()+'_blt_uuid') } catch (err) { uuid = cookie.get(app.getApiKey()+'_blt_uuid') } } // User metrics was already sent before. if(uuid && !forceSend){ return } // We set isUserMetricSent variable to true to indicate that userMetric was sent befor app.getOption('metaData').isUserMetricsSent = true; // Check whether trackAnonymously is true if it is check if user object is avaliable if(!app.getOption('analyticsConfig').trackAnonymously){ var userJSON = app.getOption('userJSON') user_uid = (userJSON && userJSON.uid) || ""; } var entity = { super_properties: userMetrics.generateUserMetrics(app.getApiKey(), user_uid) } var requestObject = utility.getAdaptorObj('POST', module.exports.getURL(app) + '/analytics/user_metrics', module.exports.getHeaders(app), entity, null); var adaptor = app.options.adaptor; return adaptor.makeCall(requestObject) } instanceMethodBuilder.define('sendUserMetrics', 2, [false]); /** * By default, the logged-in user's uid is sent to the server for analysis. To track anaymously, set it to false. This applies on {@link Analytics} module as well. * @function setTrackAnonymously * @memberof App * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * // When trackAnonymously is set to true logged-in user's info isn't logged for analysis * var app = Built.App('blt5d4sample2633b').setTrackAnonymously(true); * @return {object} */ module.exports.setTrackAnonymously = R.curry(function(bool, app){ var existingOptions = R.mixin({}, app.getOptions()); var analyticsConfig = R.mixin({}, existingOptions.analyticsConfig) var metaData = R.mixin({}, existingOptions.metaData) analyticsConfig['trackAnonymously'] = bool var newAnalyticsConfig = setAppOptions('analyticsConfig', analyticsConfig, existingOptions); // trackAnonymously when changed should send user metric call again metaData['isUserMetricsSent'] = false var newOptions = setAppOptions('metaData', analyticsConfig, newAnalyticsConfig); return setOptions(newOptions, app) }); instanceMethodBuilder.define('setTrackAnonymously',2); module.exports.InstallationData = R.curry(function(app) { var newClass = Cls(app, {}, {}, constants.APP_INSTALLATION_CLS); utility.copyProperties(newClass, Cls) return newClass }) instanceMethodBuilder.define('InstallationData', 1) module.exports.ApplicationUser = R.curry(function(app) { var newClass = Cls(app, {}, {}, constants.APP_USER_CLS); utility.copyProperties(newClass, Cls) return newClass }) instanceMethodBuilder.define('ApplicationUser', 1) module.exports.ApplicationUserRole = R.curry(function(app) { var newClass = Cls(app, {}, {}, constants.APP_ROLE_CLS); utility.copyProperties(newClass, Cls) return newClass }) instanceMethodBuilder.define('ApplicationUserRole', 1) module.exports.Uploads = R.curry(function(app) { var newClass = Cls(app, {}, {}, constants.Upload_CLS); utility.copyProperties(newClass, Cls) return newClass }) instanceMethodBuilder.define('Uploads', 1) module.exports.persistRefreshToken = R.curry(function(value, app) { if(!!value && app.getOption('persistSession') == Built.Session.NONE){ throw "Cannot persist refresh_token as Session is set to NONE Storage" } var existingOptions = getOptions(app); var newOptions = setAppOptions('persistRefreshToken',value,existingOptions); var newApp = setOptions(newOptions, app) return newApp }); instanceMethodBuilder.define('persistRefreshToken',2, [true]); function accesstokenAndApiKeyHeaderWrap(options, apiKey) { var appHeaders = {}; appHeaders['application_api_key'] = apiKey; if(utility.isBrowser()){ if(Built.Session.COOKIE === options.persistSession && cookie.get(generateSessionKey(apiKey)) !== ""){ var access_token try { access_token = JSON.parse(cookie.get(generateSessionKey(apiKey))).access_token } catch (error) {} appHeaders['access_token'] = access_token; }else if(Built.Session.LOCAL_STORAGE === options.persistSession && local_storage.get(generateSessionKey(apiKey))){ appHeaders['access_token'] = local_storage.get(generateSessionKey(apiKey)).auth.access_token; } } return appHeaders; } /** * Sets an device id in the app header * @memberof App * @function setDeviceID * @param {String} deviceID Device id of the user device * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').setDeviceID('abc123'); * @return {App} */ var setDeviceID = module.exports.setDeviceID = setHeader('device_id') instanceMethodBuilder.define('setDeviceID',2); /** * Returns device id used by the app instance * @memberof App * @function getDeviceID * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var deviceID = Built.App('blt5d4sample2633b').getDeviceID() // Returns device_id * @return {String} */ module.exports.getDeviceID = function(app){ return getHeaders(app).device_id; } instanceMethodBuilder.define('getDeviceID',1); /** * Removes device id from the app header * @memberof App * @function removeDeviceID * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var app = Built.App('blt5d4sample2633b').removeDeviceID() // Removes device id from app headers * @return {App} */ module.exports.removeDeviceID = removeHeader('device_id'); instanceMethodBuilder.define('removeDeviceID',1); /** * Returns refresh_token used by the app instance * @memberof App * @function getRefreshToken * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * var refreshtoken = Built.App('blt5d4sample2633b').getRefreshToken() // Returns refresh_token * @return {String} */ module.exports.getRefreshToken = function(app){ if(!app.getOption("persistRefreshToken")) return null return getUserAuth(app).refresh_token || null; } instanceMethodBuilder.define('getRefreshToken',1); function generateSessionKey(apiKey){ return ACCESS_TOKEN_COOKIE_NAME + "_" + apiKey; } function headersWrap(h) { return { headers: h }; }