built.io-browserify
Version:
SDK for Built.io Backend which is compatible with Browserify
1,539 lines (1,419 loc) • 49.5 kB
JavaScript
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
};
}