{"version":3,"sources":["jsdelivr-header.js","/npm/mongodb-activity-feed@0.2.3/dist/index.js"],"names":[],"mappings":"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","file":"/npm/mongodb-activity-feed@0.2.3/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/mongodb-activity-feed@0.2.3/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n\tvalue: true\n});\nexports.FeedManager = exports.FayeFirehose = exports.SocketIOFirehose = exports.DummyFirehose = exports.OPERATIONS = undefined;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _activity = require('./models/activity');\n\nvar _activity2 = _interopRequireDefault(_activity);\n\nvar _feed_group = require('./models/feed_group');\n\nvar _feed_group2 = _interopRequireDefault(_feed_group);\n\nvar _feed = require('./models/feed');\n\nvar _feed2 = _interopRequireDefault(_feed);\n\nvar _activity_feed = require('./models/activity_feed');\n\nvar _activity_feed2 = _interopRequireDefault(_activity_feed);\n\nvar _follow = require('./models/follow');\n\nvar _follow2 = _interopRequireDefault(_follow);\n\nvar _chunk = require('./utils/chunk');\n\nvar _chunk2 = _interopRequireDefault(_chunk);\n\nvar _redlock = require('redlock');\n\nvar _redlock2 = _interopRequireDefault(_redlock);\n\nvar _bull = require('bull');\n\nvar _bull2 = _interopRequireDefault(_bull);\n\nvar _faye = require('faye');\n\nvar _faye2 = _interopRequireDefault(_faye);\n\nvar _socket = require('socket.io-client');\n\nvar _socket2 = _interopRequireDefault(_socket);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }\n\nconst OPERATIONS = exports.OPERATIONS = { ADD_OPERATION: 1, REMOVE_OPERATION: 2 };\n\nconst updateOptions = { upsert: true, new: true\n\n\t// does nothing, just calls the callback with all the data\n};class DummyFirehose {\n\tconstructor(callback) {\n\t\tthis.callback = callback;\n\t}\n\tasync notify(byFeed) {\n\t\ttry {\n\t\t\tfor (const operations of Object.values(byFeed)) {\n\t\t\t\tlet feed = operations[0].feed;\n\t\t\t\tawait this.callback({ operations, feed });\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.log('failed to call the callback..', e);\n\t\t}\n\t}\n}\n\nexports.DummyFirehose = DummyFirehose; // socketio realtime notifications\n\nclass SocketIOFirehose {\n\tconstructor(socketIOUrl) {\n\t\tthis.url = socketIOUrl;\n\t\tthis.client = (0, _socket2.default)(socketIOUrl);\n\t}\n\tasync notify(byFeed) {\n\t\tfor (const operations of Object.values(byFeed)) {\n\t\t\tconst feed = operations[0].feed;\n\t\t\tconst channel = `feed-${feed.group.name}--${feed.feedID}`;\n\t\t\tconst message = { operations, feed, channel\n\t\t\t\t// server forwards this to message.channel\n\t\t\t};this.client.emit('firehose', message);\n\t\t}\n\t}\n}\n\nexports.SocketIOFirehose = SocketIOFirehose; // faye realtime notifications\n\nclass FayeFirehose {\n\tconstructor(fayeURL) {\n\t\tif (fayeURL.connection) {\n\t\t\tthis.fayeClient = fayeURL;\n\t\t} else {\n\t\t\tthis.fayeClient = new _faye2.default.Client(fayeURL, { timeout: 5, retry: 5 });\n\t\t}\n\t}\n\tasync notify(byFeed) {\n\t\tlet results = [];\n\n\t\tfor (const operations of Object.values(byFeed)) {\n\t\t\tlet feed = operations[0].feed;\n\t\t\tlet channel = `/feed-${feed.group.name}--${feed.feedID}`;\n\t\t\t// running more than one publish operation at the same time breaks faye...\n\n\t\t\tlet result = await this.fayeClient.publish(channel, { operations, feed });\n\t\t\tresults.push(result);\n\t\t}\n\n\t\treturn results;\n\t}\n}\n\nexports.FayeFirehose = FayeFirehose;\nclass FeedManager {\n\tconstructor(mongoConnection, redisConnection, options) {\n\t\tthis.mongoConnection = mongoConnection;\n\t\tthis.redisConnection = redisConnection;\n\t\tthis.redlock = this._createLock();\n\t\tthis.queue = new _bull2.default('activity feed', redisConnection);\n\t\tif (!options) {\n\t\t\toptions = {};\n\t\t}\n\t\tconst defaultOptions = { bull: false, firehose: false };\n\t\tthis.options = _extends({}, defaultOptions, options);\n\t}\n\n\tasync followMany(pairs, copyLimit = 300) {\n\t\t// start by using bulk writes to setup the follows\n\t\tlet operations = [];\n\t\tfor (const followInstruction of pairs) {\n\t\t\tlet document = {\n\t\t\t\tsource: followInstruction.source,\n\t\t\t\ttarget: followInstruction.target\n\t\t\t};\n\t\t\toperations.push({\n\t\t\t\tupdateOne: { filter: document, update: document, upsert: true }\n\t\t\t});\n\t\t}\n\t\tif (operations.length >= 1) {\n\t\t\ttry {\n\t\t\t\tawait _follow2.default.bulkWrite(operations, {\n\t\t\t\t\tordered: false\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\t// dont fail on records that already exist\n\t\t\t\tif (e.code !== 11000) throw e;\n\t\t\t}\n\t\t}\n\n\t\t// group by source\n\t\tif (copyLimit > 0) {\n\t\t\tlet grouped = {};\n\t\t\tfor (const followInstruction of pairs) {\n\t\t\t\tif (!(followInstruction.source in grouped)) {\n\t\t\t\t\tgrouped[followInstruction.source._id] = [];\n\t\t\t\t}\n\t\t\t\tgrouped[followInstruction.source._id].push(followInstruction.target._id);\n\t\t\t}\n\n\t\t\t// get the activity references\n\t\t\tfor (const [sourceID, targetIDs] of Object.entries(grouped)) {\n\t\t\t\tconst lock = await this.redlock.lock(`followLock${sourceID}`, 10 * 1000);\n\t\t\t\tconst activityReferences = await _activity_feed2.default.find({\n\t\t\t\t\tfeed: { $in: targetIDs }\n\t\t\t\t}).limit(copyLimit).sort({ time: -1, operationTime: -1 });\n\t\t\t\t// write these to the source feed in one go\n\t\t\t\tconst operations = [];\n\t\t\t\tfor (const reference of activityReferences) {\n\t\t\t\t\tlet document = reference.toObject();\n\t\t\t\t\tdocument._id = null;\n\t\t\t\t\tdocument.feed = sourceID;\n\t\t\t\t\toperations.push({ insertOne: { document } });\n\t\t\t\t}\n\t\t\t\t// call the bulk create\n\t\t\t\tif (operations.length >= 1) {\n\t\t\t\t\tawait _activity_feed2.default.bulkWrite(operations, { ordered: false });\n\t\t\t\t}\n\t\t\t\tawait lock.unlock();\n\t\t\t}\n\t\t}\n\t}\n\n\tasync follow(source, target, copyLimit = 300) {\n\t\tawait this.followMany([{ source, target }], copyLimit);\n\t}\n\n\tasync unfollow(source, target) {\n\t\tconst lock = await this.redlock.lock(`followLock${source._id}`, 10 * 1000);\n\n\t\t// create the follow relationship\n\t\tconst follow = await _follow2.default.findOneAndDelete({ source, target });\n\n\t\t// remove the activities with the given origin\n\t\tawait _activity_feed2.default.remove({\n\t\t\tfeed: source,\n\t\t\torigin: target\n\t\t});\n\n\t\tawait lock.unlock();\n\t\treturn follow;\n\t}\n\n\tasync addOrRemoveActivity(activityData, feed, operation) {\n\t\tif (!feed) {\n\t\t\tthrow Error(`missing feed ${feed}`);\n\t\t}\n\t\t// create the activity\n\t\tlet { actor, verb, object, target, time, foreign_id } = activityData,\n\t\t    extra = _objectWithoutProperties(activityData, ['actor', 'verb', 'object', 'target', 'time', 'foreign_id']);\n\t\tif (!time) {\n\t\t\ttime = new Date();\n\t\t}\n\t\tconst values = { actor, verb, object, target, time, foreign_id, extra };\n\n\t\tlet search;\n\t\tif (values.foreign_id) {\n\t\t\tsearch = { foreign_id: values.foreign_id, time: values.time };\n\t\t} else {\n\t\t\tsearch = _extends({}, values);\n\t\t}\n\t\tconst activity = await _activity2.default.findOneAndUpdate(search, values, {\n\t\t\tupsert: true,\n\t\t\tnew: true\n\t\t});\n\n\t\t// create the activity feed for the primary feed\n\t\tlet op = await _activity_feed2.default.create({\n\t\t\tfeed: feed,\n\t\t\tactivity: activity,\n\t\t\toperation: operation,\n\t\t\ttime: activity.time,\n\t\t\torigin: feed\n\t\t});\n\t\tawait this.notify([op]);\n\n\t\t// fanout to the followers in batches\n\t\tconst followers = await _follow2.default.find({ target: feed }).sort({ target: -1 });\n\t\tconst groups = (0, _chunk2.default)(followers, 500);\n\t\tlet origin = feed;\n\t\tlet promises = [];\n\t\tfor (const group of groups) {\n\t\t\tif (this.options.bull) {\n\t\t\t\tconst promise = this.queue.add({\n\t\t\t\t\targs: [activity, group, origin, operation]\n\t\t\t\t});\n\t\t\t\tpromises.push(promise);\n\t\t\t} else {\n\t\t\t\tconst promise = this._fanout(activity, group, origin, operation);\n\t\t\t\tpromises.push(promise);\n\t\t\t}\n\t\t}\n\t\tif (promises.length > 0) {\n\t\t\tawait Promise.all(promises);\n\t\t}\n\n\t\treturn activity;\n\t}\n\n\tasync _fanout(activity, group, origin, operation) {\n\t\tlet bulkWrites = [];\n\t\tlet operations = [];\n\t\tfor (const follow of group) {\n\t\t\tif (!follow.source) {\n\t\t\t\tthrow Error(`missing follow.source ${follow}`);\n\t\t\t}\n\t\t\tlet document = {\n\t\t\t\tfeed: follow.source,\n\t\t\t\tactivity: activity,\n\t\t\t\toperation: operation,\n\t\t\t\ttime: activity.time,\n\t\t\t\torigin\n\t\t\t};\n\t\t\toperations.push(document);\n\t\t\tbulkWrites.push({ insertOne: { document } });\n\t\t}\n\t\tif (operations.length >= 1) {\n\t\t\tawait _activity_feed2.default.bulkWrite(bulkWrites, { ordered: false });\n\t\t\tawait this.notify(operations);\n\t\t}\n\t}\n\n\tasync getFeedGroupMap() {\n\t\tconst feedGroups = await _feed_group2.default.find({});\n\t\tconst feedGroupMap = {};\n\t\tfor (const group of feedGroups) {\n\t\t\tfeedGroupMap[group.id] = group;\n\t\t}\n\t\treturn feedGroupMap;\n\t}\n\n\tasync notify(operations) {\n\t\tconst byFeed = {};\n\t\tconst feedGroupMap = await this.getFeedGroupMap();\n\n\t\tif (this.options.firehose !== false) {\n\t\t\tfor (const operation of operations) {\n\t\t\t\t// make sure we add the full group if its missing\n\t\t\t\tif (!operation.feed.group.name) {\n\t\t\t\t\tlet groupID = operation.feed.group._id || operation.feed.group;\n\t\t\t\t\tif (!feedGroupMap[groupID]) {\n\t\t\t\t\t\tthrow Error(`cant find feedgroup with id ${groupID}`);\n\t\t\t\t\t}\n\t\t\t\t\toperation.feed.group = feedGroupMap[groupID];\n\t\t\t\t}\n\n\t\t\t\tif (!(operation.feed._id in byFeed)) {\n\t\t\t\t\tbyFeed[operation.feed._id] = [];\n\t\t\t\t}\n\t\t\t\tbyFeed[operation.feed._id].push(operation);\n\t\t\t}\n\t\t\tawait this.options.firehose.notify(byFeed);\n\t\t}\n\t}\n\n\tasync readFeed(feed, offset, limit, rankingMethod, aggregationMethod) {\n\t\t// read the feed sorted by the activity time\n\t\tconst searchDepth = 1000;\n\t\tconst operations = await _activity_feed2.default.find({ feed }).sort({ time: -1, operationTime: -1 }).limit(searchDepth);\n\t\t// next order by the operationTime to handle scenarios where people add/remove\n\t\toperations.sort((a, b) => {\n\t\t\treturn b.operationTime - a.operationTime;\n\t\t});\n\t\t// TODO: there are edge cases here with add/remove on older activities\n\t\t// For example if you add 1 activity with a recent time 1500 times and remove it 1500 times.\n\t\t// Next you add an activity with an older time\n\t\t// the feed will show up empty\n\t\tconst seen = {};\n\t\tconst activities = [];\n\t\tfor (const activityOperation of operations) {\n\t\t\tif (activityOperation.activity in seen) {\n\t\t\t\t// ignore\n\t\t\t} else {\n\t\t\t\tif (activityOperation.operation === OPERATIONS.ADD_OPERATION) {\n\t\t\t\t\tactivities.push(activityOperation.activity);\n\t\t\t\t}\n\t\t\t\tseen[activityOperation.activity] = true;\n\t\t\t}\n\t\t}\n\t\t// add the extra properties back to the object\n\t\tlet serialized = [];\n\n\t\tfor (const activity of activities) {\n\t\t\tlet activityData = activity.toObject();\n\t\t\tlet { extra } = activityData,\n\t\t\t    others = _objectWithoutProperties(activityData, ['extra']);\n\t\t\tlet serializedActivity = _extends({}, extra, others);\n\t\t\tserialized.push(serializedActivity);\n\t\t}\n\n\t\tif (aggregationMethod && rankingMethod) {\n\t\t\tthrow new Error('cant use both ranking and aggregation at the same time');\n\t\t}\n\n\t\t// support aggregation\n\t\tlet aggregated;\n\t\tif (aggregationMethod) {\n\t\t\taggregated = {};\n\t\t\tfor (const activity of serialized) {\n\t\t\t\tconst key = aggregationMethod(activity);\n\t\t\t\tif (!(key in aggregated)) {\n\t\t\t\t\taggregated[key] = { group: key, time: activity.time, activities: [] };\n\t\t\t\t}\n\t\t\t\taggregated[key].activities.push(activity);\n\t\t\t}\n\t\t\tserialized = Object.values(aggregated);\n\t\t}\n\n\t\t// ensure that we are sorted by time and not operation time\n\t\tif (rankingMethod) {\n\t\t\tserialized.sort(rankingMethod);\n\t\t} else {\n\t\t\tserialized.sort((a, b) => {\n\t\t\t\treturn b.time - a.time;\n\t\t\t});\n\t\t}\n\n\t\tlet selectedActivities = serialized.slice(offset, limit);\n\n\t\treturn selectedActivities;\n\t}\n\n\tasync getOrCreateFeed(group, feedID) {\n\t\tconst feedMap = await this.getOrCreateFeeds([{ group, feedID }]);\n\t\treturn feedMap[group][feedID];\n\t}\n\n\tasync getOrCreateFeeds(feedReferences) {\n\t\t// step one, setup all the groups\n\t\tconst feedsByGroup = [];\n\t\tconst groupMap = {};\n\t\tconst groupIDMap = {};\n\t\tfor (const feedReference of feedReferences) {\n\t\t\tif (!(feedReference.group in feedsByGroup)) {\n\t\t\t\tfeedsByGroup[feedReference.group] = [];\n\t\t\t}\n\t\t\tfeedsByGroup[feedReference.group].push(feedReference.feedID);\n\t\t}\n\t\tfor (const name of Object.keys(feedsByGroup)) {\n\t\t\tconst group = await _feed_group2.default.findOneAndUpdate({ name }, { name }, updateOptions);\n\t\t\tgroupMap[name] = group;\n\t\t\tgroupIDMap[group._id] = group;\n\t\t}\n\t\t// step two, create the feeds\n\t\tlet operations = [];\n\t\tfor (const feedReference of feedReferences) {\n\t\t\tlet document = {\n\t\t\t\tgroup: groupMap[feedReference.group],\n\t\t\t\tfeedID: feedReference.feedID\n\t\t\t};\n\t\t\toperations.push({\n\t\t\t\tupdateOne: { filter: document, update: document, upsert: true }\n\t\t\t});\n\t\t}\n\t\tlet bulkResponse;\n\t\tif (operations.length >= 1) {\n\t\t\tbulkResponse = await _feed2.default.bulkWrite(operations, { ordered: false });\n\t\t}\n\n\t\t// step three, read the feeds and return the feedmap\n\t\tconst feedMap = {};\n\t\tfor (const groupName of Object.keys(feedsByGroup)) {\n\t\t\tfeedMap[groupName] = {};\n\t\t}\n\t\t// lookup the objects, there doesn't seem to be a better way to do this\n\t\t// bulkWrite doesn't return the ids for things that didn't change...\n\t\tlet conditions = [];\n\t\tfor (const [groupName, feedIDs] of Object.entries(feedsByGroup)) {\n\t\t\tconditions.push({\n\t\t\t\tfeedID: { $in: feedIDs },\n\t\t\t\tgroup: groupMap[groupName]._id\n\t\t\t});\n\t\t}\n\t\tconst feeds = await _feed2.default.find({ $or: conditions });\n\t\tfor (const feed of feeds) {\n\t\t\tconst group = groupIDMap[feed.group];\n\t\t\tfeedMap[group.name][feed.feedID] = feed;\n\t\t}\n\n\t\treturn feedMap;\n\t}\n\n\tasync addActivity(activityData, feed) {\n\t\treturn await this.addOrRemoveActivity(activityData, feed, OPERATIONS.ADD_OPERATION);\n\t}\n\n\tasync removeActivity(activityData, feed) {\n\t\treturn await this.addOrRemoveActivity(activityData, feed, OPERATIONS.REMOVE_OPERATION);\n\t}\n\n\t_createLock() {\n\t\tlet redlock = new _redlock2.default(\n\t\t// you should have one client for each independent redis node\n\t\t// or cluster\n\t\t[this.redisConnection], {\n\t\t\t// the expected clock drift; for more details\n\t\t\t// see http://redis.io/topics/distlock\n\t\t\tdriftFactor: 0.01, // time in ms\n\n\t\t\t// the max number of times Redlock will attempt\n\t\t\t// to lock a resource before erroring\n\t\t\tretryCount: 3,\n\n\t\t\t// the time in ms between attempts\n\t\t\tretryDelay: 300, // time in ms\n\n\t\t\t// the max time in ms randomly added to retries\n\t\t\t// to improve performance under high contention\n\t\t\t// see https://www.awsarchitectureblog.com/2015/03/backoff.html\n\t\t\tretryJitter: 200 // time in ms\n\t\t});\n\t\treturn redlock;\n\t}\n}\nexports.FeedManager = FeedManager;"]}