UNPKG

facebook-nodejs-business-sdk

Version:
1,828 lines (1,553 loc) 1.65 MB
import fs from 'fs'; import path from '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 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 _requestPromise = require('request-promise'); /** * 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) { if (typeof window !== 'undefined' && window.XMLHttpRequest) { return Http.xmlHttpRequest(method, url, data); } return Http.requestPromise(method, url, data, files, useMultipartFormData); } /** * 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 options = { method: method, uri: url, json: !useMultipartFormData, headers: { 'User-Agent': 'fbbizsdk-nodejs-' + FacebookAdsApi.VERSION }, body: Object }; // Prevent null or undefined input // because it can be merged with the files argument later if (!data) { data = {}; } options.body = 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.formData = Object.assign(data, files); delete options.body; } return _requestPromise(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. */ // request-promise error types var REQUEST_ERROR = 'RequestError'; var STATUS_CODE_ERROR = 'StatusCodeError'; 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.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; // 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; } else { // Handle single response if (response.name === STATUS_CODE_ERROR) { // Handle when we can get response error code body = response.error ? response.error : response; body = typeof body === 'string' ? JSON.parse(body) : body; // Construct an error message from subfields in body.error message = body.error.error_user_msg ? body.error.error_user_title + ': ' + body.error.error_user_msg : body.error.message; status = response.statusCode; } else if (response.name === REQUEST_ERROR) { // Handle network errors e.g. timeout, destination unreachable body = { error: response.error }; // An error message is in the response already message = response.message; // Network errors have no status code status = null; } } return { body: body, message: message, status: status }; } /** * 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 'v3.1'; } }, { 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'; classCallCheck(this, FacebookAdsApi); if (!accessToken) { throw new Error('Access token required'); } this.accessToken = accessToken; this.locale = locale; this._debug = false; } /** * Instantiate an API and store it as the default * @param {String} accessToken * @param {String} [locale] * @return {FacebookAdsApi} */ createClass(FacebookAdsApi, [{ key: 'setDebug', value: function setDebug(flag) { this._debug = 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[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).then(function (response) { if (_this._debug) { console.log('200 ' + method + ' ' + url + ' ' + (data ? JSON.stringify(data) : '')); console.log('Response: ' + (response ? JSON.stringify(response) : '')); } return Promise.resolve(response); }).catch(function (response) { if (_this._debug) { console.log(response.status + ' ' + method + ' ' + url + '\n ' + (data ? 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 api = new this(accessToken, locale); 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. * * @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)); } }]); 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('/'); // A Call object that will be used in a batch request var call = { method: method, relative_url: relativeUrl }; // 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') { call['relative_url'] += '?' + keyVals.join('&'); } else { call['body'] = keyVals.join('&'); } if (params && params['name']) { call['name'] = params['name']; } } // Handle attached files if (files != null) { call['attachedFiles'] = Object.keys(files).join(','); } this._batch.push(call); this._files.push(files); this._successCallbacks.push(successCallback); this._failureCallbacks.push(failureCallback); 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 { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return newBatch; } // No retry return null; }).catch(function (error) { throw error; }); } }]); return FacebookAdsApiBatch; }(); /** * 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', 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); } var that = this; that[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 }; _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, params).then(function (response) { var objects = _this._buildObjectsFromResponse(response); _this.set(objects); _this.paging = response.paging; _this.summary = response.summary; resolve(_this); }).catch(reject); }); if (params) params = undefined; 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 (params == null) { params = {}; } if (fields) { 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 _this5 = this; var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var targetClassConstructor = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; if (params == null) { params = {}; } if (fields && fields.length > 0) { params['fields'] = fields.join(','); } 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('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) 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. * */ /** * ANBlockedBICategory * @extends AbstractCrudObject * @see {@link https://developers.facebook.com/docs/marketing-api/} */ var ANBlockedBICategory = function (_AbstractCrudObject) { inherits(ANBlockedBICategory, _AbstractCrudObject); function ANBlockedBICategory() { classCallCheck(this, ANBlockedBICategory); return possibleConstructorReturn(this, (ANBlockedBICategory.__proto__ || Object.getPrototypeOf(ANBlockedBICategory)).apply(this, arguments)); } createClass(ANBlockedBICategory, [{ key: 'get', value: function get(fields, params) { return this.read(fields, params); } }], [{ key: 'Fields', get: function get() { return Object.freeze({ key: 'key', id: 'id' }); } }]); return ANBlockedBICategory; }(AbstractCrudObject); /** * 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. * */ /** * AdActivity * @extends AbstractCrudObject * @see {@link https://developers.facebook.com/docs/marketing-api/} */ var AdActivity = function (_AbstractCrudObject) { inherits(AdActivity, _AbstractCrudObject); function AdActivity() { classCallCheck(this, AdActivity); return possibleConstructorReturn(this, (AdActivity.__proto__ || Object.getPrototypeOf(AdActivity)).apply(this, arguments)); } createClass(AdActivity, [{ key: 'get', value: function get(fields, params) { return this.read(fields, params); } }], [{ key: 'Fields', get: function get() { return Object.freeze({ actor_id: 'actor_id', actor_name: 'actor_name', application_id: 'application_id', application_name: 'application_name', date_time_in_timezone: 'date_time_in_timezone', event_time: 'event_time', event_type: 'event_type', extra_data: 'extra_data', object_id: 'object_id', object_name: 'object_name', object_type: 'object_type', translated_event_type: 'translated_event_type', id: 'id' }); } }, { key: 'EventType', get: function get() { return Object.freeze({ ad_account_update_spend_limit: 'ad_account_update_spend_limit', ad_account_reset_spend_limit: 'ad_account_reset_spend_limit', ad_account_remove_spend_limit: 'ad_account_remove_spend_limit', ad_account_set_business_information: 'ad_account_set_business_information', ad_account_update_status: 'ad_account_update_status', ad_account_add_user_to_role: 'ad_account_add_user_to_role', ad_account_remove_user_from_role: 'ad_account_remove_user_from_role', add_images: 'add_images', edit_images: 'edit_images', delete_images: 'delete_images', ad_account_billing_charge: 'ad_account_billing_charge', ad_account_billing_charge_failed: 'ad_account_billing_charge_failed', ad_account_billing_chargeback: 'ad_account_billing_chargeback', ad_account_billing_chargeback_reversal: 'ad_account_billing_chargeback_reversal', ad_account_billing_decline: 'ad_account_billing_decline', ad_account_billing_refund: 'ad_account_billing_refund', billing_event: 'billing_event', add_funding_source: 'add_funding_source', remove_funding_source: 'remove_funding_source', create_campaign_group: 'create_campaign_group', update_campaign_name: 'update_campaign_name', update_campaign_run_status: 'update_campaign_run_status', update_campaign_group_spend_cap: 'update_campaign_group_spend_cap', create_campaign_legacy: 'create_campaign_legacy', update_campaign_budget: 'update_campaign_budget', update_campaign_duration: 'update_campaign_duration', campaign_ended: 'campaign_ended', create_ad_set: 'create_ad_set', update_ad_set_bidding: 'update_ad_set_bidding', update_ad_set_bid_strategy: 'update_ad_set_bid_strategy', update_ad_set_budget: 'update_ad_set_budget', update_ad_set_duration: 'update_ad_set_duration', update_ad_set_run_status: 'update_ad_set_run_status', update_ad_set_name: 'update_ad_set_name', update_ad_set_optimization_goal: 'update_ad_set_optimization_goal', update_ad_set_target_spec: 'update_ad_set_target_spec', update_ad_set_bid_adjustments: 'update_ad_set_bid_adjustments', create_ad: 'create_ad', ad_review_approved: 'ad_review_approved', ad_review_declined: 'ad_review_declined', update_ad_creative: 'update_ad_creative', edit_and_update_ad_creative: 'edit_and_update_ad_creative', update_ad_bid_info: 'update_ad_bid_info', update_ad_bid_type: 'update_ad_bid_type', update_ad_run_status: 'update_ad_run_status', update_ad_run_status_to_be_set_after_review: 'upda