diff --git a/.gitignore b/.gitignore index 140aebc..56da4fe 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,5 @@ package-lock.json # build directories build -bin \ No newline at end of file +bin +lib diff --git a/CHANGELOG.md b/CHANGELOG.md index a6c0921..966d4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ +# 0.3.0 +- major rewrite of incoming and outgoing traffic +- add integration tests +- upgrade NodeJS to LTS 8.x +- change bablejs configuration to use native code +- upgrade hull-node to 0.13.14 + # 0.2.0 - upgrade hull-node to 0.11.6 -- add local in memory cache to avoid duplicates to be sent to Nutshell. Only works in single process mode. \ No newline at end of file +- add local in memory cache to avoid duplicates to be sent to Nutshell. Only works in single process mode. diff --git a/assets/logo.jpg b/assets/logo.jpg index aa0b848..a3ec040 100644 Binary files a/assets/logo.jpg and b/assets/logo.jpg differ diff --git a/assets/logo.png b/assets/logo.png index eb109de..63ee8eb 100644 Binary files a/assets/logo.png and b/assets/logo.png differ diff --git a/assets/logo.svg b/assets/logo.svg index c1a3f82..42f9b89 100644 --- a/assets/logo.svg +++ b/assets/logo.svg @@ -1,28 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/logo@2x.jpg b/assets/logo@2x.jpg index c2e38b2..769d3cc 100644 Binary files a/assets/logo@2x.jpg and b/assets/logo@2x.jpg differ diff --git a/assets/logo@2x.png b/assets/logo@2x.png index b5b2bfa..8e0a457 100644 Binary files a/assets/logo@2x.png and b/assets/logo@2x.png differ diff --git a/assets/picture.jpg b/assets/picture.jpg index 5e1e244..9ab0b3f 100644 Binary files a/assets/picture.jpg and b/assets/picture.jpg differ diff --git a/assets/picture.png b/assets/picture.png index c6fc1bc..b00e513 100644 Binary files a/assets/picture.png and b/assets/picture.png differ diff --git a/assets/picture.svg b/assets/picture.svg index e81af94..611c6c1 100644 --- a/assets/picture.svg +++ b/assets/picture.svg @@ -1,29 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Nutshell - - - + \ No newline at end of file diff --git a/assets/picture@2x.jpg b/assets/picture@2x.jpg index 1eed7b3..88b47a7 100644 Binary files a/assets/picture@2x.jpg and b/assets/picture@2x.jpg differ diff --git a/assets/picture@2x.png b/assets/picture@2x.png index af1515f..22c0b68 100644 Binary files a/assets/picture@2x.png and b/assets/picture@2x.png differ diff --git a/lib/actions/fields-account.js b/lib/actions/fields-account.js deleted file mode 100644 index 38ce248..0000000 --- a/lib/actions/fields-account.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; - -var Agent = require("../lib/agent"); - -var cacheManager = require("cache-manager"); - -var Cache = cacheManager.caching({ store: "memory", max: 100, ttl: 60 }); - -function fieldsAccountAction(req, res) { - var _req$hull = req.hull, - client = _req$hull.client, - ship = _req$hull.ship, - metric = _req$hull.metric; - - var _client$configuration = client.configuration(), - secret = _client$configuration.secret; - - var cacheKey = [ship.id, ship.updated_at, secret, "af"].join("/"); - var agent = new Agent(client, ship, metric); - - if (!agent.isAuthenticationConfigured()) { - return res.json({ ok: false, error: "The connector is not or not properly authenticated to Nutshell.", options: [] }); - } - - return Cache.wrap(cacheKey, function () { - return agent.getAccountFields(); - }).then(function (ls) { - var fields = (ls || []).map(function (s) { - return { value: s.value, label: s.label }; - }); - return res.json({ options: fields }); - }).catch(function (err) { - client.logger.error("connector.metadata.error", { status: err.status, message: err.message, type: "/fields-lead" }); - return res.json({ ok: false, error: err.message, options: [] }); - }); -} - -module.exports = fieldsAccountAction; \ No newline at end of file diff --git a/lib/actions/index.js b/lib/actions/index.js deleted file mode 100644 index 9c4fd14..0000000 --- a/lib/actions/index.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -var fieldsAccount = require("./fields-account"); -var statusCheck = require("./status-check"); - -module.exports = { - fieldsAccount: fieldsAccount, - statusCheck: statusCheck -}; \ No newline at end of file diff --git a/lib/actions/status-check.js b/lib/actions/status-check.js deleted file mode 100644 index b0f6b64..0000000 --- a/lib/actions/status-check.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; - -var _express = require("express"); - -var _ = require("lodash"); - -var Agent = require("../lib/agent"); - -function statusCheckAction(req, res) { - if (req.hull && req.hull.ship && req.hull.ship.private_settings) { - var _req$hull = req.hull, - _req$hull$ship = _req$hull.ship, - ship = _req$hull$ship === undefined ? {} : _req$hull$ship, - _req$hull$client = _req$hull.client, - client = _req$hull$client === undefined ? {} : _req$hull$client, - _req$hull$metric = _req$hull.metric, - metric = _req$hull$metric === undefined ? {} : _req$hull$metric; - - var messages = []; - var status = "ok"; - var agent = new Agent(client, ship, metric); - - if (agent.isAuthenticationConfigured() === false) { - status = "error"; - messages.push("API Key is not configured. Connector cannot communicate with external service."); - } - - if (_.isEmpty(_.get(ship, "private_settings.synchronized_segments", []))) { - status = "error"; - messages.push("No users will be synchronized because no segments are whitelisted."); - } - - res.json({ status: status, messages: messages }); - client.put(ship.id + "/status", { status: status, messages: messages }); - } - - res.status(404).json({ status: 404, messages: ["Request doesn't contain data about the connector"] }); -} - -module.exports = statusCheckAction; \ No newline at end of file diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index fcf0960..0000000 --- a/lib/index.js +++ /dev/null @@ -1,27 +0,0 @@ -"use strict"; - -var _express = require("express"); - -var _express2 = _interopRequireDefault(_express); - -var _hull = require("hull"); - -var _hull2 = _interopRequireDefault(_hull); - -var _server = require("./server"); - -var _server2 = _interopRequireDefault(_server); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var config = { - hostSecret: process.env.SECRET, - port: process.env.PORT || 8082, - devMode: process.env.NODE_ENV === "development" -}; - -var connector = new _hull2.default.Connector(config); -var app = (0, _express2.default)(); - -connector.setupApp(app); -(0, _server2.default)(app); \ No newline at end of file diff --git a/lib/lib/agent.js b/lib/lib/agent.js deleted file mode 100644 index 43a9edf..0000000 --- a/lib/lib/agent.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; - -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 _shared = require("./shared"); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var _ = require("lodash"); -var Promise = require("bluebird"); -var NutshellClient = require("./nutshell-client"); - -var Agent = function () { - function Agent(hullClient, connector, metricClient) { - _classCallCheck(this, Agent); - - this.connector = connector; - this.synchronizedSegments = connector.private_settings.synchronized_segments; - this.hullClient = hullClient; - this.logger = hullClient.logger; - this.metricClient = metricClient; - } - - /** - * Returns the fields for Nutshell accounts. - * - * @returns {Promise>} The list of account fields. - * @memberof Agent - */ - - - _createClass(Agent, [{ - key: "getAccountFields", - value: function getAccountFields() { - // TODO: compose proper options - var options = { - host: "app.nutshell.com", - requestId: "hull" - }; - - var defaultFields = [{ value: "name", label: "Name" }, { value: "description", label: "Description" }, { value: "industryId", label: "Industry (ID)" }, { value: "accountTypeId", label: "Account Type (ID)" }, { value: "territoryId", label: "Territory (ID)" }, { value: "url", label: "Url" }, { value: "phone", label: "Phone" }]; - return this.nutshellClient.findCustomFields(options).then(function (opsResult) { - var customFields = _.map(opsResult.result.Accounts, function (field) { - return { value: field.name, label: field.name }; - }); - - return _.concat(defaultFields, customFields); - }); - } - - /** - * Checks whether the API key and User ID are provided at all and hypothetically valid. - * - * @returns {boolean} True if both are present and hypothetically valid; otherwise false. - * @memberof Agent - */ - - }, { - key: "isAuthenticationConfigured", - value: function isAuthenticationConfigured() { - if (_.get(this.connector, "private_settings.auth_userid", "n/a") === "n/a") { - return false; - } - - if (_.get(this.connector, "private_settings.auth_apikey", "n/a") === "n/a") { - return false; - } - - return true; - } - }]); - - return Agent; -}(); - -module.exports = Agent; \ No newline at end of file diff --git a/lib/lib/nutshell-client.js b/lib/lib/nutshell-client.js deleted file mode 100644 index 7cde7d3..0000000 --- a/lib/lib/nutshell-client.js +++ /dev/null @@ -1,291 +0,0 @@ -"use strict"; - -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 _shared = require("./shared"); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Promise = require("bluebird"); -var rpc = require("jayson"); -var shared = require("./shared"); - -function _initHttpsClient(options) { - var auth = Buffer.from(options.userId + ":" + options.apiKey).toString("base64"); - var client = rpc.client.https({ - hostname: options.host, - path: "/api/v1/json", - headers: { - authorization: "Basic " + auth - } - }); - return client; -} - -var NutshellClient = function () { - /** - * Gets or sets the user name or identifier. - * - * @type {string} - * @memberof NutshellClient - */ - function NutshellClient(options) { - _classCallCheck(this, NutshellClient); - - this.userId = options.userId; - this.apiKey = options.apiKey; - } - - /** - * Discovers the endpoint that should be used to communicate. - * Response shall be cached between 10-90 minutes. - * - * @returns {Promise} The discovery result. - * @memberof NutshellClient - */ - - - /** - * Gets or sets the API key to authenticate against the Nutshell. - * - * @type {string} - * @memberof NutshellClient - */ - - - _createClass(NutshellClient, [{ - key: "discoverEndpoint", - value: function discoverEndpoint() { - var _this = this; - - return new Promise(function (resolve, reject) { - var client = rpc.client.http(shared.DISCOVERY_ENDPOINT); - - client.request("getApiForUsername", { username: _this.userId }, "apeye", function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - - /** - * Creates a new contact in Nutshell. - * - * @param {Object} data The contact data. - * @param {INutshellOperationOptions} options The options for the operation. - * @returns {Promise} The result of the operation. - * @memberof NutshellClient - */ - - }, { - key: "createContact", - value: function createContact(data, options) { - var _this2 = this; - - return new Promise(function (resolve, reject) { - var client = _initHttpsClient({ userId: _this2.userId, apiKey: _this2.apiKey, host: options.host }); - client.request("newContact", { contact: data }, options.requestId, function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - - /** - * Creates a new account in Nutshell. - * - * @param {Object} data The account data. - * @param {INutshellOperationOptions} options The options for the operation. - * @returns {Promise} The result of the operation. - * @memberof NutshellClient - */ - - }, { - key: "createAccount", - value: function createAccount(data, options) { - var _this3 = this; - - return new Promise(function (resolve, reject) { - var client = _initHttpsClient({ userId: _this3.userId, apiKey: _this3.apiKey, host: options.host }); - client.request("newAccount", { account: data }, options.requestId, function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - - /** - * Edit a contact. - * - * Warning: Fields which allow multiples (phone, email, URL, etc.) will be completely replaced by - * whatever data you supply, if you supply any data for the field. (Eg. the new phone array replaces - * all previously known phone numbers.) If you are updating a multi-value field, you must include all - * values you wish to keep (not just the new values) for the field. - * - * If a note is specified, it will be added to the existing notes (preexisting notes are not affected). - * - * @param {string} id The contact ID to update. - * @param {string} rev The revision number. - * @param {Object} data The updated contact information. - * @param {INutshellOperationOptions} options The options for the operation. - * @returns {Promise} The result of the operation. - * @memberof NutshellClient - */ - - }, { - key: "editContact", - value: function editContact(id, rev, data, options) { - var _this4 = this; - - return new Promise(function (resolve, reject) { - var client = _initHttpsClient({ userId: _this4.userId, apiKey: _this4.apiKey, host: options.host }); - client.request("editContact", { contactId: id, rev: rev, contact: data }, options.requestId, function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - - /** - * Edit an account. - * - * Warning: Fields which allow multiples (phone, email, URL, etc.) will be completely replaced by - * whatever data you supply, if you supply any data for the field. (Eg. the new phone array replaces - * all previously known phone numbers.) If you are updating a multi-value field, you must include - * all values you wish to keep (not just the new values) for the field. - * - * If a note is specified, it will be added to the existing notes (preexisting notes are not affected). - * - * @param {string} id The account ID to edit. - * @param {string} rev The revision number. - * @param {Object} data The updated account information - * @param {INutshellOperationOptions} options The options for the operation. - * @returns {Promise} The result of the operation. - * @memberof NutshellClient - */ - - }, { - key: "editAccount", - value: function editAccount(id, rev, data, options) { - var _this5 = this; - - return new Promise(function (resolve, reject) { - var client = _initHttpsClient({ userId: _this5.userId, apiKey: _this5.apiKey, host: options.host }); - client.request("editAccount", { accountId: id, rev: rev, account: data }, options.requestId, function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - - /** - * Gets all of the custom fields available for Leads, Accounts and Contacts, including appropriate meta-information. - * - * @param {INutshellOperationOptions} options The options for the operation. - * @returns {Promise} The result of the operation. - * @memberof NutshellClient - * - * @example - * The result property contains an object of the following shape if the operation succeeded: - * { - * "Leads": [ EntityAttribute, ... ], - * "Contacts": [ EntityAttribute, ... ], - * "Accounts": [ EntityAttribute, ... ] - * } - * - */ - - }, { - key: "findCustomFields", - value: function findCustomFields(options) { - var _this6 = this; - - return new Promise(function (resolve, reject) { - var client = _initHttpsClient({ userId: _this6.userId, apiKey: _this6.apiKey, host: options.host }); - client.request("findCustomFields", [], options.requestId, function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - - /** - * Return a list of Account stubs matching a given search string. - * - * @param {string} query The string to search for. - * @param {number} limit The maximum number of entities returned. - * @param {INutshellOperationOptions} options The options for the operation. - * @returns {Promise} The result of the operation. - * @memberof NutshellClient - * - * @example - * The result property contains an array of matching account objects. - */ - - }, { - key: "searchAccounts", - value: function searchAccounts(query, limit, options) { - var _this7 = this; - - return new Promise(function (resolve, reject) { - var client = _initHttpsClient({ userId: _this7.userId, apiKey: _this7.apiKey, host: options.host }); - client.request("searchAccounts", { string: query, limit: limit }, options.requestId, function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - - /** - * Searches accounts and contacts by email address and returns - * up to 5 account or contact stubs with the specified email address. - * Results are organized by entity type. - * - * @param {string} emailAddress The email address to search for. - * @param {INutshellOperationOptions} options The options for the operation. - * @returns {Promise} The result of the operation. - * @memberof NutshellClient - * - * @example - * The result property will contain an object of the following shape when successful: - * { - * "contacts": [ Contact, ... ], - * "accounts": [ Account, ... ] - * } - */ - - }, { - key: "searchByEmail", - value: function searchByEmail(emailAddress, options) { - var _this8 = this; - - return new Promise(function (resolve, reject) { - var client = _initHttpsClient({ userId: _this8.userId, apiKey: _this8.apiKey, host: options.host }); - client.request("searchByEmail", { emailAddressString: emailAddress }, options.requestId, function (err, result) { - if (err) { - return reject(err); - } - return resolve(result); - }); - }); - } - }]); - - return NutshellClient; -}(); - -module.exports = NutshellClient; \ No newline at end of file diff --git a/lib/lib/shared.js b/lib/lib/shared.js deleted file mode 100644 index 84d2566..0000000 --- a/lib/lib/shared.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; - -var DISCOVERY_ENDPOINT = "http://api.nutshell.com/v1/json"; - - -module.exports = { - DISCOVERY_ENDPOINT: DISCOVERY_ENDPOINT -}; \ No newline at end of file diff --git a/lib/server.js b/lib/server.js deleted file mode 100644 index 6096890..0000000 --- a/lib/server.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = Server; - -var _utils = require("hull/lib/utils"); - -var _updateUser = require("./update-user"); - -var _updateUser2 = _interopRequireDefault(_updateUser); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var NotifyHandler = (0, _utils.notifHandler)({ - handlers: { - "user:update": function userUpdate(_ref) { - var ship = _ref.ship, - hull = _ref.client; - var messages = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; - - return Promise.all(messages.map(function (message) { - return (0, _updateUser2.default)({ message: message }, { ship: ship, hull: hull }); - })); - } - } -}); - -function Server(app) { - app.post("/batch", NotifyHandler); - app.post("/notify", NotifyHandler); - return app; -} \ No newline at end of file diff --git a/lib/update-user.js b/lib/update-user.js deleted file mode 100644 index 7125397..0000000 --- a/lib/update-user.js +++ /dev/null @@ -1,146 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = updateUser; - -var _lodash = require("lodash"); - -var _lodash2 = _interopRequireDefault(_lodash); - -var _request = require("request"); - -var _request2 = _interopRequireDefault(_request); - -var _hogan = require("hogan.js"); - -var _hogan2 = _interopRequireDefault(_hogan); - -var _bluebird = require("bluebird"); - -var _bluebird2 = _interopRequireDefault(_bluebird); - -var _bottleneck = require("bottleneck"); - -var _bottleneck2 = _interopRequireDefault(_bottleneck); - -var _lruCache = require("lru-cache"); - -var _lruCache2 = _interopRequireDefault(_lruCache); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var Limiter = new _bottleneck2.default(1, 1000); - -var cache = (0, _lruCache2.default)({ max: 1000, maxAge: 24 * 3600 * 1000 }); // Max age 1 day - -function createUser(url, form) { - return new _bluebird2.default(function (resolve, reject) { - _request2.default.post({ url: url, form: form }, function (err, res) { - if (!err && res.statusCode < 400) { - resolve(res); - } else { - var error = err || new Error(res.body); - reject(error); - } - }); - }); -} - -// return updateUser({ message }, { ship, hull }); -function updateUser(_ref, _ref2) { - var _ref$message = _ref.message, - message = _ref$message === undefined ? {} : _ref$message; - var _ref2$ship = _ref2.ship, - ship = _ref2$ship === undefined ? {} : _ref2$ship, - hull = _ref2.hull, - _ref2$force = _ref2.force, - force = _ref2$force === undefined ? false : _ref2$force; - // eslint-disable-line consistent-return - hull.logger.debug("nutshell.user.update", message); - - var _message$user = message.user, - user = _message$user === undefined ? {} : _message$user, - _message$segments = message.segments, - segments = _message$segments === undefined ? [] : _message$segments; - - - if (!ship || !user || !user.id) { - return hull.logger.debug("nutshell.user.error", { message: "missing data", ship: ship, user: user }); - } - - // User has already been pushed to nutshell - if (!force && cache.get(user.id)) { - return hull.logger.warn("nutshell.user.skip", { message: "id in cache", id: user.id, email: user.email }); - } - // if (!force && user[`traits_nutshell/created_at`]) return hull.logger.warn("nutshell.user.skip",{ message: "already imported", id: user.id, email: user.email, nutshell_created_at: user[`traits_nutshell/created_at`] }); - - // Ignore if form_api_url is not present - - var _ref3 = ship.private_settings || {}, - form_api_url = _ref3.form_api_url, - synchronized_segments = _ref3.synchronized_segments, - mapping = _ref3.mapping; - - if (!form_api_url) return hull.logger.error("nutshell.error.credentials", { message: "missing form_api_url" }); - - if (!force && synchronized_segments.length > 0 && !_lodash2.default.intersection(_lodash2.default.map(segments, "id"), synchronized_segments).length) { - return hull.logger.warn("nutshell.user.skip", { message: "not matching any segments", user: user.id }); - } - - // Ignore if mapping is not defined - if (!mapping || !mapping.length) { - return hull.logger.info("nutshell.user.skip", { message: "no mapping defined", mapping: mapping }); - } - - var missingField = false; - var form = mapping.reduce(function (r, m) { - // eslint-disable-line array-callback-return, consistent-return - if (r) { - var value = void 0; - try { - value = _hogan2.default.compile(m.hull).render(user); - } catch (err) { - hull.logger.error("nutshell.user.template.error ", err.message); - } - - if (_lodash2.default.isEmpty(value)) { - if (m.is_required) { - missingField = m; - return false; - } - return r; - } - - return _lodash2.default.set(r, m.nutshell, value); - } - }, {}); - - var formEmail = _lodash2.default.get(form, "contact.email"); - - if (!force && formEmail && cache.get(formEmail)) { - return hull.logger.warn("nutshell.user.skip", { message: "email in cache", id: user.id, email: formEmail }); - } - - if (!form) { - return hull.logger.info("nutshell.user.skip", { message: "missing field", field: missingField, user: user }); - } - - hull.logger.warn("nutshell.user.create", { id: user.id, form: form }); - - cache.set(user.id, new Date().getTime()); - - if (formEmail) cache.set(formEmail, new Date().getTime()); - - Limiter.schedule(createUser, form_api_url, form).then(function () { - hull.logger.info("nutshell.user.create.success", { id: user.id, email: formEmail }); - return hull.asUser({ id: user.id }).traits({ created_at: new Date().toISOString() }, { source: "nutshell", sync: true }); - }, function (err) { - cache.del(user.id); - if (formEmail) { - cache.del(formEmail); - } - hull.logger.warn("nutshell.user.create.error", { id: user.id, err: JSON.stringify(err) }); - }); -} \ No newline at end of file diff --git a/manifest.json b/manifest.json index 4748de6..bae1205 100644 --- a/manifest.json +++ b/manifest.json @@ -3,6 +3,8 @@ "tags": ["outgoing","batch", "oneColumn", "smart-notifier"], "description" : "Send Users as Leads or Contacts to Nutshell with custom mappings", "version" : "0.3.0", + "source": "nutshell", + "logo": "logo.png", "picture": "picture.png", "ui": false, "readme" : "readme.md", diff --git a/package.json b/package.json index 62c7dfe..4198b08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hull-nutshell", - "version": "0.2.0", + "version": "0.3.0", "description": "Hull Nutshell CRM integration", "homepage": "https://github.com/hull-ships/hull-nutshell", "repository": { @@ -21,7 +21,7 @@ "engines": { "node": "8.11.x", "npm": "5.6.x", - "yarn": "1.5.x" + "yarn": "1.6.x" }, "scripts": { "build": "yarn run clean && yarn run build:server",