facebook-nodejs-business-sdk
Version:
SDK for the Facebook Marketing API in Javascript and Node.js
1,864 lines (1,572 loc) • 1.95 MB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var fs = _interopDefault(require('fs'));
var path = _interopDefault(require('path'));
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
// HTTP Status Code
var HTTP_STATUS = {
OK: '200',
NOT_MODIFIED: '304'
};
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var asyncToGenerator = function (fn) {
return function () {
var gen = fn.apply(this, arguments);
return new Promise(function (resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(function (value) {
step("next", value);
}, function (err) {
step("throw", err);
});
}
}
return step("next");
});
};
};
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var get$1 = function get$1(object, property, receiver) {
if (object === null) object = Function.prototype;
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get$1(parent, property, receiver);
}
} else if ("value" in desc) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
var inherits = function (subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
};
var possibleConstructorReturn = function (self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
};
var set$1 = function set$1(object, property, value, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent !== null) {
set$1(parent, property, value, receiver);
}
} else if ("value" in desc && desc.writable) {
desc.value = value;
} else {
var setter = desc.set;
if (setter !== undefined) {
setter.call(receiver, value);
}
}
return value;
};
var toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
} else {
return Array.from(arr);
}
};
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
var axios = require("axios");
/**
* Isomorphic Http Promise Requests Class
*
*/
var Http = function () {
function Http() {
classCallCheck(this, Http);
}
createClass(Http, null, [{
key: 'request',
/**
* Request
* @param {String} method
* @param {String} url
* @param {Object} [data]
* @return {Promise}
*/
value: function request(method, url, data, files, useMultipartFormData, showHeader) {
if (typeof window !== 'undefined' && window.XMLHttpRequest) {
return Http.xmlHttpRequest(method, url, data);
}
return Http.requestPromise(method, url, data, files, useMultipartFormData, showHeader);
}
/**
* XmlHttpRequest request
* @param {String} method
* @param {String} url
* @param {Object} [data]
* @return {Promise}
*/
}, {
key: 'xmlHttpRequest',
value: function xmlHttpRequest(method, url, data) {
return new Promise(function (resolve, reject) {
var request = new window.XMLHttpRequest();
request.open(method, url);
request.onload = function () {
try {
var response = JSON.parse(request.response);
if (request.status.toString() === HTTP_STATUS.OK) {
resolve(response);
} else {
reject(new Error({
body: response,
status: request.status
}));
}
} catch (e) {
reject(new Error({
body: request.responseText,
status: request.status
}));
}
};
request.setRequestHeader('Content-Type', 'application/json');
request.setRequestHeader('Accept', 'application/json');
request.send(JSON.stringify(data));
});
}
/**
* Request Promise
* @param {String} method The HTTP method name (e.g. 'GET').
* @param {String} url A full URL string.
* @param {Object} [data] A mapping of request parameters where a key
* is the parameter name and its value is a string or an object
* which can be JSON-encoded.
* @param {Object} [files] An optional mapping of file names to ReadStream
* objects. These files will be attached to the request.
* @param {Boolean} [useMultipartFormData] An optional flag to call with
* multipart/form-data.
* @return {Promise}
*/
}, {
key: 'requestPromise',
value: function requestPromise(method, url, data, files) {
var useMultipartFormData = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
var showHeader = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
var options = {
method: method,
url: url,
baseURL: FacebookAdsApi.GRAPH,
json: !useMultipartFormData,
headers: { 'User-Agent': 'fbbizsdk-nodejs-v' + FacebookAdsApi.SDK_VERSION },
data: Object,
resolveWithFullResponse: showHeader
};
// Prevent null or undefined input
// because it can be merged with the files argument later
if (!data) {
data = {};
}
options.data = data;
// Handle file attachments if provided
if (useMultipartFormData || files && Object.keys(files).length > 0) {
// Use formData instead of body (required by the request-promise library)
options.data = Object.assign(data, files);
delete options.data;
}
return axios(options).catch(function (response) {
throw response;
});
}
}]);
return Http;
}();
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
// request-promise error types
function FacebookError(error) {
this.name = 'FacebookError';
this.message = error.message;
this.stack = new Error().stack;
}
FacebookError.prototype = Object.create(Error.prototype);
FacebookError.prototype.constructor = FacebookError;
/**
* Raised when an api request fails.
*/
var FacebookRequestError = function (_FacebookError) {
inherits(FacebookRequestError, _FacebookError);
/**
* @param {[Object} response
* @param {String} method
* @param {String} url
* @param {Object} data
*/
function FacebookRequestError(response, method, url, data) {
classCallCheck(this, FacebookRequestError);
var errorResponse = constructErrorResponse(response);
var _this = possibleConstructorReturn(this, (FacebookRequestError.__proto__ || Object.getPrototypeOf(FacebookRequestError)).call(this, errorResponse));
_this.name = 'FacebookRequestError';
_this.message = errorResponse.message;
_this.status = errorResponse.status;
_this.response = errorResponse.body;
_this.headers = errorResponse.headers;
_this.method = method;
_this.url = url;
if (data) {
_this.data = data;
}
return _this;
}
return FacebookRequestError;
}(FacebookError);
/**
* Error response has several structures depended on called APIs or errors.
* This method contructs and formats the response into the same structure for
* creating a FacebookRequestError object.
*/
function constructErrorResponse(response) {
var body = void 0;
var message = void 0;
var status = void 0;
var headers = void 0;
// Batch request error contains code and body fields
var isBatchResponse = response.code && response.body;
if (isBatchResponse) {
// Handle batch response
body = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
status = response.code;
message = body.error.message;
headers = response.headers;
} else {
// Handle single response
if (response.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
body = response.response.data.error ? response.response.data.error : response.response.data;
body = typeof body === 'string' ? JSON.parse(body) : body;
message = body.message;
status = response.response.status;
headers = response.response.headers;
} else if (response.request) {
body = null;
message = "The request was made but no response was received";
status = null;
headers = null;
} else {
body = null;
message = "Something happened in setting up the request that triggered an Error";
status = null;
headers = null;
}
}
return { body: body, message: message, status: status, headers: headers };
}
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
var CrashReporter = function () {
function CrashReporter() {
classCallCheck(this, CrashReporter);
this._active = true;
}
createClass(CrashReporter, null, [{
key: 'enable',
value: function enable() {
var _this = this;
if (this._instance == undefined || this._instance == null) {
this._instance = new this();
process.on('uncaughtException', function (err) {
if (_this._instance._active && err instanceof Error) {
var params = privateMethods.parseParam(err);
if (params != null) {
console.log('CrashReporter: SDK crash detected!');
privateMethods.processUncaughtException(err, params);
return;
}
}
console.log('CrashReporter: No SDK crash detected or crash reporter is disabled!');
throw err;
});
}
}
}, {
key: 'disable',
value: function disable() {
if (this._instance == undefined || this._instance == null) {
return;
}
this._instance._active = false;
}
}]);
return CrashReporter;
}();
var privateMethods = {
processUncaughtException: function processUncaughtException(err, params) {
FacebookAdsApi.getDefaultApi().getAppID().then(function (data) {
if (data["data"] !== undefined && data['data']['app_id'] !== undefined) {
var appID = data['data']['app_id'];
console.log("active uncaughtException : " + appID);
var url = [FacebookAdsApi.GRAPH, FacebookAdsApi.VERSION, appID, 'instruments'].join('/');
Http.request('POST', url, params).then(function (response) {
console.log('Successfully sent crash report.');
}).catch(function (response) {
console.log('Failed to send crash report.');
}).then(function () {
throw err;
});
}
}).catch(function (error) {
console.log("Not be able to find appID, fail to send report to server.");
throw err;
});
},
parseParam: function parseParam(err) {
var stack = err.stack.split('\n');
var params = {};
if (stack.length == 0) {
return null;
}
var fln = stack[0].split(':');
params['reason'] = fln[0];
params['callstack'] = stack;
params['platform'] = process.version;
for (var i = 0; i < stack.length; i++) {
if (stack[i].includes('facebook-nodejs-business-sdk')) {
return { 'bizsdk_crash_report': params };
}
}
return null;
}
};
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
/**
* Facebook Ads API
*/
var FacebookAdsApi = function () {
createClass(FacebookAdsApi, null, [{
key: 'VERSION',
get: function get() {
return 'v20.0';
}
}, {
key: 'SDK_VERSION',
get: function get() {
return '20.0.3';
}
}, {
key: 'GRAPH',
get: function get() {
return 'https://graph.facebook.com';
}
}, {
key: 'GRAPH_VIDEO',
get: function get() {
return 'https://graph-video.facebook.com';
}
/**
* @param {String} accessToken
* @param {String} [locale]
*/
}]);
function FacebookAdsApi(accessToken) {
var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en_US';
var crash_log = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
classCallCheck(this, FacebookAdsApi);
if (!accessToken) {
throw new Error('Access token required');
}
this.accessToken = accessToken;
this.locale = locale;
this._debug = false;
this._showHeader = false;
if (crash_log) {
CrashReporter.enable();
}
}
/**
* Instantiate an API and store it as the default
* @param {String} accessToken
* @param {String} [locale]
* @return {FacebookAdsApi}
*/
createClass(FacebookAdsApi, [{
key: 'getAppID',
value: function getAppID() {
var url = [FacebookAdsApi.GRAPH, FacebookAdsApi.VERSION, 'debug_token'].join('/');
var params = {};
params['access_token'] = this.accessToken;
params['input_token'] = this.accessToken;
params['fields'] = 'app_id';
url += '?' + FacebookAdsApi._encodeParams(params);
return Http.request('GET', url, {}, {}, false);
}
}, {
key: 'setDebug',
value: function setDebug(flag) {
this._debug = flag;
return this;
}
}, {
key: 'setShowHeader',
value: function setShowHeader(flag) {
this._showHeader = flag;
return this;
}
/**
* Http Request
* @param {String} method
* @param {String} path
* @param {Object} [params]
* @param {Object} [files]
* @return {Promise}
*/
}, {
key: 'call',
value: function call(method, path$$1) {
var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var files = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var _this = this;
var useMultipartFormData = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
var urlOverride = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : '';
var url = void 0;
var data = {};
if (method === 'POST' || method === 'PUT') {
data = params;
params = {};
}
var domain = urlOverride || FacebookAdsApi.GRAPH;
if (typeof path$$1 !== 'string' && !(path$$1 instanceof String)) {
url = [domain, FacebookAdsApi.VERSION].concat(toConsumableArray(path$$1)).join('/');
params['access_token'] = this.accessToken;
url += '?' + FacebookAdsApi._encodeParams(params);
} else {
url = path$$1;
}
var strUrl = url;
return Http.request(method, strUrl, data, files, useMultipartFormData, this._showHeader).then(function (response) {
if (_this._showHeader) {
response.data['headers'] = response.headers;
}
response = response.data;
if (_this._debug) {
console.log('200 ' + method + ' ' + url + ' ' + (Object.keys(data).length > 0 ? JSON.stringify(data) : ""));
console.log('Response: ' + (response ? JSON.stringify(response) : ""));
}
return Promise.resolve(response);
}).catch(function (response) {
if (_this._debug && response.response) {
console.log(response.response.status + ' ' + method + ' ' + url + '\n ' + (Object.keys(data).length > 0 ? JSON.stringify(data) : ''));
}
throw new FacebookRequestError(response, method, url, data);
});
}
}], [{
key: 'init',
value: function init(accessToken) {
var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en_US';
var crash_log = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var api = new this(accessToken, locale, crash_log);
this.setDefaultApi(api);
return api;
}
}, {
key: 'setDefaultApi',
value: function setDefaultApi(api) {
this._defaultApi = api;
}
}, {
key: 'getDefaultApi',
value: function getDefaultApi() {
return this._defaultApi;
}
}, {
key: '_encodeParams',
value: function _encodeParams(params) {
return Object.keys(params).map(function (key) {
var param = params[key];
if ((typeof param === 'undefined' ? 'undefined' : _typeof(param)) === 'object') {
param = param ? JSON.stringify(param) : '';
}
return encodeURIComponent(key) + '=' + encodeURIComponent(param);
}).join('&');
}
}]);
return FacebookAdsApi;
}();
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* Abstract Object
* Manages object data fields and provides matching properties
*
*
* @format
*/
var AbstractObject = function () {
createClass(AbstractObject, null, [{
key: 'Fields',
// This is a Flow workaround for setting `this[field]` in the set() function.
get: function get() {
return Object.freeze({});
}
}]);
function AbstractObject() {
var _this = this;
classCallCheck(this, AbstractObject);
this._data = {};
if (this.constructor.Fields === undefined) {
throw new Error('A "Fields" frozen object must be defined in the object class');
}
var fields = this.constructor.Fields;
this._fields = Object.keys(fields);
this._fields.forEach(function (field) {
_this._defineProperty(field);
});
}
/**
* Define data getter and setter field
* @param {String} field
*/
createClass(AbstractObject, [{
key: '_defineProperty',
value: function _defineProperty(field) {
var _this2 = this;
Object.defineProperty(this, field, {
get: function get() {
return _this2._data[field];
},
set: function set(value) {
_this2._data[field] = value;
},
enumerable: true
});
}
/**
* Set data field
* @param {String} field
* @param {Mixed} value
* @return this
*/
}, {
key: 'set',
value: function set(field, value) {
if (this._fields.indexOf(field) < 0) {
this._defineProperty(field);
}
this[field] = value;
return this;
}
/**
* Set multiple data fields
* @param {Object} data
* @return this
*/
}, {
key: 'setData',
value: function setData(data) {
var _this3 = this;
Object.keys(data).forEach(function (key) {
_this3.set(key, data[key]);
});
return this;
}
/**
* Export object data
* @return {Object}
*/
}, {
key: 'exportData',
value: function exportData() {
return this._data;
}
}]);
return AbstractObject;
}();
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
var Utils = function () {
function Utils() {
classCallCheck(this, Utils);
}
createClass(Utils, null, [{
key: 'normalizeEndpoint',
value: function normalizeEndpoint(str) {
return str.replace(/^\/|\/$/g, '');
}
}, {
key: 'removePreceedingSlash',
value: function removePreceedingSlash(str) {
return str.length && str[0] === '/' ? str.slice(1) : str;
}
}]);
return Utils;
}();
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* Cursor
* Iterates over edge objects and controls pagination
*
* @format
*/
var Cursor = function (_Array) {
inherits(Cursor, _Array);
/**
* @param {Object} sourceObject
* @param {Object} targetClass
* @param {Object} [params]
* @param {String} [endpoint]
*/
function Cursor(sourceObject, targetClass, params, endpoint) {
classCallCheck(this, Cursor);
var _this = possibleConstructorReturn(this, (Cursor.__proto__ || Object.getPrototypeOf(Cursor)).call(this));
var next = [sourceObject.getId()];
if (endpoint) {
next.push(Utils.normalizeEndpoint(endpoint));
} else {
throw new Error('No endpoint specified for the target edge.');
}
_this._api = sourceObject.getApi();
_this._targetClass = targetClass;
_this.paging = { next: next, params: params };
_this.clear = function () {
_this.length = 0;
};
_this.set = function (array) {
_this.clear();
_this.push.apply(_this, toConsumableArray(array));
};
_this.next = function () {
if (!_this.hasNext()) {
return Promise.reject(new RangeError('end of pagination'));
}
return _this._loadPage(_this.paging.next);
};
_this.hasNext = function () {
return Boolean(_this.paging) && Boolean(_this.paging.next);
};
_this.previous = function () {
if (!_this.hasPrevious()) {
return Promise.reject(new RangeError('start of pagination'));
}
return _this._loadPage(_this.paging.previous);
};
_this.hasPrevious = function () {
return Boolean(_this.paging) && Boolean(_this.paging.previous);
};
_this._loadPage = function (path$$1) {
var promise = new Promise(function (resolve, reject) {
_this._api.call('GET', path$$1, _this.paging.params).then(function (response) {
var objects = _this._buildObjectsFromResponse(response);
_this.set(objects);
_this.paging = response.paging;
_this.summary = response.summary;
_this.headers = response.headers;
resolve(_this);
}).catch(reject);
});
return promise;
};
_this._buildObjectsFromResponse = function (response) {
return response.data.map(function (item) {
var That = _this._targetClass;
if (That.name === 'AbstractObject') {
var result = new That();
result.setData(item);
return result;
}
return new That(item && item.id ? item.id : null, item, undefined, _this._api);
});
};
return _this;
}
return Cursor;
}(Array);
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
* @format
*
*/
/**
* Abstract Crud Object
* Facebook Object basic persistence functions
* @extends AbstractObject
*
*/
var AbstractCrudObject = function (_AbstractObject) {
inherits(AbstractCrudObject, _AbstractObject);
/**
* @param {Object} data
* @param {String} parentId
* @param {FacebookAdApi} [api]
*/
function AbstractCrudObject() {
var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var parentId = arguments[2];
var api = arguments[3];
classCallCheck(this, AbstractCrudObject);
var _this = possibleConstructorReturn(this, (AbstractCrudObject.__proto__ || Object.getPrototypeOf(AbstractCrudObject)).call(this));
_this._parentId = parentId;
_this._api = api || FacebookAdsApi.getDefaultApi();
if (id) {
data.id = id;
}
if (data) {
get$1(AbstractCrudObject.prototype.__proto__ || Object.getPrototypeOf(AbstractCrudObject.prototype), 'setData', _this).call(_this, data);
}
return _this;
}
/**
* Define data getter and setter recording changes
* @param {String} field
*/
createClass(AbstractCrudObject, [{
key: '_defineProperty',
value: function _defineProperty(field) {
var _this2 = this;
if (this._changes === undefined) {
this._changes = {};
}
Object.defineProperty(this, field, {
get: function get() {
return _this2._data[field];
},
set: function set(value) {
_this2._changes[field] = value;
_this2._data[field] = value;
},
enumerable: true
});
}
/**
* Set object data as if it were read from the server. Wipes related changes
* @param {Object} data
* @return this
*/
}, {
key: 'setData',
value: function setData(data) {
var _this3 = this;
get$1(AbstractCrudObject.prototype.__proto__ || Object.getPrototypeOf(AbstractCrudObject.prototype), 'setData', this).call(this, data);
Object.keys(data).forEach(function (key) {
delete _this3._changes[key];
});
return this;
}
/**
* Export changed object data
* @return {Object}
*/
}, {
key: 'exportData',
value: function exportData() {
return this._changes;
}
/**
* Export object data
* @return {Object}
*/
}, {
key: 'exportAllData',
value: function exportAllData() {
return this._data;
}
/**
* Clear change history
* @return this
*/
}, {
key: 'clearHistory',
value: function clearHistory() {
this._changes = {};
return this;
}
/**
* @throws {Error} if object has no id
* @return {String}
*/
}, {
key: 'getId',
value: function getId() {
if (!this.id) {
throw new Error(this.constructor.name + ' Id not defined');
}
return this.id;
}
/**
* @throws {Error} if object has no parent id
* @return {String}
*/
}, {
key: 'getParentId',
value: function getParentId() {
if (!this._parentId) {
throw new Error(this.constructor.name + ' parentId not defined');
}
return this._parentId;
}
/**
* @return {String}
*/
}, {
key: 'getNodePath',
value: function getNodePath() {
return this.getId();
}
/**
* Return object API instance
* @throws {Error} if object doesn't hold an API
* @return {FacebookAdsApi}
*/
}, {
key: 'getApi',
value: function getApi() {
var api = this._api;
if (!api) {
throw new Error(this.constructor.name + ' does not yet have an\n associated api object.\n Did you forget to\n instantiate an API session with:\n "FacebookAdsApi.init"?');
}
return api;
}
/**
* Read object data
* @param {Array} [fields]
* @param {Object} [params]
* @return {Promise}
*/
}, {
key: 'read',
value: function read(fields) {
var _this4 = this;
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var api = this.getApi();
var path$$1 = [this.getNodePath()];
if (fields) {
params['fields'] = fields.join(',');
}
return new Promise(function (resolve, reject) {
api.call('GET', path$$1, params).then(function (data) {
return resolve(_this4.setData(data));
}).catch(reject);
});
}
/**
* Update object
* @param {Object} [params]
* @return {Promise}
*/
}, {
key: 'update',
value: function update() {
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var api = this.getApi();
var path$$1 = [this.getNodePath()];
params = Object.assign(params, this.exportData());
return new Promise(function (resolve, reject) {
api.call('POST', path$$1, params).then(function (data) {
return resolve(data);
}).catch(reject);
});
}
/**
* Delete object
* @param {Object} [params]
* @return {Promise}
*/
}, {
key: 'delete',
value: function _delete() {
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var api = this.getApi();
var path$$1 = [this.getNodePath()];
params = Object.assign(params, this.exportData());
return new Promise(function (resolve, reject) {
api.call('DELETE', path$$1, params).then(function (data) {
return resolve(data);
}).catch(reject);
});
}
/**
* Initialize Cursor to paginate on edges
* @param {Object} targetClass
* @param {Array} [fields]
* @param {Object} [params]
* @param {Boolean} [fetchFirstPage]
* @param {String} [endpoint]
* @return {Cursor}
*/
}, {
key: 'getEdge',
value: function getEdge(targetClass, fields) {
var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var fetchFirstPage = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
var endpoint = arguments[4];
if (fields && fields.length > 0) {
params['fields'] = fields.join(',');
}
var sourceObject = this;
var cursor = new Cursor(sourceObject, targetClass, params, endpoint);
if (fetchFirstPage) {
return cursor.next();
}
return cursor;
}
/**
* Create edge object
* @param {String} [endpoint]
* @param {Array} [fields]
* @param {Object} [params]
* @param {Function} [targetClassConstructor]
* @return {Promise}
*/
}, {
key: 'createEdge',
value: function createEdge(endpoint, fields) {
var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var _this5 = this;
var targetClassConstructor = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
var pathOverride = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
if (fields && fields.length > 0) {
params['fields'] = fields.join(',');
}
var api = this.getApi();
var path$$1 = pathOverride != null ? pathOverride : [this.getNodePath(), Utils.removePreceedingSlash(endpoint)];
params = Object.assign(params, this.exportData());
return new Promise(function (resolve, reject) {
api.call('POST', path$$1, params).then(function (data) {
resolve(
/* eslint new-cap: "off" */
targetClassConstructor === null ? _this5.setData(data) : new targetClassConstructor(data.id, data));
}).catch(reject);
});
}
/**
* Delete edge object
* @param {String} [endpoint]
* @param {Object} [params]
* @return {Promise}
*/
}, {
key: 'deleteEdge',
value: function deleteEdge(endpoint) {
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var api = this.getApi();
var path$$1 = [this.getNodePath(), Utils.removePreceedingSlash(endpoint)];
params = Object.assign(params, this.exportData());
return new Promise(function (resolve, reject) {
api.call('DELETE', path$$1, params).then(function (data) {
return resolve(data);
}).catch(reject);
});
}
/**
* Read Objects by Ids
* @param {Array} ids
* @param {Array} [fields]
* @param {Object} [params]
* @param {FacebookAdsApi} [api]
* @return {Promise}
*/
}], [{
key: 'getByIds',
value: function getByIds(ids, fields) {
var _this6 = this;
var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var api = arguments[3];
api = api || FacebookAdsApi.getDefaultApi();
if (fields && fields.length > 0) {
params['fields'] = fields.join(',');
}
params['ids'] = ids.join(',');
return new Promise(function (resolve, reject) {
return api.call('GET', [''], params).then(function (response) {
var result = [];
for (var id in response) {
var data = response[id];
var That = _this6;
var object = new That(data);
result.push(object);
}
resolve(result);
}).catch(reject);
});
}
}]);
return AbstractCrudObject;
}(AbstractObject);
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
/**
* Represents an API request
*/
var APIRequest = function () {
/**
* @param {string} nodeId The node id to perform the api call.
* @param {string} method The HTTP method of the call.
* @param {string} endpoint The edge of the api call.
*/
function APIRequest(nodeId, method, endpoint) {
classCallCheck(this, APIRequest);
this._nodeId = nodeId;
this._method = method;
this._endpoint = endpoint.replace('/', '');
this._path = [nodeId, this.endpoint];
this._fields = [];
this._fileParams = Object.create(null);
this._params = Object.create(null);
this._fileCounter = 0;
}
/**
* Getter function for node ID
* @return {string} Node ID
*/
createClass(APIRequest, [{
key: 'addFile',
/**
* @param {string} filePath Path to file attached to the request
* @return {APIReqeust} APIRequest instance
*/
value: function addFile(filePath) {
var fileKey = 'source' + this._fileCounter;
var stats = fs.lstatSync(filePath);
if (!stats.isFile()) {
throw Error('Cannot find file ' + filePath + '!');
}
this._fileParams[fileKey] = filePath;
this._fileCounter += 1;
return this;
}
/**
* @param {string[]} filePaths Array of paths to files attached to the request
* @return {APIRequest} APIRequest instance
*/
}, {
key: 'addFiles',
value: function addFiles(filePaths) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = filePaths[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var filePath = _step.value;
this.addFile(filePath);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return this;
}
/**
* @param {string} field Requested field
* @return {APIReqeust} APIRequest instance
*/
}, {
key: 'addField',
value: function addField(field) {
if (!this._fields.includes(field)) {
this._fields.push(field);
}
return this;
}
/**
* @param {string[]} fields Array of requested fields
* @return {APIRequest} APIRequest instance
*/
}, {
key: 'addFields',
value: function addFields(fields) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = fields[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var field = _step2.value;
this.addField(field);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return this;
}
/**
* @param {string} key Param key
* @param {*} value Param value
* @return {APIRequest} APIRequest instance
*/
}, {
key: 'addParam',
value: function addParam(key, value) {
this._params[key] = value;
return this;
}
/**
* @param {Object} params An object containing param keys and values
* @return {APIRequest} APIRequest instance
*/
}, {
key: 'addParams',
value: function addParams(params) {
this._params = params;
return this;
}
}, {
key: 'nodeId',
get: function get() {
return this._nodeId;
}
/**
* Getter function for HTTP method e.g. GET, POST
* @return {string} HTTP method
*/
}, {
key: 'method',
get: function get() {
return this._method;
}
/**
* Getter function for the edge of the API call
* @return {string} Endpoint edge
*/
}, {
key: 'endpoint',
get: function get() {
return this._endpoint;
}
/**
* Getter function for path tokens
* @return {Array<string>} Array of path tokens
*/
}, {
key: 'path',
get: function get() {
return this._path;
}
/**
* Getter function for requested fields
* @return {Array<string>} Array of request fields
*/
}, {
key: 'fields',
get: function get() {
return this._fields;
}
/**
* Getter function for API params
* @return {Object} Object containing API Params
*/
}, {
key: 'params',
get: function get() {
// Deep cloning when object value is not a function
return JSON.parse(JSON.stringify(this._params));
}
/**
* Getter function for API fileparams
* @return {Object} Object containing API fileParams
*/
}, {
key: 'fileParams',
get: function get() {
// Deep cloning when object value is not a function
return JSON.parse(JSON.stringify(this._fileParams));
}
}]);
return APIRequest;
}();
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
/**
* Encapsulates an http response from Facebook's Graph API.
*/
var APIResponse = function () {
function APIResponse(response, call) {
classCallCheck(this, APIResponse);
response.body = JSON.parse(response.body);
this._body = response.body;
this._httpStatus = response.code;
this._headers = response.headers;
this._call = call;
this._response = response;
}
/**
* @return {Object} The response body
*/
createClass(APIResponse, [{
key: 'body',
get: function get() {
return this._body;
}
}, {
key: 'headers',
get: function get() {
return this._headers;
}
}, {
key: 'etag',
get: function get() {
return this._headers['ETag'];
}
}, {
key: 'status',
get: function get() {
return this._httpStatus;
}
}, {
key: 'isSuccess',
get: function get() {
var body = this._body;
if ('error' in body) {
return false;
} else if (Object.keys(body).length !== 0) {
if ('success' in body) {
return body['success'];
}
return !('Service Unavailable' in body);
} else if (this._httpStatus === HTTP_STATUS.NOT_MODIFIED) {
// ETag Hit
return true;
} else if (this._httpStatus === HTTP_STATUS.OK) {
// HTTP OK
return true;
} else {
// Something else
return false;
}
}
}, {
key: 'error',
get: function get() {
if (this.isSuccess) {
return null;
}
return new FacebookRequestError(this._response, this._call.method, this._call.relativeUrl, this._call.body);
}
}]);
return APIResponse;
}();
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
/**
* Facebook Ads API Batch
*/
var FacebookAdsApiBatch = function () {
/**
* @param {FacebookAdsApi} api
* @param {Function} successCallback
* @param {Function} failureCallback
*/
function FacebookAdsApiBatch(api, successCallback, failureCallback) {
classCallCheck(this, FacebookAdsApiBatch);
this._api = api;
this._files = [];
this._batch = [];
this._requests = [];
this._successCallbacks = [];
this._failureCallbacks = [];
if (successCallback != null) {
this._successCallbacks.push(successCallback);
}
if (failureCallback != null) {
this._failureCallbacks.push(failureCallback);
}
}
/**
* Adds a call to the batch.
* @param {string} method The HTTP method name (e.g. 'GET').
* @param {string[]|string} relativePath An array of path tokens or
* a relative URL string. An array will be translated to a url as follows:
* <graph url>/<tuple[0]>/<tuple[1]>...
* It will be assumed that if the path is not a string, it will be iterable.
* @param {Object} [params] A mapping of request parameters
* where a key is the parameter name and its value is a string or an object
* which can be JSON-encoded.
* @param {Object} [files] An optional mapping of file names to binary open
* file objects. These files will be attached to the request.
* @param {Function} [successCallback] A callback function which will be
* called with the response of this call if the call succeeded.
* @param {Function} [failureCallback] A callback function which will be
* called with the response of this call if the call failed.
* @param {APIRequest} [request] The APIRequest object
* @return {Object} An object describing the call
*/
createClass(FacebookAdsApiBatch, [{
key: 'add',
value: function add(method, relativePath, params, files, successCallback, failureCallback, request) {
// Construct a relaitveUrl from relateivePath by assuming that
// relativePath can only be a string or an array of strings
var relativeUrl = typeof relativePath === 'string' ? relativePath : relativePath.join('/');
// Contruct key-value pairs from params for GET querystring or POST body
if (params != null) {
var keyVals = [];
for (var key in params) {
var value = params[key];
if (_typeof(params[key]) === 'object' && !(params[key] instanceof Date)) {
value = JSON.stringify(value);
}
keyVals.push(key + '=' + value);
}
if (method === 'GET') {
relativeUrl += '?' + keyVals.join('&');
} else {
var body = keyVals.join('&');
}
if (params && params['name']) {
var name = params['name'];
}
}
// Handle attached files
if (files != null) {
var attachedFiles = Object.keys(files).join(',');
}
// A Call object that will be used in a batch request
var call = {
method: method,
relative_url: relativeUrl,
body: body,
name: name,
attachedFiles: attachedFiles
};
this._batch.push(call);
this._files.push(files);
this._successCallbacks.push(successCallback);
this._failureCallbacks.push(failureCallback);
if (request !== undefined) {
this._requests.push(request);
}
return call;
}
/**
* Interface to add a APIRequest to the batch.
* @param {APIRequest} request The APIRequest object to add
* @param {Function} [successCallback] A callback function which
* will be called with response of this call if the call succeeded.
* @param {Function} [failureCallback] A callback function which
* will be called with the FacebookResponse of this call if the call failed.
* @return {Object} An object describing the call
*/
}, {
key: 'addRequest',
value: function addRequest(request, successCallback, failureCallback) {
var updatedParams = request.params;
updatedParams['fields'] = request.fields.join();
return this.add(request.method, request.path, updatedParams, request.fileParams, successCallback, failureCallback, request);
}
/**
* Makes a batch call to the api associated with this object.
* For each individual call response, calls the success or failure callback
* function if they were specified.
* Note: Does not explicitly raise exceptions. Individual exceptions won't
* be thrown for each call that fails. The success and failure callback
* functions corresponding to a call should handle its success or failure.
* @return {FacebookAdsApiBatch|None} If some of the calls have failed,
* returns a new FacebookAdsApiBatch object with those calls.
* Otherwise, returns None.
*/
}, {
key: 'execute',
value: function execute() {
var _this = this;
if (this._batch.length < 1) {
return;
}
var method = 'POST';
var path$$1 = []; // request to root domain for a batch request
var params = {
batch: this._batch
};
// Call to the batch endpoint (WIP)
return this._api.call(method, path$$1, params).then(function (responses) {
// Keep track of batch indices that need to retry
var retryIndices = [];
// Check each response
for (var index = 0; index < responses.length; index++) {
var response = responses[index];
if (response != null) {
var apiResponse = new APIResponse(response, _this._batch[index]);
// Call the success callback if provided
if (apiResponse.isSuccess) {
if (_this._successCallbacks[index]) {
_this._successCallbacks[index](apiResponse);
}
} else {
// Call the failure callback if provided
if (_this._failureCallbacks[index]) {
_this._failureCallbacks[index](apiResponse);
}
}
} else {
// Do not get response, so, we keep track of the index to retry
retryIndices.push(index);
}
}
// Create and return new batch if we need to retry
if (retryIndices.length > 0) {
// Create a new batch from retry indices in the current batch
var newBatch = new FacebookAdsApiBatch(_this._api);
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = retryIndices[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _index = _step.value;
newBatch._files.push(_this._files[_index]);
newBatch._batch.push(_this._batch[_index]);
newBatch._successCallbacks.push(_this._successCallbacks[_index]);
newBatch._failureCallbacks.push(_this._failureCallbacks[_index]);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {