UNPKG

getstream

Version:

The official low-level GetStream.io client for Node.js and the browser.

454 lines (436 loc) 19.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.StreamFeed = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _user = require("./user"); var _errors = require("./errors"); var _utils = _interopRequireDefault(require("./utils")); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /// <reference path="../types/modules.d.ts" /> /** * Manage api calls for specific feeds * The feed object contains convenience functions such add activity, remove activity etc * @class StreamFeed */ var StreamFeed = exports.StreamFeed = /*#__PURE__*/function () { /** * Initialize a feed object * @link https://getstream.io/activity-feeds/docs/node/adding_activities/?language=js * @method constructor * @memberof StreamFeed.prototype * @param {StreamClient} client - The stream client this feed is constructed from * @param {string} feedSlug - The feed slug * @param {string} userId - The user id * @param {string} [token] - The authentication token */ function StreamFeed(client, feedSlug, userId, token) { (0, _classCallCheck2.default)(this, StreamFeed); (0, _defineProperty2.default)(this, "client", void 0); (0, _defineProperty2.default)(this, "token", void 0); (0, _defineProperty2.default)(this, "id", void 0); (0, _defineProperty2.default)(this, "slug", void 0); (0, _defineProperty2.default)(this, "userId", void 0); (0, _defineProperty2.default)(this, "feedUrl", void 0); (0, _defineProperty2.default)(this, "feedTogether", void 0); (0, _defineProperty2.default)(this, "notificationChannel", void 0); if (!feedSlug || !userId) { throw new _errors.FeedError('Please provide a feed slug and user id, ie client.feed("user", "1")'); } if (feedSlug.indexOf(':') !== -1) { throw new _errors.FeedError('Please initialize the feed using client.feed("user", "1") not client.feed("user:1")'); } _utils.default.validateFeedSlug(feedSlug); _utils.default.validateUserId(userId); // raise an error if there is no token if (!token) { throw new _errors.FeedError('Missing token, in client side mode please provide a feed secret'); } this.client = client; this.slug = feedSlug; this.userId = userId; this.id = "".concat(this.slug, ":").concat(this.userId); this.token = token; this.feedUrl = this.id.replace(':', '/'); this.feedTogether = this.id.replace(':', ''); // faye setup this.notificationChannel = "site-".concat(this.client.appId, "-feed-").concat(this.feedTogether); } /** * Adds the given activity to the feed * @link https://getstream.io/activity-feeds/docs/node/adding_activities/?language=js#adding-activities-basic * @method addActivity * @memberof StreamFeed.prototype * @param {NewActivity<StreamFeedGenerics>} activity - The activity to add * @return {Promise<Activity<StreamFeedGenerics>>} */ (0, _createClass2.default)(StreamFeed, [{ key: "addActivity", value: function addActivity(activity) { activity = _utils.default.replaceStreamObjects(activity); if (!activity.actor && this.client.currentUser) { activity.actor = this.client.currentUser.ref(); } return this.client.post({ url: "feed/".concat(this.feedUrl, "/"), body: activity, token: this.token }); } /** * Removes the activity by activityId or foreignId * @link https://getstream.io/activity-feeds/docs/node/adding_activities/?language=js#removing-activities * @method removeActivity * @memberof StreamFeed.prototype * @param {string} activityOrActivityId Identifier of activity to remove * @return {Promise<APIResponse & { removed: string }>} * @example feed.removeActivity(activityId); * @example feed.removeActivity({'foreign_id': foreignId}); */ }, { key: "removeActivity", value: function removeActivity(activityOrActivityId) { var foreign_id = activityOrActivityId.foreignId || activityOrActivityId.foreign_id; return this.client.delete({ url: "feed/".concat(this.feedUrl, "/").concat(foreign_id || activityOrActivityId, "/"), qs: foreign_id ? { foreign_id: '1' } : {}, token: this.token }); } /** * Adds the given activities to the feed * @link https://getstream.io/activity-feeds/docs/node/add_many_activities/?language=js#batch-add-activities * @method addActivities * @memberof StreamFeed.prototype * @param {NewActivity<StreamFeedGenerics>[]} activities Array of activities to add * @return {Promise<Activity<StreamFeedGenerics>[]>} */ }, { key: "addActivities", value: function addActivities(activities) { return this.client.post({ url: "feed/".concat(this.feedUrl, "/"), body: { activities: _utils.default.replaceStreamObjects(activities) }, token: this.token }); } /** * Follows the given target feed * @link https://getstream.io/activity-feeds/docs/node/following/?language=js * @method follow * @memberof StreamFeed.prototype * @param {string} targetSlug Slug of the target feed * @param {string} targetUserId User identifier of the target feed * @param {object} [options] Additional options * @param {number} [options.limit] Limit the amount of activities copied over on follow * @return {Promise<APIResponse>} * @example feed.follow('user', '1'); * @example feed.follow('user', '1'); * @example feed.follow('user', '1', options); */ }, { key: "follow", value: function follow(targetSlug, targetUserId) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; if (targetUserId instanceof _user.StreamUser) { targetUserId = targetUserId.id; } _utils.default.validateFeedSlug(targetSlug); _utils.default.validateUserId(targetUserId); var body = { target: "".concat(targetSlug, ":").concat(targetUserId) }; if (typeof options.limit === 'number') body.activity_copy_limit = options.limit; return this.client.post({ url: "feed/".concat(this.feedUrl, "/following/"), body: body, token: this.token }); } /** * Unfollow the given feed * @link https://getstream.io/activity-feeds/docs/node/following/?language=js#unfollowing-feeds * @method unfollow * @memberof StreamFeed.prototype * @param {string} targetSlug Slug of the target feed * @param {string} targetUserId User identifier of the target feed * @param {object} [options] * @param {boolean} [options.keepHistory] when provided the activities from target * feed will not be kept in the feed * @return {Promise<APIResponse>} * @example feed.unfollow('user', '2'); */ }, { key: "unfollow", value: function unfollow(targetSlug, targetUserId) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var qs = {}; if (typeof options.keepHistory === 'boolean' && options.keepHistory) qs.keep_history = '1'; _utils.default.validateFeedSlug(targetSlug); _utils.default.validateUserId(targetUserId); var targetFeedId = "".concat(targetSlug, ":").concat(targetUserId); return this.client.delete({ url: "feed/".concat(this.feedUrl, "/following/").concat(targetFeedId, "/"), qs: qs, token: this.token }); } /** * List which feeds this feed is following * @link https://getstream.io/activity-feeds/docs/node/following/?language=js#reading-followed-feeds * @method following * @memberof StreamFeed.prototype * @param {GetFollowOptions} [options] Additional options * @param {string[]} options.filter array of feed id to filter on * @param {number} options.limit pagination * @param {number} options.offset pagination * @return {Promise<GetFollowAPIResponse>} * @example feed.following({limit:10, filter: ['user:1', 'user:2']}); */ }, { key: "following", value: function following() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var extraOptions = {}; if (options.filter) extraOptions.filter = options.filter.join(','); return this.client.get({ url: "feed/".concat(this.feedUrl, "/following/"), qs: _objectSpread(_objectSpread({}, options), extraOptions), token: this.token }); } /** * List the followers of this feed * @link https://getstream.io/activity-feeds/docs/node/following/?language=js#reading-feed-followers * @method followers * @memberof StreamFeed.prototype * @param {GetFollowOptions} [options] Additional options * @param {string[]} options.filter array of feed id to filter on * @param {number} options.limit pagination * @param {number} options.offset pagination * @return {Promise<GetFollowAPIResponse>} * @example feed.followers({limit:10, filter: ['user:1', 'user:2']}); */ }, { key: "followers", value: function followers() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var extraOptions = {}; if (options.filter) extraOptions.filter = options.filter.join(','); return this.client.get({ url: "feed/".concat(this.feedUrl, "/followers/"), qs: _objectSpread(_objectSpread({}, options), extraOptions), token: this.token }); } /** * Retrieve the number of follower and following feed stats of the current feed. * For each count, feed slugs can be provided to filter counts accordingly. * @link https://getstream.io/activity-feeds/docs/node/following/?language=js#reading-follow-stats * @method followStats * @param {object} [options] * @param {string[]} [options.followerSlugs] find counts only on these slugs * @param {string[]} [options.followingSlugs] find counts only on these slugs * @return {Promise<FollowStatsAPIResponse>} * @example feed.followStats(); * @example feed.followStats({ followerSlugs:['user', 'news'], followingSlugs:['timeline'] }); */ }, { key: "followStats", value: function followStats() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var qs = { followers: this.id, following: this.id }; if (options.followerSlugs && options.followerSlugs.length) qs.followers_slugs = options.followerSlugs.join(','); if (options.followingSlugs && options.followingSlugs.length) qs.following_slugs = options.followingSlugs.join(','); return this.client.get({ url: 'stats/follow/', qs: qs, token: this.client.getOrCreateToken() || this.token }); } /** * Reads the feed * @link https://getstream.io/activity-feeds/docs/node/adding_activities/?language=js#retrieving-activities * @method get * @memberof StreamFeed.prototype * @param {GetFeedOptions} options Additional options * @return {Promise<FeedAPIResponse>} * @example feed.get({limit: 10, id_lte: 'activity-id'}) * @example feed.get({limit: 10, mark_seen: true}) */ }, { key: "get", value: function get() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var extraOptions = {}; if (options.mark_read && options.mark_read.join) { extraOptions.mark_read = options.mark_read.join(','); } if (options.mark_seen && options.mark_seen.join) { extraOptions.mark_seen = options.mark_seen.join(','); } this.client.replaceReactionOptions(options); var path = this.client.shouldUseEnrichEndpoint(options) ? 'enrich/feed/' : 'feed/'; return this.client.get({ url: "".concat(path).concat(this.feedUrl, "/"), qs: _objectSpread(_objectSpread({}, options), extraOptions), token: this.token }); } /** * Retrieves one activity from a feed and adds enrichment * @link https://getstream.io/activity-feeds/docs/node/adding_activities/?language=js#retrieving-activities * @method getActivityDetail * @memberof StreamFeed.prototype * @param {string} activityId Identifier of activity to retrieve * @param {EnrichOptions} options Additional options * @return {Promise<FeedAPIResponse>} * @example feed.getActivityDetail(activityId) * @example feed.getActivityDetail(activityId, {withRecentReactions: true}) * @example feed.getActivityDetail(activityId, {withReactionCounts: true}) * @example feed.getActivityDetail(activityId, {withScoreVars: true}) * @example feed.getActivityDetail(activityId, {withOwnReactions: true, withReactionCounts: true}) */ }, { key: "getActivityDetail", value: function getActivityDetail(activityId, options) { return this.get(_objectSpread({ id_lte: activityId, id_gte: activityId, limit: 1 }, options || {})); } /** * Returns the current faye client object * @method getFayeClient * @memberof StreamFeed.prototype * @access private * @return {Faye.Client} Faye client */ }, { key: "getFayeClient", value: function getFayeClient() { return this.client.getFayeClient(); } /** * Subscribes to any changes in the feed, return a promise * @link https://getstream.io/activity-feeds/docs/node/web_and_mobile/?language=js#subscribe-to-realtime-updates-via-api-client * @method subscribe * @memberof StreamFeed.prototype * @param {function} Faye.Callback<RealTimeMessage<StreamFeedGenerics>> Callback to call on completion * @return {Promise<Faye.Subscription>} * @example * feed.subscribe(callback).then(function(){ * console.log('we are now listening to changes'); * }); */ }, { key: "subscribe", value: function subscribe(callback) { if (!this.client.appId) { throw new _errors.SiteError('Missing app id, which is needed to subscribe, use var client = stream.connect(key, secret, appId);'); } var subscription = this.getFayeClient().subscribe("/".concat(this.notificationChannel), callback); this.client.subscriptions["/".concat(this.notificationChannel)] = { token: this.token, userId: this.notificationChannel, fayeSubscription: subscription }; return subscription; } /** * Cancel updates created via feed.subscribe() * @link https://getstream.io/activity-feeds/docs/node/web_and_mobile/?language=js#subscribe-to-realtime-updates-via-api-client * @return void */ }, { key: "unsubscribe", value: function unsubscribe() { var streamSubscription = this.client.subscriptions["/".concat(this.notificationChannel)]; if (streamSubscription) { delete this.client.subscriptions["/".concat(this.notificationChannel)]; streamSubscription.fayeSubscription.cancel(); } } }, { key: "_validateToTargetInput", value: function _validateToTargetInput(foreignId, time, newTargets, addedTargets, removedTargets) { if (!foreignId) throw new Error('Missing `foreign_id` parameter!'); if (!time) throw new Error('Missing `time` parameter!'); if (!newTargets && !addedTargets && !removedTargets) { throw new Error('Requires you to provide at least one parameter for `newTargets`, `addedTargets`, or `removedTargets` - example: `updateActivityToTargets("foreignID:1234", new Date(), [newTargets...], [addedTargets...], [removedTargets...])`'); } if (newTargets) { if (addedTargets || removedTargets) { throw new Error("Can't include add_targets or removedTargets if you're also including newTargets"); } } if (addedTargets && removedTargets) { // brute force - iterate through added, check to see if removed contains that element addedTargets.forEach(function (addedTarget) { if (removedTargets.includes(addedTarget)) { throw new Error("Can't have the same feed ID in addedTargets and removedTargets."); } }); } } /** * Updates an activity's "to" fields * @link https://getstream.io/activity-feeds/docs/node/targeting/?language=js * @param {string} foreignId The foreign_id of the activity to update * @param {string} time The time of the activity to update * @param {string[]} newTargets Set the new "to" targets for the activity - will remove old targets * @param {string[]} addedTargets Add these new targets to the activity * @param {string[]} removedTargets Remove these targets from the activity */ }, { key: "updateActivityToTargets", value: function updateActivityToTargets(foreignId, time, newTargets, addedTargets, removedTargets) { return this._updateActivityToTargetsMany([{ foreignId: foreignId, time: time, newTargets: newTargets, addedTargets: addedTargets, removedTargets: removedTargets }]); } // NOTE: it can change without notice }, { key: "_updateActivityToTargetsMany", value: function _updateActivityToTargetsMany(inputs) { if (!inputs || inputs.length === 0) { throw new Error('At least one input is required'); } var body = []; for (var i = 0; i < inputs.length; i++) { var input = inputs[i]; this._validateToTargetInput(input.foreignId, input.time, input.newTargets, input.addedTargets, input.removedTargets); var item = { foreign_id: input.foreignId, time: input.time }; if (input.newTargets) item.new_targets = input.newTargets; if (input.addedTargets) item.added_targets = input.addedTargets; if (input.removedTargets) item.removed_targets = input.removedTargets; body.push(item); } return this.client.post({ url: "feed_targets/".concat(this.feedUrl, "/activity_to_targets/"), token: this.token, body: body.length > 1 ? body : body[0] }); } }]); return StreamFeed; }();