UNPKG

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
'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 {