UNPKG

@vivianhealth/braze-segment-debounce

Version:

Segment utilities to debounce data before it reaches the Braze destination

188 lines (156 loc) 7.48 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.debouncePayload = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _index = require("./index"); var _utils = require("./utils"); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } /** * Default serialize function for the server * @param {object|array|null|string|number} value * @return {Buffer} */ var serializeAsJSONForCache = function serializeAsJSONForCache(value) { return Buffer.from(JSON.stringify(value), 'utf8'); }; /** * Default deserialize function for frontend * @param {Buffer} serializedValue * @return {object|array|null|string|number} */ var deserializeFromJSONForCache = function deserializeFromJSONForCache(serializedValue) { return JSON.parse(serializedValue.toString('utf8')); }; /* * `debouncePayload` is meant to work with `anayltics-node`. It does not * require middleware like the frontend but it does rely on a caching * or storage mechanism that the user provides. Similar to * `debouncePayloadSync`, it stores previous payloads using the storage * mechanism, and compares the `payload` to be sent to Segment/Braze * against the previous versions so that it only sends new or updated * `traits`. * @param {Object} payload The data to be sent to Segment/Braze * @param {Function} fetchPayload A function to retrieve previous payloads * @param {Function} persistPayload A function to store previous payloads * @param {Function} options.serializePayload An optional function to * override the default serializer * @param {Function} options.deserializePayload An optional function to * override the default deserialize * @return {Object} The debounced payload to send to Braze. If `null`, * there is no new or updated data to send. * @example * ``` * import _isNil from 'lodash/isNil'; * import Analytics from 'analytics-node'; * import memjs from 'memjs'; * import { debouncePayload } from 'braze-segment-debounce/server'; * * const segmentWriteKey = 'YOUR-SEGMENT-WRITE-KEY'; * const analytics = new Analytics(segmentWriteKey); * const cache = memjs.Client.create(); * const fetchPayload = async (k) => cache.get(k); * const persistPayload = async (k, v) => { * await cache.set(k, v, { expires: 3600 }); * }; * * const identifyWithDebounce = async (payload) => { * // TODO filter Braze integration, called `AppBoy`, if possible * const identifyPayload = await debouncePayload( * payload, * fetchPayload, * persistPayload, * ); * if (!_isNil(identifyPayload)) { * return analytics.identify(identifyPayload); * } * return null; * }; * ``` */ var debouncePayload = /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(payload, fetchPayload, persistPayload) { var _ref2, _ref2$serializePayloa, serializePayload, _ref2$deserializePayl, deserializePayload, getPayloadProperty, key, parsedPreviousPayload, rawPreviousPayload, previousPayload, sanitizedPayload, _debouncePayloads, nextPayload, newOrUpdatedTraits, debouncedPayload, previousPayloadToStore, _args = arguments; return _regenerator.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _ref2 = _args.length > 3 && _args[3] !== undefined ? _args[3] : {}, _ref2$serializePayloa = _ref2.serializePayload, serializePayload = _ref2$serializePayloa === void 0 ? serializeAsJSONForCache : _ref2$serializePayloa, _ref2$deserializePayl = _ref2.deserializePayload, deserializePayload = _ref2$deserializePayl === void 0 ? deserializeFromJSONForCache : _ref2$deserializePayl; getPayloadProperty = function getPayloadProperty(payload, prop) { return payload[prop]; }; key = (0, _utils.getPayloadKey)(payload, getPayloadProperty); parsedPreviousPayload = null; _context.prev = 4; _context.next = 7; return fetchPayload(key); case 7: rawPreviousPayload = _context.sent; if (rawPreviousPayload) { parsedPreviousPayload = deserializePayload(rawPreviousPayload); } _context.next = 14; break; case 11: _context.prev = 11; _context.t0 = _context["catch"](4); console.error('debouncePayload: failed to fetch previous payload for debouncing'); case 14: previousPayload = parsedPreviousPayload || {}; // Remove undefined fields sanitizedPayload = deserializePayload(serializePayload(payload)); _debouncePayloads = (0, _index.debouncePayloads)(previousPayload, sanitizedPayload, getPayloadProperty), nextPayload = _debouncePayloads.nextPayload, newOrUpdatedTraits = _debouncePayloads.newOrUpdatedTraits; if (!nextPayload) { _context.next = 29; break; } debouncedPayload = _objectSpread(_objectSpread({}, nextPayload), {}, { traits: newOrUpdatedTraits || nextPayload.traits }); previousPayloadToStore = (0, _utils.combinePreviousPayloads)([previousPayload, sanitizedPayload]); _context.prev = 20; _context.next = 23; return persistPayload(key, serializePayload(previousPayloadToStore)); case 23: _context.next = 28; break; case 25: _context.prev = 25; _context.t1 = _context["catch"](20); console.error('debouncePayload: failed to store previous payload for debouncing'); case 28: return _context.abrupt("return", debouncedPayload); case 29: return _context.abrupt("return", null); case 30: case "end": return _context.stop(); } } }, _callee, null, [[4, 11], [20, 25]]); })); return function debouncePayload(_x, _x2, _x3) { return _ref.apply(this, arguments); }; }(); exports.debouncePayload = debouncePayload;