add User type and allow lbryinc types to be used by apps
This commit is contained in:
parent
66a719ebfb
commit
09c9a6ca2b
17 changed files with 1748 additions and 1111 deletions
|
@ -25,6 +25,7 @@
|
|||
"import/no-commonjs": "warn",
|
||||
"import/no-amd": "warn",
|
||||
"import/prefer-default-export": "ignore",
|
||||
"flowtype/generic-spacing": 0,
|
||||
"func-names": ["warn", "as-needed"],
|
||||
"no-plusplus": 0
|
||||
}
|
||||
|
|
548
dist/bundle.es.js
vendored
548
dist/bundle.es.js
vendored
|
@ -86,9 +86,7 @@ const SET_SYNC_COMPLETED = 'SET_SYNC_COMPLETED';
|
|||
const SET_DEFAULT_ACCOUNT = 'SET_DEFAULT_ACCOUNT';
|
||||
const SYNC_APPLY_STARTED = 'SYNC_APPLY_STARTED';
|
||||
const SYNC_APPLY_COMPLETED = 'SYNC_APPLY_COMPLETED';
|
||||
const SYNC_APPLY_FAILED = 'SYNC_APPLY_FAILED'; // User
|
||||
|
||||
const USER_SETTINGS_POPULATE = 'USER_SETTINGS_POPULATE';
|
||||
const SYNC_APPLY_FAILED = 'SYNC_APPLY_FAILED';
|
||||
|
||||
var action_types = /*#__PURE__*/Object.freeze({
|
||||
GENERATE_AUTH_TOKEN_FAILURE: GENERATE_AUTH_TOKEN_FAILURE,
|
||||
|
@ -161,8 +159,7 @@ var action_types = /*#__PURE__*/Object.freeze({
|
|||
SET_DEFAULT_ACCOUNT: SET_DEFAULT_ACCOUNT,
|
||||
SYNC_APPLY_STARTED: SYNC_APPLY_STARTED,
|
||||
SYNC_APPLY_COMPLETED: SYNC_APPLY_COMPLETED,
|
||||
SYNC_APPLY_FAILED: SYNC_APPLY_FAILED,
|
||||
USER_SETTINGS_POPULATE: USER_SETTINGS_POPULATE
|
||||
SYNC_APPLY_FAILED: SYNC_APPLY_FAILED
|
||||
});
|
||||
|
||||
const Lbryio = {
|
||||
|
@ -638,6 +635,273 @@ var subscriptions = handleActions({
|
|||
})
|
||||
}, defaultState);
|
||||
|
||||
function swapKeyAndValue(dict) {
|
||||
const ret = {}; // eslint-disable-next-line no-restricted-syntax
|
||||
|
||||
for (const key in dict) {
|
||||
if (dict.hasOwnProperty(key)) {
|
||||
ret[dict[key]] = key;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const selectState = state => state.subscriptions || {}; // Returns the list of channel uris a user is subscribed to
|
||||
|
||||
|
||||
const selectSubscriptions = reselect.createSelector(selectState, state => state.subscriptions); // Fetching list of users subscriptions
|
||||
|
||||
const selectIsFetchingSubscriptions = reselect.createSelector(selectState, state => state.loading); // The current view mode on the subscriptions page
|
||||
|
||||
const selectViewMode = reselect.createSelector(selectState, state => state.viewMode); // Suggested subscriptions from internal apis
|
||||
|
||||
const selectSuggested = reselect.createSelector(selectState, state => state.suggested);
|
||||
const selectIsFetchingSuggested = reselect.createSelector(selectState, state => state.loadingSuggested);
|
||||
const selectSuggestedChannels = reselect.createSelector(selectSubscriptions, selectSuggested, (userSubscriptions, suggested) => {
|
||||
if (!suggested) {
|
||||
return null;
|
||||
} // Swap the key/value because we will use the uri for everything, this just makes it easier
|
||||
// suggested is returned from the api with the form:
|
||||
// {
|
||||
// featured: { "Channel label": uri, ... },
|
||||
// top_subscribed: { "@channel": uri, ... }
|
||||
// top_bid: { "@channel": uri, ... }
|
||||
// }
|
||||
// To properly compare the suggested subscriptions from our current subscribed channels
|
||||
// We only care about the uri, not the label
|
||||
// We also only care about top_subscribed and featured
|
||||
// top_bid could just be porn or a channel with no content
|
||||
|
||||
|
||||
const topSubscribedSuggestions = swapKeyAndValue(suggested[SUGGESTED_TOP_SUBSCRIBED]);
|
||||
const featuredSuggestions = swapKeyAndValue(suggested[SUGGESTED_FEATURED]); // Make sure there are no duplicates
|
||||
// If a uri isn't already in the suggested object, add it
|
||||
|
||||
const suggestedChannels = { ...topSubscribedSuggestions
|
||||
};
|
||||
Object.keys(featuredSuggestions).forEach(uri => {
|
||||
if (!suggestedChannels[uri]) {
|
||||
const channelLabel = featuredSuggestions[uri];
|
||||
suggestedChannels[uri] = channelLabel;
|
||||
}
|
||||
});
|
||||
userSubscriptions.forEach(({
|
||||
uri
|
||||
}) => {
|
||||
// Note to passer bys:
|
||||
// Maybe we should just remove the `lbry://` prefix from subscription uris
|
||||
// Most places don't store them like that
|
||||
const subscribedUri = uri.slice('lbry://'.length);
|
||||
|
||||
if (suggestedChannels[subscribedUri]) {
|
||||
delete suggestedChannels[subscribedUri];
|
||||
}
|
||||
});
|
||||
return Object.keys(suggestedChannels).map(uri => ({
|
||||
uri,
|
||||
label: suggestedChannels[uri]
|
||||
})).slice(0, 5);
|
||||
});
|
||||
const selectFirstRunCompleted = reselect.createSelector(selectState, state => state.firstRunCompleted);
|
||||
const selectShowSuggestedSubs = reselect.createSelector(selectState, state => state.showSuggestedSubs); // Fetching any claims that are a part of a users subscriptions
|
||||
|
||||
const selectSubscriptionsBeingFetched = reselect.createSelector(selectSubscriptions, lbryRedux.selectAllFetchingChannelClaims, (subscriptions, fetchingChannelClaims) => {
|
||||
const fetchingSubscriptionMap = {};
|
||||
subscriptions.forEach(sub => {
|
||||
const isFetching = fetchingChannelClaims && fetchingChannelClaims[sub.uri];
|
||||
|
||||
if (isFetching) {
|
||||
fetchingSubscriptionMap[sub.uri] = true;
|
||||
}
|
||||
});
|
||||
return fetchingSubscriptionMap;
|
||||
});
|
||||
const selectUnreadByChannel = reselect.createSelector(selectState, state => state.unread); // Returns the current total of unread subscriptions
|
||||
|
||||
const selectUnreadAmount = reselect.createSelector(selectUnreadByChannel, unreadByChannel => {
|
||||
const unreadChannels = Object.keys(unreadByChannel);
|
||||
let badges = 0;
|
||||
|
||||
if (!unreadChannels.length) {
|
||||
return badges;
|
||||
}
|
||||
|
||||
unreadChannels.forEach(channel => {
|
||||
badges += unreadByChannel[channel].uris.length;
|
||||
});
|
||||
return badges;
|
||||
}); // Returns the uris with channels as an array with the channel with the newest content first
|
||||
// If you just want the `unread` state, use selectUnread
|
||||
|
||||
const selectUnreadSubscriptions = reselect.createSelector(selectUnreadAmount, selectUnreadByChannel, lbryRedux.selectClaimsByUri, (unreadAmount, unreadByChannel, claimsByUri) => {
|
||||
// determine which channel has the newest content
|
||||
const unreadList = [];
|
||||
|
||||
if (!unreadAmount) {
|
||||
return unreadList;
|
||||
}
|
||||
|
||||
const channelUriList = Object.keys(unreadByChannel); // There is only one channel with unread notifications
|
||||
|
||||
if (unreadAmount === 1) {
|
||||
channelUriList.forEach(channel => {
|
||||
const unreadChannel = {
|
||||
channel,
|
||||
uris: unreadByChannel[channel].uris
|
||||
};
|
||||
unreadList.push(unreadChannel);
|
||||
});
|
||||
return unreadList;
|
||||
}
|
||||
|
||||
channelUriList.sort((channel1, channel2) => {
|
||||
const latestUriFromChannel1 = unreadByChannel[channel1].uris[0];
|
||||
const latestClaimFromChannel1 = claimsByUri[latestUriFromChannel1] || {};
|
||||
const latestUriFromChannel2 = unreadByChannel[channel2].uris[0];
|
||||
const latestClaimFromChannel2 = claimsByUri[latestUriFromChannel2] || {};
|
||||
const latestHeightFromChannel1 = latestClaimFromChannel1.height || 0;
|
||||
const latestHeightFromChannel2 = latestClaimFromChannel2.height || 0;
|
||||
|
||||
if (latestHeightFromChannel1 !== latestHeightFromChannel2) {
|
||||
return latestHeightFromChannel2 - latestHeightFromChannel1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}).forEach(channel => {
|
||||
const unreadSubscription = unreadByChannel[channel];
|
||||
const unreadChannel = {
|
||||
channel,
|
||||
uris: unreadSubscription.uris
|
||||
};
|
||||
unreadList.push(unreadChannel);
|
||||
});
|
||||
return unreadList;
|
||||
}); // Returns all unread subscriptions for a uri passed in
|
||||
|
||||
const makeSelectUnreadByChannel = uri => reselect.createSelector(selectUnreadByChannel, unread => unread[uri]); // Returns the first page of claims for every channel a user is subscribed to
|
||||
|
||||
const selectSubscriptionClaims = reselect.createSelector(lbryRedux.selectAllClaimsByChannel, lbryRedux.selectClaimsById, selectSubscriptions, selectUnreadByChannel, (channelIds, allClaims, savedSubscriptions, unreadByChannel) => {
|
||||
// no claims loaded yet
|
||||
if (!Object.keys(channelIds).length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let fetchedSubscriptions = [];
|
||||
savedSubscriptions.forEach(subscription => {
|
||||
let channelClaims = []; // if subscribed channel has content
|
||||
|
||||
if (channelIds[subscription.uri] && channelIds[subscription.uri]['1']) {
|
||||
// This will need to be more robust, we will want to be able to load more than the first page
|
||||
// Strip out any ids that will be shown as notifications
|
||||
const pageOneChannelIds = channelIds[subscription.uri]['1']; // we have the channel ids and the corresponding claims
|
||||
// loop over the list of ids and grab the claim
|
||||
|
||||
pageOneChannelIds.forEach(id => {
|
||||
const grabbedClaim = allClaims[id];
|
||||
|
||||
if (unreadByChannel[subscription.uri] && unreadByChannel[subscription.uri].uris.some(uri => uri.includes(id))) {
|
||||
grabbedClaim.isNew = true;
|
||||
}
|
||||
|
||||
channelClaims = channelClaims.concat([grabbedClaim]);
|
||||
});
|
||||
}
|
||||
|
||||
fetchedSubscriptions = fetchedSubscriptions.concat(channelClaims);
|
||||
});
|
||||
return fetchedSubscriptions;
|
||||
}); // Returns true if a user is subscribed to the channel associated with the uri passed in
|
||||
// Accepts content or channel uris
|
||||
|
||||
const makeSelectIsSubscribed = uri => reselect.createSelector(selectSubscriptions, lbryRedux.makeSelectChannelForClaimUri(uri, true), (subscriptions, channelUri) => {
|
||||
if (channelUri) {
|
||||
return subscriptions.some(sub => sub.uri === channelUri);
|
||||
} // If we couldn't get a channel uri from the claim uri, the uri passed in might be a channel already
|
||||
|
||||
|
||||
const {
|
||||
isChannel
|
||||
} = lbryRedux.parseURI(uri);
|
||||
|
||||
if (isChannel) {
|
||||
const uriWithPrefix = uri.startsWith('lbry://') ? uri : `lbry://${uri}`;
|
||||
return subscriptions.some(sub => sub.uri === uriWithPrefix);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
const makeSelectIsNew = uri => reselect.createSelector(makeSelectIsSubscribed(uri), lbryRedux.makeSelectChannelForClaimUri(uri), selectUnreadByChannel, (isSubscribed, channel, unreadByChannel) => {
|
||||
if (!isSubscribed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unreadForChannel = unreadByChannel[`lbry://${channel}`];
|
||||
|
||||
if (unreadForChannel) {
|
||||
return unreadForChannel.uris.includes(uri);
|
||||
}
|
||||
|
||||
return false; // If they are subscribed, check to see if this uri is in the list of unreads
|
||||
});
|
||||
const selectEnabledChannelNotifications = reselect.createSelector(selectState, state => state.enabledChannelNotifications);
|
||||
|
||||
const persistShape = {
|
||||
version: '0',
|
||||
shared: {}
|
||||
};
|
||||
function userStateSyncMiddleware() {
|
||||
return ({
|
||||
getState
|
||||
}) => next => action => {
|
||||
if (action.type === CHANNEL_SUBSCRIBE || action.type === CHANNEL_UNSUBSCRIBE || action.type === lbryRedux.ACTIONS.TOGGLE_TAG_FOLLOW) {
|
||||
const newShape = { ...persistShape
|
||||
};
|
||||
const state = getState();
|
||||
const subscriptions = selectSubscriptions(state).map(({
|
||||
uri
|
||||
}) => uri);
|
||||
const tags = lbryRedux.selectFollowedTags(state);
|
||||
newShape.shared.subscriptions = subscriptions;
|
||||
newShape.shared.tags = tags;
|
||||
const {
|
||||
uri
|
||||
} = action.data;
|
||||
|
||||
if (action.type === CHANNEL_SUBSCRIBE) {
|
||||
const newSubscriptions = subscriptions.slice();
|
||||
newSubscriptions.push(uri);
|
||||
newShape.shared.subscriptions = newSubscriptions;
|
||||
} else if (action.type === CHANNEL_UNSUBSCRIBE) {
|
||||
let newSubscriptions = subscriptions.slice();
|
||||
newSubscriptions = newSubscriptions.filter(subscribedUri => subscribedUri !== uri);
|
||||
newShape.shared.subscriptions = newSubscriptions;
|
||||
} else {
|
||||
const toggledTag = action.data.name;
|
||||
const followedTags = lbryRedux.selectFollowedTags(state).map(({
|
||||
name
|
||||
}) => name);
|
||||
const isFollowing = lbryRedux.makeSelectIsFollowingTag(toggledTag)(state);
|
||||
let newTags = followedTags.slice();
|
||||
|
||||
if (isFollowing) {
|
||||
newTags = newTags.filter(followedTag => followedTag.name !== toggledTag);
|
||||
} else {
|
||||
newTags.push(toggledTag);
|
||||
}
|
||||
|
||||
newShape.shared.tags = newTags;
|
||||
}
|
||||
|
||||
Lbryio.call('user_settings', 'set', {
|
||||
settings: newShape
|
||||
});
|
||||
}
|
||||
|
||||
return next(action);
|
||||
};
|
||||
}
|
||||
|
||||
function doGenerateAuthToken(installationId) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
|
@ -668,25 +932,25 @@ function doGenerateAuthToken(installationId) {
|
|||
};
|
||||
}
|
||||
|
||||
const selectState = state => state.rewards || {};
|
||||
const selectState$1 = state => state.rewards || {};
|
||||
|
||||
const selectUnclaimedRewardsByType = reselect.createSelector(selectState, state => state.unclaimedRewardsByType);
|
||||
const selectClaimedRewardsById = reselect.createSelector(selectState, state => state.claimedRewardsById);
|
||||
const selectUnclaimedRewardsByType = reselect.createSelector(selectState$1, state => state.unclaimedRewardsByType);
|
||||
const selectClaimedRewardsById = reselect.createSelector(selectState$1, state => state.claimedRewardsById);
|
||||
const selectClaimedRewards = reselect.createSelector(selectClaimedRewardsById, byId => Object.values(byId) || []);
|
||||
const selectClaimedRewardsByTransactionId = reselect.createSelector(selectClaimedRewards, rewards => rewards.reduce((mapParam, reward) => {
|
||||
const map = mapParam;
|
||||
map[reward.transaction_id] = reward;
|
||||
return map;
|
||||
}, {}));
|
||||
const selectUnclaimedRewards = reselect.createSelector(selectState, state => state.unclaimedRewards);
|
||||
const selectFetchingRewards = reselect.createSelector(selectState, state => !!state.fetching);
|
||||
const selectUnclaimedRewards = reselect.createSelector(selectState$1, state => state.unclaimedRewards);
|
||||
const selectFetchingRewards = reselect.createSelector(selectState$1, state => !!state.fetching);
|
||||
const selectUnclaimedRewardValue = reselect.createSelector(selectUnclaimedRewards, rewards => rewards.reduce((sum, reward) => sum + reward.reward_amount, 0));
|
||||
const selectClaimsPendingByType = reselect.createSelector(selectState, state => state.claimPendingByType);
|
||||
const selectClaimsPendingByType = reselect.createSelector(selectState$1, state => state.claimPendingByType);
|
||||
|
||||
const selectIsClaimRewardPending = (state, props) => selectClaimsPendingByType(state, props)[props.reward_type];
|
||||
|
||||
const makeSelectIsRewardClaimPending = () => reselect.createSelector(selectIsClaimRewardPending, isClaiming => isClaiming);
|
||||
const selectClaimErrorsByType = reselect.createSelector(selectState, state => state.claimErrorsByType);
|
||||
const selectClaimErrorsByType = reselect.createSelector(selectState$1, state => state.claimErrorsByType);
|
||||
|
||||
const selectClaimRewardError = (state, props) => selectClaimErrorsByType(state, props)[props.reward_type];
|
||||
|
||||
|
@ -696,39 +960,39 @@ const selectRewardByType = (state, rewardType) => selectUnclaimedRewards(state).
|
|||
|
||||
const makeSelectRewardByType = () => reselect.createSelector(selectRewardByType, reward => reward);
|
||||
const makeSelectRewardAmountByType = () => reselect.createSelector(selectRewardByType, reward => reward ? reward.reward_amount : 0);
|
||||
const selectRewardContentClaimIds = reselect.createSelector(selectState, state => state.rewardedContentClaimIds);
|
||||
const selectRewardContentClaimIds = reselect.createSelector(selectState$1, state => state.rewardedContentClaimIds);
|
||||
const selectReferralReward = reselect.createSelector(selectUnclaimedRewards, unclaimedRewards => unclaimedRewards.filter(reward => reward.reward_type === rewards.TYPE_REFERRAL)[0]);
|
||||
|
||||
const selectState$1 = state => state.user || {};
|
||||
const selectAuthenticationIsPending = reselect.createSelector(selectState$1, state => state.authenticationIsPending);
|
||||
const selectUserIsPending = reselect.createSelector(selectState$1, state => state.userIsPending);
|
||||
const selectUser = reselect.createSelector(selectState$1, state => state.user);
|
||||
const selectState$2 = state => state.user || {};
|
||||
const selectAuthenticationIsPending = reselect.createSelector(selectState$2, state => state.authenticationIsPending);
|
||||
const selectUserIsPending = reselect.createSelector(selectState$2, state => state.userIsPending);
|
||||
const selectUser = reselect.createSelector(selectState$2, state => state.user);
|
||||
const selectUserEmail = reselect.createSelector(selectUser, user => user ? user.primary_email : null);
|
||||
const selectUserPhone = reselect.createSelector(selectUser, user => user ? user.phone_number : null);
|
||||
const selectUserCountryCode = reselect.createSelector(selectUser, user => user ? user.country_code : null);
|
||||
const selectEmailToVerify = reselect.createSelector(selectState$1, selectUserEmail, (state, userEmail) => state.emailToVerify || userEmail);
|
||||
const selectPhoneToVerify = reselect.createSelector(selectState$1, selectUserPhone, (state, userPhone) => state.phoneToVerify || userPhone);
|
||||
const selectEmailToVerify = reselect.createSelector(selectState$2, selectUserEmail, (state, userEmail) => state.emailToVerify || userEmail);
|
||||
const selectPhoneToVerify = reselect.createSelector(selectState$2, selectUserPhone, (state, userPhone) => state.phoneToVerify || userPhone);
|
||||
const selectUserIsRewardApproved = reselect.createSelector(selectUser, user => user && user.is_reward_approved);
|
||||
const selectEmailNewIsPending = reselect.createSelector(selectState$1, state => state.emailNewIsPending);
|
||||
const selectEmailNewErrorMessage = reselect.createSelector(selectState$1, state => state.emailNewErrorMessage);
|
||||
const selectPhoneNewErrorMessage = reselect.createSelector(selectState$1, state => state.phoneNewErrorMessage);
|
||||
const selectEmailVerifyIsPending = reselect.createSelector(selectState$1, state => state.emailVerifyIsPending);
|
||||
const selectEmailVerifyErrorMessage = reselect.createSelector(selectState$1, state => state.emailVerifyErrorMessage);
|
||||
const selectPhoneNewIsPending = reselect.createSelector(selectState$1, state => state.phoneNewIsPending);
|
||||
const selectPhoneVerifyIsPending = reselect.createSelector(selectState$1, state => state.phoneVerifyIsPending);
|
||||
const selectPhoneVerifyErrorMessage = reselect.createSelector(selectState$1, state => state.phoneVerifyErrorMessage);
|
||||
const selectIdentityVerifyIsPending = reselect.createSelector(selectState$1, state => state.identityVerifyIsPending);
|
||||
const selectIdentityVerifyErrorMessage = reselect.createSelector(selectState$1, state => state.identityVerifyErrorMessage);
|
||||
const selectEmailNewIsPending = reselect.createSelector(selectState$2, state => state.emailNewIsPending);
|
||||
const selectEmailNewErrorMessage = reselect.createSelector(selectState$2, state => state.emailNewErrorMessage);
|
||||
const selectPhoneNewErrorMessage = reselect.createSelector(selectState$2, state => state.phoneNewErrorMessage);
|
||||
const selectEmailVerifyIsPending = reselect.createSelector(selectState$2, state => state.emailVerifyIsPending);
|
||||
const selectEmailVerifyErrorMessage = reselect.createSelector(selectState$2, state => state.emailVerifyErrorMessage);
|
||||
const selectPhoneNewIsPending = reselect.createSelector(selectState$2, state => state.phoneNewIsPending);
|
||||
const selectPhoneVerifyIsPending = reselect.createSelector(selectState$2, state => state.phoneVerifyIsPending);
|
||||
const selectPhoneVerifyErrorMessage = reselect.createSelector(selectState$2, state => state.phoneVerifyErrorMessage);
|
||||
const selectIdentityVerifyIsPending = reselect.createSelector(selectState$2, state => state.identityVerifyIsPending);
|
||||
const selectIdentityVerifyErrorMessage = reselect.createSelector(selectState$2, state => state.identityVerifyErrorMessage);
|
||||
const selectUserVerifiedEmail = reselect.createSelector(selectUser, user => user && user.has_verified_email);
|
||||
const selectUserIsVerificationCandidate = reselect.createSelector(selectUser, user => user && (!user.has_verified_email || !user.is_identity_verified));
|
||||
const selectAccessToken = reselect.createSelector(selectState$1, state => state.accessToken);
|
||||
const selectUserInviteStatusIsPending = reselect.createSelector(selectState$1, state => state.inviteStatusIsPending);
|
||||
const selectUserInvitesRemaining = reselect.createSelector(selectState$1, state => state.invitesRemaining);
|
||||
const selectUserInvitees = reselect.createSelector(selectState$1, state => state.invitees);
|
||||
const selectAccessToken = reselect.createSelector(selectState$2, state => state.accessToken);
|
||||
const selectUserInviteStatusIsPending = reselect.createSelector(selectState$2, state => state.inviteStatusIsPending);
|
||||
const selectUserInvitesRemaining = reselect.createSelector(selectState$2, state => state.invitesRemaining);
|
||||
const selectUserInvitees = reselect.createSelector(selectState$2, state => state.invitees);
|
||||
const selectUserInviteStatusFailed = reselect.createSelector(selectUserInvitesRemaining, () => selectUserInvitesRemaining === null);
|
||||
const selectUserInviteNewIsPending = reselect.createSelector(selectState$1, state => state.inviteNewIsPending);
|
||||
const selectUserInviteNewErrorMessage = reselect.createSelector(selectState$1, state => state.inviteNewErrorMessage);
|
||||
const selectUserInviteReferralLink = reselect.createSelector(selectState$1, state => state.referralLink);
|
||||
const selectUserInviteNewIsPending = reselect.createSelector(selectState$2, state => state.inviteNewIsPending);
|
||||
const selectUserInviteNewErrorMessage = reselect.createSelector(selectState$2, state => state.inviteNewErrorMessage);
|
||||
const selectUserInviteReferralLink = reselect.createSelector(selectState$2, state => state.referralLink);
|
||||
|
||||
function doFetchInviteStatus() {
|
||||
return dispatch => {
|
||||
|
@ -1263,217 +1527,6 @@ function doFetchRewardedContent() {
|
|||
|
||||
const PAGE_SIZE = 20;
|
||||
|
||||
function swapKeyAndValue(dict) {
|
||||
const ret = {}; // eslint-disable-next-line no-restricted-syntax
|
||||
|
||||
for (const key in dict) {
|
||||
if (dict.hasOwnProperty(key)) {
|
||||
ret[dict[key]] = key;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const selectState$2 = state => state.subscriptions || {}; // Returns the list of channel uris a user is subscribed to
|
||||
|
||||
|
||||
const selectSubscriptions = reselect.createSelector(selectState$2, state => state.subscriptions); // Fetching list of users subscriptions
|
||||
|
||||
const selectIsFetchingSubscriptions = reselect.createSelector(selectState$2, state => state.loading); // The current view mode on the subscriptions page
|
||||
|
||||
const selectViewMode = reselect.createSelector(selectState$2, state => state.viewMode); // Suggested subscriptions from internal apis
|
||||
|
||||
const selectSuggested = reselect.createSelector(selectState$2, state => state.suggested);
|
||||
const selectIsFetchingSuggested = reselect.createSelector(selectState$2, state => state.loadingSuggested);
|
||||
const selectSuggestedChannels = reselect.createSelector(selectSubscriptions, selectSuggested, (userSubscriptions, suggested) => {
|
||||
if (!suggested) {
|
||||
return null;
|
||||
} // Swap the key/value because we will use the uri for everything, this just makes it easier
|
||||
// suggested is returned from the api with the form:
|
||||
// {
|
||||
// featured: { "Channel label": uri, ... },
|
||||
// top_subscribed: { "@channel": uri, ... }
|
||||
// top_bid: { "@channel": uri, ... }
|
||||
// }
|
||||
// To properly compare the suggested subscriptions from our current subscribed channels
|
||||
// We only care about the uri, not the label
|
||||
// We also only care about top_subscribed and featured
|
||||
// top_bid could just be porn or a channel with no content
|
||||
|
||||
|
||||
const topSubscribedSuggestions = swapKeyAndValue(suggested[SUGGESTED_TOP_SUBSCRIBED]);
|
||||
const featuredSuggestions = swapKeyAndValue(suggested[SUGGESTED_FEATURED]); // Make sure there are no duplicates
|
||||
// If a uri isn't already in the suggested object, add it
|
||||
|
||||
const suggestedChannels = { ...topSubscribedSuggestions
|
||||
};
|
||||
Object.keys(featuredSuggestions).forEach(uri => {
|
||||
if (!suggestedChannels[uri]) {
|
||||
const channelLabel = featuredSuggestions[uri];
|
||||
suggestedChannels[uri] = channelLabel;
|
||||
}
|
||||
});
|
||||
userSubscriptions.forEach(({
|
||||
uri
|
||||
}) => {
|
||||
// Note to passer bys:
|
||||
// Maybe we should just remove the `lbry://` prefix from subscription uris
|
||||
// Most places don't store them like that
|
||||
const subscribedUri = uri.slice('lbry://'.length);
|
||||
|
||||
if (suggestedChannels[subscribedUri]) {
|
||||
delete suggestedChannels[subscribedUri];
|
||||
}
|
||||
});
|
||||
return Object.keys(suggestedChannels).map(uri => ({
|
||||
uri,
|
||||
label: suggestedChannels[uri]
|
||||
})).slice(0, 5);
|
||||
});
|
||||
const selectFirstRunCompleted = reselect.createSelector(selectState$2, state => state.firstRunCompleted);
|
||||
const selectShowSuggestedSubs = reselect.createSelector(selectState$2, state => state.showSuggestedSubs); // Fetching any claims that are a part of a users subscriptions
|
||||
|
||||
const selectSubscriptionsBeingFetched = reselect.createSelector(selectSubscriptions, lbryRedux.selectAllFetchingChannelClaims, (subscriptions, fetchingChannelClaims) => {
|
||||
const fetchingSubscriptionMap = {};
|
||||
subscriptions.forEach(sub => {
|
||||
const isFetching = fetchingChannelClaims && fetchingChannelClaims[sub.uri];
|
||||
|
||||
if (isFetching) {
|
||||
fetchingSubscriptionMap[sub.uri] = true;
|
||||
}
|
||||
});
|
||||
return fetchingSubscriptionMap;
|
||||
});
|
||||
const selectUnreadByChannel = reselect.createSelector(selectState$2, state => state.unread); // Returns the current total of unread subscriptions
|
||||
|
||||
const selectUnreadAmount = reselect.createSelector(selectUnreadByChannel, unreadByChannel => {
|
||||
const unreadChannels = Object.keys(unreadByChannel);
|
||||
let badges = 0;
|
||||
|
||||
if (!unreadChannels.length) {
|
||||
return badges;
|
||||
}
|
||||
|
||||
unreadChannels.forEach(channel => {
|
||||
badges += unreadByChannel[channel].uris.length;
|
||||
});
|
||||
return badges;
|
||||
}); // Returns the uris with channels as an array with the channel with the newest content first
|
||||
// If you just want the `unread` state, use selectUnread
|
||||
|
||||
const selectUnreadSubscriptions = reselect.createSelector(selectUnreadAmount, selectUnreadByChannel, lbryRedux.selectClaimsByUri, (unreadAmount, unreadByChannel, claimsByUri) => {
|
||||
// determine which channel has the newest content
|
||||
const unreadList = [];
|
||||
|
||||
if (!unreadAmount) {
|
||||
return unreadList;
|
||||
}
|
||||
|
||||
const channelUriList = Object.keys(unreadByChannel); // There is only one channel with unread notifications
|
||||
|
||||
if (unreadAmount === 1) {
|
||||
channelUriList.forEach(channel => {
|
||||
const unreadChannel = {
|
||||
channel,
|
||||
uris: unreadByChannel[channel].uris
|
||||
};
|
||||
unreadList.push(unreadChannel);
|
||||
});
|
||||
return unreadList;
|
||||
}
|
||||
|
||||
channelUriList.sort((channel1, channel2) => {
|
||||
const latestUriFromChannel1 = unreadByChannel[channel1].uris[0];
|
||||
const latestClaimFromChannel1 = claimsByUri[latestUriFromChannel1] || {};
|
||||
const latestUriFromChannel2 = unreadByChannel[channel2].uris[0];
|
||||
const latestClaimFromChannel2 = claimsByUri[latestUriFromChannel2] || {};
|
||||
const latestHeightFromChannel1 = latestClaimFromChannel1.height || 0;
|
||||
const latestHeightFromChannel2 = latestClaimFromChannel2.height || 0;
|
||||
|
||||
if (latestHeightFromChannel1 !== latestHeightFromChannel2) {
|
||||
return latestHeightFromChannel2 - latestHeightFromChannel1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}).forEach(channel => {
|
||||
const unreadSubscription = unreadByChannel[channel];
|
||||
const unreadChannel = {
|
||||
channel,
|
||||
uris: unreadSubscription.uris
|
||||
};
|
||||
unreadList.push(unreadChannel);
|
||||
});
|
||||
return unreadList;
|
||||
}); // Returns all unread subscriptions for a uri passed in
|
||||
|
||||
const makeSelectUnreadByChannel = uri => reselect.createSelector(selectUnreadByChannel, unread => unread[uri]); // Returns the first page of claims for every channel a user is subscribed to
|
||||
|
||||
const selectSubscriptionClaims = reselect.createSelector(lbryRedux.selectAllClaimsByChannel, lbryRedux.selectClaimsById, selectSubscriptions, selectUnreadByChannel, (channelIds, allClaims, savedSubscriptions, unreadByChannel) => {
|
||||
// no claims loaded yet
|
||||
if (!Object.keys(channelIds).length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let fetchedSubscriptions = [];
|
||||
savedSubscriptions.forEach(subscription => {
|
||||
let channelClaims = []; // if subscribed channel has content
|
||||
|
||||
if (channelIds[subscription.uri] && channelIds[subscription.uri]['1']) {
|
||||
// This will need to be more robust, we will want to be able to load more than the first page
|
||||
// Strip out any ids that will be shown as notifications
|
||||
const pageOneChannelIds = channelIds[subscription.uri]['1']; // we have the channel ids and the corresponding claims
|
||||
// loop over the list of ids and grab the claim
|
||||
|
||||
pageOneChannelIds.forEach(id => {
|
||||
const grabbedClaim = allClaims[id];
|
||||
|
||||
if (unreadByChannel[subscription.uri] && unreadByChannel[subscription.uri].uris.some(uri => uri.includes(id))) {
|
||||
grabbedClaim.isNew = true;
|
||||
}
|
||||
|
||||
channelClaims = channelClaims.concat([grabbedClaim]);
|
||||
});
|
||||
}
|
||||
|
||||
fetchedSubscriptions = fetchedSubscriptions.concat(channelClaims);
|
||||
});
|
||||
return fetchedSubscriptions;
|
||||
}); // Returns true if a user is subscribed to the channel associated with the uri passed in
|
||||
// Accepts content or channel uris
|
||||
|
||||
const makeSelectIsSubscribed = uri => reselect.createSelector(selectSubscriptions, lbryRedux.makeSelectChannelForClaimUri(uri, true), (subscriptions, channelUri) => {
|
||||
if (channelUri) {
|
||||
return subscriptions.some(sub => sub.uri === channelUri);
|
||||
} // If we couldn't get a channel uri from the claim uri, the uri passed in might be a channel already
|
||||
|
||||
|
||||
const {
|
||||
isChannel
|
||||
} = lbryRedux.parseURI(uri);
|
||||
|
||||
if (isChannel) {
|
||||
const uriWithPrefix = uri.startsWith('lbry://') ? uri : `lbry://${uri}`;
|
||||
return subscriptions.some(sub => sub.uri === uriWithPrefix);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
const makeSelectIsNew = uri => reselect.createSelector(makeSelectIsSubscribed(uri), lbryRedux.makeSelectChannelForClaimUri(uri), selectUnreadByChannel, (isSubscribed, channel, unreadByChannel) => {
|
||||
if (!isSubscribed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unreadForChannel = unreadByChannel[`lbry://${channel}`];
|
||||
|
||||
if (unreadForChannel) {
|
||||
return unreadForChannel.uris.includes(uri);
|
||||
}
|
||||
|
||||
return false; // If they are subscribed, check to see if this uri is in the list of unreads
|
||||
});
|
||||
const selectEnabledChannelNotifications = reselect.createSelector(selectState$2, state => state.enabledChannelNotifications);
|
||||
|
||||
//
|
||||
const CHECK_SUBSCRIPTIONS_INTERVAL = 15 * 60 * 1000;
|
||||
const doSetViewMode = viewMode => dispatch => dispatch({
|
||||
|
@ -2998,3 +3051,4 @@ exports.statsReducer = statsReducer;
|
|||
exports.subscriptionsReducer = subscriptions;
|
||||
exports.syncReducer = syncReducer;
|
||||
exports.userReducer = userReducer;
|
||||
exports.userStateSyncMiddleware = userStateSyncMiddleware;
|
||||
|
|
1655
dist/bundle.js
vendored
1655
dist/bundle.js
vendored
File diff suppressed because it is too large
Load diff
|
@ -3,4 +3,3 @@
|
|||
// eslint-disable-next-line no-use-before-define
|
||||
export type Dispatch<T> = (action: T | Promise<T> | Array<T> | ThunkAction<T>) => any; // Need to refer to ThunkAction
|
||||
export type GetState = () => any;
|
||||
export type ThunkAction<T> = (dispatch: Dispatch<T>, getState: GetState) => any;
|
|
@ -1,5 +1,5 @@
|
|||
// @flow
|
||||
import type { Dispatch as ReduxDispatch } from 'types/redux';
|
||||
import type { Dispatch } from 'flow-typed/Redux';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import {
|
||||
DOWNLOADED,
|
||||
|
@ -12,7 +12,7 @@ import {
|
|||
SUGGESTED_FEATURED,
|
||||
} from 'constants/subscriptions';
|
||||
|
||||
export type Subscription = {
|
||||
declare type Subscription = {
|
||||
channelName: string, // @CryptoCandor,
|
||||
uri: string, // lbry://@CryptoCandor#9152f3b054f692076a6882d1b58a30e8781cc8e6
|
||||
latest?: string, // substratum#b0ab143243020e7831fd070d9f871e1fda948620
|
||||
|
@ -21,26 +21,26 @@ export type Subscription = {
|
|||
// Tracking for new content
|
||||
// i.e. If a subscription has a DOWNLOADING type, we will trigger an OS notification
|
||||
// to tell users there is new content from their subscriptions
|
||||
export type SubscriptionNotificationType = DOWNLOADED | DOWNLOADING | NOTIFY_ONLY;
|
||||
declare type SubscriptionNotificationType = DOWNLOADED | DOWNLOADING | NOTIFY_ONLY;
|
||||
|
||||
export type UnreadSubscription = {
|
||||
declare type UnreadSubscription = {
|
||||
type: SubscriptionNotificationType,
|
||||
uris: Array<string>,
|
||||
};
|
||||
|
||||
export type UnreadSubscriptions = {
|
||||
declare type UnreadSubscriptions = {
|
||||
[string]: UnreadSubscription,
|
||||
};
|
||||
|
||||
export type ViewMode = VIEW_LATEST_FIRST | VIEW_ALL;
|
||||
declare type ViewMode = VIEW_LATEST_FIRST | VIEW_ALL;
|
||||
|
||||
export type SuggestedType = SUGGESTED_TOP_BID | SUGGESTED_TOP_SUBSCRIBED | SUGGESTED_FEATURED;
|
||||
declare type SuggestedType = SUGGESTED_TOP_BID | SUGGESTED_TOP_SUBSCRIBED | SUGGESTED_FEATURED;
|
||||
|
||||
export type SuggestedSubscriptions = {
|
||||
declare type SuggestedSubscriptions = {
|
||||
[SuggestedType]: string,
|
||||
};
|
||||
|
||||
export type SubscriptionState = {
|
||||
declare type SubscriptionState = {
|
||||
enabledChannelNotifications: Array<string>,
|
||||
subscriptions: Array<Subscription>,
|
||||
unread: UnreadSubscriptions,
|
||||
|
@ -55,27 +55,27 @@ export type SubscriptionState = {
|
|||
//
|
||||
// Action types
|
||||
//
|
||||
export type DoChannelSubscriptionEnableNotifications = {
|
||||
declare type DoChannelSubscriptionEnableNotifications = {
|
||||
type: ACTIONS.CHANNEL_SUBSCRIPTION_ENABLE_NOTIFICATIONS,
|
||||
data: string,
|
||||
};
|
||||
|
||||
export type DoChannelSubscriptionDisableNotifications = {
|
||||
declare type DoChannelSubscriptionDisableNotifications = {
|
||||
type: ACTIONS.CHANNEL_SUBSCRIPTION_DISABLE_NOTIFICATIONS,
|
||||
data: string,
|
||||
};
|
||||
|
||||
export type DoChannelSubscribe = {
|
||||
declare type DoChannelSubscribe = {
|
||||
type: ACTIONS.CHANNEL_SUBSCRIBE,
|
||||
data: Subscription,
|
||||
};
|
||||
|
||||
export type DoChannelUnsubscribe = {
|
||||
declare type DoChannelUnsubscribe = {
|
||||
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
|
||||
data: Subscription,
|
||||
};
|
||||
|
||||
export type DoUpdateSubscriptionUnreads = {
|
||||
declare type DoUpdateSubscriptionUnreads = {
|
||||
type: ACTIONS.UPDATE_SUBSCRIPTION_UNREADS,
|
||||
data: {
|
||||
channel: string,
|
||||
|
@ -84,7 +84,7 @@ export type DoUpdateSubscriptionUnreads = {
|
|||
},
|
||||
};
|
||||
|
||||
export type DoRemoveSubscriptionUnreads = {
|
||||
declare type DoRemoveSubscriptionUnreads = {
|
||||
type: ACTIONS.REMOVE_SUBSCRIPTION_UNREADS,
|
||||
data: {
|
||||
channel: string,
|
||||
|
@ -92,7 +92,7 @@ export type DoRemoveSubscriptionUnreads = {
|
|||
},
|
||||
};
|
||||
|
||||
export type SetSubscriptionLatest = {
|
||||
declare type SetSubscriptionLatest = {
|
||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||
data: {
|
||||
subscription: Subscription,
|
||||
|
@ -100,30 +100,30 @@ export type SetSubscriptionLatest = {
|
|||
},
|
||||
};
|
||||
|
||||
export type CheckSubscriptionStarted = {
|
||||
declare type CheckSubscriptionStarted = {
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
|
||||
};
|
||||
|
||||
export type CheckSubscriptionCompleted = {
|
||||
declare type CheckSubscriptionCompleted = {
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||
};
|
||||
|
||||
export type FetchedSubscriptionsSucess = {
|
||||
declare type FetchedSubscriptionsSucess = {
|
||||
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
||||
data: Array<Subscription>,
|
||||
};
|
||||
|
||||
export type SetViewMode = {
|
||||
declare type SetViewMode = {
|
||||
type: ACTIONS.SET_VIEW_MODE,
|
||||
data: ViewMode,
|
||||
};
|
||||
|
||||
export type GetSuggestedSubscriptionsSuccess = {
|
||||
declare type GetSuggestedSubscriptionsSuccess = {
|
||||
type: ACTIONS.GET_SUGGESTED_SUBSCRIPTIONS_START,
|
||||
data: SuggestedSubscriptions,
|
||||
};
|
||||
|
||||
export type Action =
|
||||
declare type SubscriptionAction =
|
||||
| DoChannelSubscribe
|
||||
| DoChannelUnsubscribe
|
||||
| DoUpdateSubscriptionUnreads
|
||||
|
@ -134,4 +134,4 @@ export type Action =
|
|||
| SetViewMode
|
||||
| Function;
|
||||
|
||||
export type Dispatch = ReduxDispatch<Action>;
|
||||
declare type SubscriptionDispatch = Dispatch<SubscriptionAction>;
|
23
dist/flow-typed/User.js
vendored
Normal file
23
dist/flow-typed/User.js
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
// @flow
|
||||
|
||||
declare type User = {
|
||||
created_at: string,
|
||||
family_name: ?string,
|
||||
given_name: ?string,
|
||||
groups: Array<string>,
|
||||
has_verified_email: boolean,
|
||||
id: number,
|
||||
invite_reward_claimed: boolean,
|
||||
invited_at: ?number,
|
||||
invited_by_id: number,
|
||||
invites_remaining: number,
|
||||
is_email_enabled: boolean,
|
||||
is_identity_verified: boolean,
|
||||
is_reward_approved: boolean,
|
||||
language: string,
|
||||
manual_approval_user_id: ?number,
|
||||
primary_email: string,
|
||||
reward_status_change_trigger: string,
|
||||
updated_at: string,
|
||||
youtube_channels: ?Array<string>,
|
||||
};
|
5
flow-typed/Redux.js
vendored
Normal file
5
flow-typed/Redux.js
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
// @flow
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
export type Dispatch<T> = (action: T | Promise<T> | Array<T> | ThunkAction<T>) => any; // Need to refer to ThunkAction
|
||||
export type GetState = () => any;
|
137
flow-typed/Subscription.js
vendored
Normal file
137
flow-typed/Subscription.js
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
// @flow
|
||||
import type { Dispatch } from 'flow-typed/Redux';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import {
|
||||
DOWNLOADED,
|
||||
DOWNLOADING,
|
||||
NOTIFY_ONLY,
|
||||
VIEW_ALL,
|
||||
VIEW_LATEST_FIRST,
|
||||
SUGGESTED_TOP_BID,
|
||||
SUGGESTED_TOP_SUBSCRIBED,
|
||||
SUGGESTED_FEATURED,
|
||||
} from 'constants/subscriptions';
|
||||
|
||||
declare type Subscription = {
|
||||
channelName: string, // @CryptoCandor,
|
||||
uri: string, // lbry://@CryptoCandor#9152f3b054f692076a6882d1b58a30e8781cc8e6
|
||||
latest?: string, // substratum#b0ab143243020e7831fd070d9f871e1fda948620
|
||||
};
|
||||
|
||||
// Tracking for new content
|
||||
// i.e. If a subscription has a DOWNLOADING type, we will trigger an OS notification
|
||||
// to tell users there is new content from their subscriptions
|
||||
declare type SubscriptionNotificationType = DOWNLOADED | DOWNLOADING | NOTIFY_ONLY;
|
||||
|
||||
declare type UnreadSubscription = {
|
||||
type: SubscriptionNotificationType,
|
||||
uris: Array<string>,
|
||||
};
|
||||
|
||||
declare type UnreadSubscriptions = {
|
||||
[string]: UnreadSubscription,
|
||||
};
|
||||
|
||||
declare type ViewMode = VIEW_LATEST_FIRST | VIEW_ALL;
|
||||
|
||||
declare type SuggestedType = SUGGESTED_TOP_BID | SUGGESTED_TOP_SUBSCRIBED | SUGGESTED_FEATURED;
|
||||
|
||||
declare type SuggestedSubscriptions = {
|
||||
[SuggestedType]: string,
|
||||
};
|
||||
|
||||
declare type SubscriptionState = {
|
||||
enabledChannelNotifications: Array<string>,
|
||||
subscriptions: Array<Subscription>,
|
||||
unread: UnreadSubscriptions,
|
||||
loading: boolean,
|
||||
viewMode: ViewMode,
|
||||
suggested: SuggestedSubscriptions,
|
||||
loadingSuggested: boolean,
|
||||
firstRunCompleted: boolean,
|
||||
showSuggestedSubs: boolean,
|
||||
};
|
||||
|
||||
//
|
||||
// Action types
|
||||
//
|
||||
declare type DoChannelSubscriptionEnableNotifications = {
|
||||
type: ACTIONS.CHANNEL_SUBSCRIPTION_ENABLE_NOTIFICATIONS,
|
||||
data: string,
|
||||
};
|
||||
|
||||
declare type DoChannelSubscriptionDisableNotifications = {
|
||||
type: ACTIONS.CHANNEL_SUBSCRIPTION_DISABLE_NOTIFICATIONS,
|
||||
data: string,
|
||||
};
|
||||
|
||||
declare type DoChannelSubscribe = {
|
||||
type: ACTIONS.CHANNEL_SUBSCRIBE,
|
||||
data: Subscription,
|
||||
};
|
||||
|
||||
declare type DoChannelUnsubscribe = {
|
||||
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
|
||||
data: Subscription,
|
||||
};
|
||||
|
||||
declare type DoUpdateSubscriptionUnreads = {
|
||||
type: ACTIONS.UPDATE_SUBSCRIPTION_UNREADS,
|
||||
data: {
|
||||
channel: string,
|
||||
uris: Array<string>,
|
||||
type?: SubscriptionNotificationType,
|
||||
},
|
||||
};
|
||||
|
||||
declare type DoRemoveSubscriptionUnreads = {
|
||||
type: ACTIONS.REMOVE_SUBSCRIPTION_UNREADS,
|
||||
data: {
|
||||
channel: string,
|
||||
uris: Array<string>,
|
||||
},
|
||||
};
|
||||
|
||||
declare type SetSubscriptionLatest = {
|
||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||
data: {
|
||||
subscription: Subscription,
|
||||
uri: string,
|
||||
},
|
||||
};
|
||||
|
||||
declare type CheckSubscriptionStarted = {
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
|
||||
};
|
||||
|
||||
declare type CheckSubscriptionCompleted = {
|
||||
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||
};
|
||||
|
||||
declare type FetchedSubscriptionsSucess = {
|
||||
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
|
||||
data: Array<Subscription>,
|
||||
};
|
||||
|
||||
declare type SetViewMode = {
|
||||
type: ACTIONS.SET_VIEW_MODE,
|
||||
data: ViewMode,
|
||||
};
|
||||
|
||||
declare type GetSuggestedSubscriptionsSuccess = {
|
||||
type: ACTIONS.GET_SUGGESTED_SUBSCRIPTIONS_START,
|
||||
data: SuggestedSubscriptions,
|
||||
};
|
||||
|
||||
declare type SubscriptionAction =
|
||||
| DoChannelSubscribe
|
||||
| DoChannelUnsubscribe
|
||||
| DoUpdateSubscriptionUnreads
|
||||
| DoRemoveSubscriptionUnreads
|
||||
| SetSubscriptionLatest
|
||||
| CheckSubscriptionStarted
|
||||
| CheckSubscriptionCompleted
|
||||
| SetViewMode
|
||||
| Function;
|
||||
|
||||
declare type SubscriptionDispatch = Dispatch<SubscriptionAction>;
|
23
flow-typed/User.js
vendored
Normal file
23
flow-typed/User.js
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
// @flow
|
||||
|
||||
declare type User = {
|
||||
created_at: string,
|
||||
family_name: ?string,
|
||||
given_name: ?string,
|
||||
groups: Array<string>,
|
||||
has_verified_email: boolean,
|
||||
id: number,
|
||||
invite_reward_claimed: boolean,
|
||||
invited_at: ?number,
|
||||
invited_by_id: number,
|
||||
invites_remaining: number,
|
||||
is_email_enabled: boolean,
|
||||
is_identity_verified: boolean,
|
||||
is_reward_approved: boolean,
|
||||
language: string,
|
||||
manual_approval_user_id: ?number,
|
||||
primary_email: string,
|
||||
reward_status_change_trigger: string,
|
||||
updated_at: string,
|
||||
youtube_channels: ?Array<string>,
|
||||
};
|
|
@ -57,7 +57,9 @@
|
|||
"lint-staged": "^7.0.4",
|
||||
"prettier": "^1.4.2",
|
||||
"rollup": "^1.8.0",
|
||||
"rollup-plugin-alias": "^2.0.0",
|
||||
"rollup-plugin-babel": "^4.3.2",
|
||||
"rollup-plugin-copy": "^3.1.0",
|
||||
"rollup-plugin-flow": "^1.1.1",
|
||||
"rollup-plugin-includepaths": "^0.2.3",
|
||||
"webpack": "^4.5.0",
|
||||
|
|
|
@ -1,27 +1,38 @@
|
|||
import babel from 'rollup-plugin-babel';
|
||||
import flow from 'rollup-plugin-flow';
|
||||
import includePaths from 'rollup-plugin-includepaths';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
import alias from 'rollup-plugin-alias';
|
||||
|
||||
let includePathOptions = {
|
||||
include: {},
|
||||
paths: ['src'],
|
||||
external: [],
|
||||
extensions: ['.js']
|
||||
extensions: ['.js'],
|
||||
};
|
||||
|
||||
export default {
|
||||
input: 'src/index.js',
|
||||
output: {
|
||||
file: 'dist/bundle.es.js',
|
||||
format: 'cjs'
|
||||
format: 'cjs',
|
||||
},
|
||||
plugins: [
|
||||
alias({
|
||||
entries: [
|
||||
{
|
||||
find: 'flow-typed',
|
||||
replacement: './flow-typed',
|
||||
},
|
||||
],
|
||||
}),
|
||||
flow({ all: true }),
|
||||
includePaths(includePathOptions),
|
||||
babel({
|
||||
babelrc: false,
|
||||
presets: [],
|
||||
}),
|
||||
copy({ targets: [{ src: './flow-typed', dest: 'dist' }] }),
|
||||
],
|
||||
external: ['lbry-redux']
|
||||
}
|
||||
external: ['lbry-redux'],
|
||||
};
|
||||
|
|
|
@ -3,6 +3,9 @@ import Lbryio from 'lbryio';
|
|||
import rewards from 'rewards';
|
||||
import subscriptionsReducer from 'redux/reducers/subscriptions';
|
||||
|
||||
// middleware
|
||||
export { userStateSyncMiddleware } from 'redux/middleware/sync';
|
||||
|
||||
// constants
|
||||
export { LBRYINC_ACTIONS };
|
||||
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
// @flow
|
||||
import type { GetState } from 'types/redux';
|
||||
import type {
|
||||
Dispatch as ReduxDispatch,
|
||||
SubscriptionState,
|
||||
Subscription,
|
||||
SubscriptionNotificationType,
|
||||
ViewMode,
|
||||
UnreadSubscription,
|
||||
} from 'types/subscription';
|
||||
import type { SubscriptionDispatch } from 'flow-typed/Subscription';
|
||||
import { PAGE_SIZE } from 'constants/claim';
|
||||
import { doClaimRewardType } from 'redux/actions/rewards';
|
||||
import { selectSubscriptions, selectUnreadByChannel } from 'redux/selectors/subscriptions';
|
||||
|
@ -20,14 +12,14 @@ import rewards from 'rewards';
|
|||
const CHECK_SUBSCRIPTIONS_INTERVAL = 15 * 60 * 1000;
|
||||
const SUBSCRIPTION_DOWNLOAD_LIMIT = 1;
|
||||
|
||||
export const doSetViewMode = (viewMode: ViewMode) => (dispatch: ReduxDispatch) =>
|
||||
export const doSetViewMode = (viewMode: ViewMode) => (dispatch: SubscriptionDispatch) =>
|
||||
dispatch({
|
||||
type: ACTIONS.SET_VIEW_MODE,
|
||||
data: viewMode,
|
||||
});
|
||||
|
||||
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (
|
||||
dispatch: ReduxDispatch
|
||||
dispatch: SubscriptionDispatch
|
||||
) =>
|
||||
dispatch({
|
||||
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||
|
@ -42,7 +34,7 @@ export const doUpdateUnreadSubscriptions = (
|
|||
channelUri: string,
|
||||
uris: ?Array<string>,
|
||||
type: ?SubscriptionNotificationType
|
||||
) => (dispatch: ReduxDispatch, getState: GetState) => {
|
||||
) => (dispatch: SubscriptionDispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
const unreadByChannel = selectUnreadByChannel(state);
|
||||
const currentUnreadForChannel: UnreadSubscription = unreadByChannel[channelUri];
|
||||
|
@ -84,7 +76,7 @@ export const doUpdateUnreadSubscriptions = (
|
|||
|
||||
// Remove multiple files (or all) from a channels unread subscriptions
|
||||
export const doRemoveUnreadSubscriptions = (channelUri: ?string, readUris: ?Array<string>) => (
|
||||
dispatch: ReduxDispatch,
|
||||
dispatch: SubscriptionDispatch,
|
||||
getState: GetState
|
||||
) => {
|
||||
const state = getState();
|
||||
|
@ -133,13 +125,13 @@ export const doRemoveUnreadSubscriptions = (channelUri: ?string, readUris: ?Arra
|
|||
|
||||
// Remove a single file from a channels unread subscriptions
|
||||
export const doRemoveUnreadSubscription = (channelUri: string, readUri: string) => (
|
||||
dispatch: ReduxDispatch
|
||||
dispatch: SubscriptionDispatch
|
||||
) => {
|
||||
dispatch(doRemoveUnreadSubscriptions(channelUri, [readUri]));
|
||||
};
|
||||
|
||||
export const doCheckSubscription = (subscriptionUri: string, shouldNotify?: boolean) => (
|
||||
dispatch: ReduxDispatch,
|
||||
dispatch: SubscriptionDispatch,
|
||||
getState: GetState
|
||||
) => {
|
||||
// no dispatching FETCH_CHANNEL_CLAIMS_STARTED; causes loading issues on <SubscriptionsPage>
|
||||
|
@ -238,7 +230,7 @@ export const doCheckSubscription = (subscriptionUri: string, shouldNotify?: bool
|
|||
};
|
||||
|
||||
export const doChannelSubscribe = (subscription: Subscription) => (
|
||||
dispatch: ReduxDispatch,
|
||||
dispatch: SubscriptionDispatch,
|
||||
getState: GetState
|
||||
) => {
|
||||
const {
|
||||
|
@ -275,7 +267,7 @@ export const doChannelSubscribe = (subscription: Subscription) => (
|
|||
};
|
||||
|
||||
export const doChannelUnsubscribe = (subscription: Subscription) => (
|
||||
dispatch: ReduxDispatch,
|
||||
dispatch: SubscriptionDispatch,
|
||||
getState: GetState
|
||||
) => {
|
||||
const {
|
||||
|
@ -296,7 +288,7 @@ export const doChannelUnsubscribe = (subscription: Subscription) => (
|
|||
}
|
||||
};
|
||||
|
||||
export const doCheckSubscriptions = () => (dispatch: ReduxDispatch, getState: GetState) => {
|
||||
export const doCheckSubscriptions = () => (dispatch: SubscriptionDispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
const subscriptions = selectSubscriptions(state);
|
||||
|
||||
|
@ -305,7 +297,10 @@ export const doCheckSubscriptions = () => (dispatch: ReduxDispatch, getState: Ge
|
|||
});
|
||||
};
|
||||
|
||||
export const doFetchMySubscriptions = () => (dispatch: ReduxDispatch, getState: GetState) => {
|
||||
export const doFetchMySubscriptions = () => (
|
||||
dispatch: SubscriptionDispatch,
|
||||
getState: GetState
|
||||
) => {
|
||||
const state: { subscriptions: SubscriptionState, settings: any } = getState();
|
||||
const { subscriptions: reduxSubscriptions } = state.subscriptions;
|
||||
|
||||
|
@ -386,7 +381,7 @@ export const doFetchMySubscriptions = () => (dispatch: ReduxDispatch, getState:
|
|||
});
|
||||
};
|
||||
|
||||
export const doCheckSubscriptionsInit = () => (dispatch: ReduxDispatch) => {
|
||||
export const doCheckSubscriptionsInit = () => (dispatch: SubscriptionDispatch) => {
|
||||
// doCheckSubscriptionsInit is called by doDaemonReady
|
||||
// setTimeout below is a hack to ensure redux is hydrated when subscriptions are checked
|
||||
// this will be replaced with <PersistGate> which reqiures a package upgrade
|
||||
|
@ -402,7 +397,7 @@ export const doCheckSubscriptionsInit = () => (dispatch: ReduxDispatch) => {
|
|||
setInterval(() => dispatch(doCheckSubscriptions()), CHECK_SUBSCRIPTIONS_INTERVAL);
|
||||
};
|
||||
|
||||
export const doFetchRecommendedSubscriptions = () => (dispatch: ReduxDispatch) => {
|
||||
export const doFetchRecommendedSubscriptions = () => (dispatch: SubscriptionDispatch) => {
|
||||
dispatch({
|
||||
type: ACTIONS.GET_SUGGESTED_SUBSCRIPTIONS_START,
|
||||
});
|
||||
|
@ -422,18 +417,18 @@ export const doFetchRecommendedSubscriptions = () => (dispatch: ReduxDispatch) =
|
|||
);
|
||||
};
|
||||
|
||||
export const doCompleteFirstRun = () => (dispatch: ReduxDispatch) =>
|
||||
export const doCompleteFirstRun = () => (dispatch: SubscriptionDispatch) =>
|
||||
dispatch({
|
||||
type: ACTIONS.SUBSCRIPTION_FIRST_RUN_COMPLETED,
|
||||
});
|
||||
|
||||
export const doShowSuggestedSubs = () => (dispatch: ReduxDispatch) =>
|
||||
export const doShowSuggestedSubs = () => (dispatch: SubscriptionDispatch) =>
|
||||
dispatch({
|
||||
type: ACTIONS.VIEW_SUGGESTED_SUBSCRIPTIONS,
|
||||
});
|
||||
|
||||
export const doChannelSubscriptionEnableNotifications = (channelName: string) => (
|
||||
dispatch: ReduxDispatch
|
||||
dispatch: SubscriptionDispatch
|
||||
) =>
|
||||
dispatch({
|
||||
type: ACTIONS.CHANNEL_SUBSCRIPTION_ENABLE_NOTIFICATIONS,
|
||||
|
@ -441,7 +436,7 @@ export const doChannelSubscriptionEnableNotifications = (channelName: string) =>
|
|||
});
|
||||
|
||||
export const doChannelSubscriptionDisableNotifications = (channelName: string) => (
|
||||
dispatch: ReduxDispatch
|
||||
dispatch: SubscriptionDispatch
|
||||
) =>
|
||||
dispatch({
|
||||
type: ACTIONS.CHANNEL_SUBSCRIPTION_DISABLE_NOTIFICATIONS,
|
||||
|
|
58
src/redux/middleware/sync.js
Normal file
58
src/redux/middleware/sync.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
import {
|
||||
ACTIONS as LBRY_REDUX_ACTIONS,
|
||||
makeSelectIsFollowingTag,
|
||||
selectFollowedTags,
|
||||
} from 'lbry-redux';
|
||||
import Lbryio from 'lbryio';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||
|
||||
const persistShape = {
|
||||
version: '0',
|
||||
shared: {},
|
||||
};
|
||||
|
||||
export function userStateSyncMiddleware() {
|
||||
return ({ getState }) => next => action => {
|
||||
if (
|
||||
action.type === ACTIONS.CHANNEL_SUBSCRIBE ||
|
||||
action.type === ACTIONS.CHANNEL_UNSUBSCRIBE ||
|
||||
action.type === LBRY_REDUX_ACTIONS.TOGGLE_TAG_FOLLOW
|
||||
) {
|
||||
const newShape = { ...persistShape };
|
||||
const state = getState();
|
||||
const subscriptions = selectSubscriptions(state).map(({ uri }) => uri);
|
||||
const tags = selectFollowedTags(state);
|
||||
newShape.shared.subscriptions = subscriptions;
|
||||
newShape.shared.tags = tags;
|
||||
|
||||
const { uri } = action.data;
|
||||
|
||||
if (action.type === ACTIONS.CHANNEL_SUBSCRIBE) {
|
||||
const newSubscriptions = subscriptions.slice();
|
||||
newSubscriptions.push(uri);
|
||||
newShape.shared.subscriptions = newSubscriptions;
|
||||
} else if (action.type === ACTIONS.CHANNEL_UNSUBSCRIBE) {
|
||||
let newSubscriptions = subscriptions.slice();
|
||||
newSubscriptions = newSubscriptions.filter(subscribedUri => subscribedUri !== uri);
|
||||
newShape.shared.subscriptions = newSubscriptions;
|
||||
} else {
|
||||
const toggledTag = action.data.name;
|
||||
const followedTags = selectFollowedTags(state).map(({ name }) => name);
|
||||
const isFollowing = makeSelectIsFollowingTag(toggledTag)(state);
|
||||
let newTags = followedTags.slice();
|
||||
|
||||
if (isFollowing) {
|
||||
newTags = newTags.filter(followedTag => followedTag.name !== toggledTag);
|
||||
} else {
|
||||
newTags.push(toggledTag);
|
||||
}
|
||||
|
||||
newShape.shared.tags = newTags;
|
||||
}
|
||||
|
||||
Lbryio.call('user_settings', 'set', { settings: newShape });
|
||||
}
|
||||
return next(action);
|
||||
};
|
||||
}
|
|
@ -2,20 +2,6 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import { VIEW_ALL } from 'constants/subscriptions';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
import type {
|
||||
SubscriptionState,
|
||||
Subscription,
|
||||
DoChannelSubscribe,
|
||||
DoChannelUnsubscribe,
|
||||
DoChannelSubscriptionEnableNotifications,
|
||||
DoChannelSubscriptionDisableNotifications,
|
||||
SetSubscriptionLatest,
|
||||
DoUpdateSubscriptionUnreads,
|
||||
DoRemoveSubscriptionUnreads,
|
||||
FetchedSubscriptionsSucess,
|
||||
SetViewMode,
|
||||
GetSuggestedSubscriptionsSuccess,
|
||||
} from 'types/subscription';
|
||||
|
||||
const defaultState: SubscriptionState = {
|
||||
enabledChannelNotifications: [],
|
||||
|
|
|
@ -20,6 +20,9 @@ module.exports = {
|
|||
},
|
||||
resolve: {
|
||||
modules: [path.resolve(__dirname, 'src'), 'node_modules'],
|
||||
alias: {
|
||||
'flow-typed': path.resolve(__dirname, './flow-typed'),
|
||||
},
|
||||
},
|
||||
externals: 'lbry-redux',
|
||||
};
|
||||
|
|
226
yarn.lock
226
yarn.lock
|
@ -642,6 +642,27 @@
|
|||
lodash "^4.17.11"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.2":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.2.tgz#1f981cd5b83e85cfdeb386fc693d4baab392fa54"
|
||||
integrity sha512-wrIBsjA5pl13f0RN4Zx4FNWmU71lv03meGKnqRUoCyan17s4V3WL92f3w3AIuWbNnpcrQyFBU5qMavJoB8d27w==
|
||||
dependencies:
|
||||
"@nodelib/fs.stat" "2.0.2"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/fs.stat@2.0.2", "@nodelib/fs.stat@^2.0.1":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.2.tgz#2762aea8fe78ea256860182dcb52d61ee4b8fda6"
|
||||
integrity sha512-z8+wGWV2dgUhLqrtRYa03yDx4HWMvXKi1z8g3m2JyxAx8F7xk74asqPk5LAETjqDSGLFML/6CDl0+yFunSYicw==
|
||||
|
||||
"@nodelib/fs.walk@^1.2.1":
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.3.tgz#a555dc256acaf00c62b0db29529028dd4d4cb141"
|
||||
integrity sha512-l6t8xEhfK9Sa4YO5mIRdau7XSOADfmh3jCr0evNHdY+HNkW6xuQhgMH7D73VV6WpZOagrW0UludvMTiifiwTfA==
|
||||
dependencies:
|
||||
"@nodelib/fs.scandir" "2.1.2"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@samverschueren/stream-to-observable@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
|
||||
|
@ -652,6 +673,37 @@
|
|||
version "0.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
|
||||
|
||||
"@types/events@*":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
||||
|
||||
"@types/fs-extra@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.0.tgz#d3e2c313ca29f95059f198dd60d1f774642d4b25"
|
||||
integrity sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@^7.1.1":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
||||
integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
|
||||
dependencies:
|
||||
"@types/events" "*"
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/minimatch@*":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||
|
||||
"@types/node@*":
|
||||
version "12.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.5.tgz#e19436e7f8e9b4601005d73673b6dc4784ffcc2f"
|
||||
integrity sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==
|
||||
|
||||
"@types/node@^11.11.6":
|
||||
version "11.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.0.tgz#b0df8d6ef9b5001b2be3a94d909ce3c29a80f9e1"
|
||||
|
@ -974,6 +1026,11 @@ array-union@^1.0.1:
|
|||
dependencies:
|
||||
array-uniq "^1.0.1"
|
||||
|
||||
array-union@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
||||
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
|
||||
|
||||
array-uniq@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
|
||||
|
@ -1154,6 +1211,13 @@ braces@^2.3.1, braces@^2.3.2:
|
|||
split-string "^3.0.2"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
braces@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
brorand@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
||||
|
@ -1477,6 +1541,11 @@ color-name@1.1.1:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
|
||||
|
||||
colorette@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.1.0.tgz#1f943e5a357fac10b4e0f5aaef3b14cdc1af6ec7"
|
||||
integrity sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==
|
||||
|
||||
colors@^1.1.2:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e"
|
||||
|
@ -1790,6 +1859,13 @@ diffie-hellman@^5.0.0:
|
|||
miller-rabin "^4.0.0"
|
||||
randombytes "^2.0.0"
|
||||
|
||||
dir-glob@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
|
||||
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
|
||||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
doctrine@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
|
||||
|
@ -2201,6 +2277,18 @@ fast-diff@^1.1.1:
|
|||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154"
|
||||
|
||||
fast-glob@^3.0.3:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602"
|
||||
integrity sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==
|
||||
dependencies:
|
||||
"@nodelib/fs.stat" "^2.0.1"
|
||||
"@nodelib/fs.walk" "^1.2.1"
|
||||
glob-parent "^5.0.0"
|
||||
is-glob "^4.0.1"
|
||||
merge2 "^1.2.3"
|
||||
micromatch "^4.0.2"
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||
|
@ -2209,6 +2297,13 @@ fast-levenshtein@~2.0.4:
|
|||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||
|
||||
fastq@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2"
|
||||
integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==
|
||||
dependencies:
|
||||
reusify "^1.0.0"
|
||||
|
||||
figgy-pudding@^3.5.1:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
|
||||
|
@ -2243,6 +2338,13 @@ fill-range@^4.0.0:
|
|||
repeat-string "^1.6.1"
|
||||
to-regex-range "^2.1.0"
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
find-babel-config@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.1.0.tgz#acc01043a6749fec34429be6b64f542ebb5d6355"
|
||||
|
@ -2370,6 +2472,15 @@ fs-extra@^5.0.0:
|
|||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-extra@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
||||
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-minipass@^1.2.5:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
|
||||
|
@ -2476,6 +2587,13 @@ glob-parent@^3.1.0:
|
|||
is-glob "^3.1.0"
|
||||
path-dirname "^1.0.0"
|
||||
|
||||
glob-parent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954"
|
||||
integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^7.0.3, glob@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
|
@ -2538,6 +2656,20 @@ globals@^11.0.1, globals@^11.1.0:
|
|||
version "11.7.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
|
||||
|
||||
globby@10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.1.tgz#4782c34cb75dd683351335c5829cc3420e606b22"
|
||||
integrity sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==
|
||||
dependencies:
|
||||
"@types/glob" "^7.1.1"
|
||||
array-union "^2.1.0"
|
||||
dir-glob "^3.0.1"
|
||||
fast-glob "^3.0.3"
|
||||
glob "^7.1.3"
|
||||
ignore "^5.1.1"
|
||||
merge2 "^1.2.3"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
|
||||
|
@ -2568,7 +2700,7 @@ got@^7.1.0:
|
|||
url-parse-lax "^1.0.0"
|
||||
url-to-options "^1.0.1"
|
||||
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.15:
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.2.0:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02"
|
||||
integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==
|
||||
|
@ -2717,6 +2849,11 @@ ignore@^3.3.3:
|
|||
version "3.3.10"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
|
||||
|
||||
ignore@^5.1.1:
|
||||
version "5.1.4"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
|
||||
integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==
|
||||
|
||||
import-local@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
|
||||
|
@ -2945,12 +3082,24 @@ is-glob@^4.0.0:
|
|||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-glob@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
|
||||
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-number@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
is-obj@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
||||
|
@ -2992,6 +3141,13 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
|||
dependencies:
|
||||
isobject "^3.0.1"
|
||||
|
||||
is-plain-object@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928"
|
||||
integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==
|
||||
dependencies:
|
||||
isobject "^4.0.0"
|
||||
|
||||
is-promise@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
|
||||
|
@ -3072,6 +3228,11 @@ isobject@^3.0.0, isobject@^3.0.1:
|
|||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||
|
||||
isobject@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
|
||||
integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
|
||||
|
||||
isurl@^1.0.0-alpha5:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
|
||||
|
@ -3468,6 +3629,11 @@ memory-fs@^0.4.0, memory-fs@^0.4.1:
|
|||
errno "^0.1.3"
|
||||
readable-stream "^2.0.1"
|
||||
|
||||
merge2@^1.2.3:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
|
||||
integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
|
||||
|
||||
micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
|
||||
version "3.1.10"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
|
||||
|
@ -3486,6 +3652,14 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
|
|||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.2"
|
||||
|
||||
micromatch@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
|
||||
integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
|
||||
dependencies:
|
||||
braces "^3.0.1"
|
||||
picomatch "^2.0.5"
|
||||
|
||||
miller-rabin@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
|
||||
|
@ -4073,6 +4247,11 @@ path-type@^2.0.0:
|
|||
dependencies:
|
||||
pify "^2.0.0"
|
||||
|
||||
path-type@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
pbkdf2@^3.0.3:
|
||||
version "3.0.16"
|
||||
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c"
|
||||
|
@ -4083,6 +4262,11 @@ pbkdf2@^3.0.3:
|
|||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
picomatch@^2.0.5:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
|
||||
integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
|
||||
|
||||
pify@^2.0.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
|
@ -4496,6 +4680,11 @@ ret@~0.1.10:
|
|||
version "0.1.15"
|
||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||
|
||||
reusify@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||
|
||||
rimraf@2, rimraf@^2.2.8, rimraf@^2.6.2:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
||||
|
@ -4516,6 +4705,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
|
||||
rollup-plugin-alias@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-alias/-/rollup-plugin-alias-2.0.0.tgz#eea77466a8a8a063007c8edb2e9d7a3d06cbb889"
|
||||
integrity sha512-JVwxV9nwzjc0q7JmrV9jvZlJ8FykNd5r7RmYps8i/7v+vcmmVpeMvXrljhCboYErf4VZ2z9FEj+fP7eJlEGfug==
|
||||
dependencies:
|
||||
slash "^3.0.0"
|
||||
|
||||
rollup-plugin-babel@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-4.3.2.tgz#8c0e1bd7aa9826e90769cf76895007098ffd1413"
|
||||
|
@ -4523,6 +4719,17 @@ rollup-plugin-babel@^4.3.2:
|
|||
"@babel/helper-module-imports" "^7.0.0"
|
||||
rollup-pluginutils "^2.3.0"
|
||||
|
||||
rollup-plugin-copy@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-copy/-/rollup-plugin-copy-3.1.0.tgz#435589857f4e346ea63fc137d99dcc1b25f51c3b"
|
||||
integrity sha512-oVw3ljRV5jv7Yw/6eCEHntVs9Mc+NFglc0iU0J8ei76gldYmtBQ0M/j6WAkZUFVRSrhgfCrEakUllnN87V2f4w==
|
||||
dependencies:
|
||||
"@types/fs-extra" "^8.0.0"
|
||||
colorette "^1.1.0"
|
||||
fs-extra "^8.1.0"
|
||||
globby "10.0.1"
|
||||
is-plain-object "^3.0.0"
|
||||
|
||||
rollup-plugin-flow@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup-plugin-flow/-/rollup-plugin-flow-1.1.1.tgz#6ce568f1dd559666b77ab76b4bae251407528db6"
|
||||
|
@ -4562,6 +4769,11 @@ run-async@^2.2.0:
|
|||
dependencies:
|
||||
is-promise "^2.1.0"
|
||||
|
||||
run-parallel@^1.1.9:
|
||||
version "1.1.9"
|
||||
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
|
||||
integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
|
||||
|
||||
run-queue@^1.0.0, run-queue@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
|
||||
|
@ -4682,6 +4894,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
|
|||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
|
||||
slash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||
|
||||
slice-ansi@0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
||||
|
@ -5064,6 +5281,13 @@ to-regex-range@^2.1.0:
|
|||
is-number "^3.0.0"
|
||||
repeat-string "^1.6.1"
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
to-regex@^3.0.1, to-regex@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
|
||||
|
|
Loading…
Reference in a new issue