diff --git a/.circleci/config.yml b/.circleci/config.yml index e1889c85d8..64e50105bb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,6 +39,7 @@ aliases: name: Setup and build command: | + cp now-secrets.example.json now-secrets.json yarn run build:web yarn run build:api @@ -107,10 +108,10 @@ jobs: - run: name: Danger when: always - command: test -z $DANGER_GITHUB_API_TOKEN && yarn run danger ci || echo "forks are not allowed to run danger" + command: test $DANGER_GITHUB_API_TOKEN && yarn run danger ci || echo "forks are not allowed to run danger" - run: name: Run E2E Tests - command: yarn run test:e2e + command: test $CYPRESS_RECORD_KEY && yarn run test:e2e -- --record || yarn run test:e2e # Run eslint, flow etc. test_static_js: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3f290db376..ea26e4d74b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,6 +12,7 @@ - mercury - hermes - chronos +- pluto - mobile **Run database migrations (delete if no migration was added)** diff --git a/.gitignore b/.gitignore index e59250cecc..1ede68338f 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ api/.env .expo mobile/.expo test-results.json +public/uploads diff --git a/.prettierignore b/.prettierignore index c6417d938a..3d08affae0 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ flow-typed +package.json \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..c1a6f66713 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "es5" +} diff --git a/README.md b/README.md index 832f400993..a6ede63b47 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,11 @@ yarn run db:seed # ⚠️ To empty the database (e.g. if there's faulty data) run yarn run db:drop ``` +There's a shortcut for dropping, migrating and seeding the database too: +```sh +yarn run db:reset +``` + #### Getting the secrets While the app will run without any secrets set up, you won't be able to sign in locally. To get that set up, copy the provided example secrets file to the real location: diff --git a/admin/package.json b/admin/package.json index ad9a021deb..15fa42015f 100644 --- a/admin/package.json +++ b/admin/package.json @@ -44,11 +44,8 @@ "subscriptions-transport-ws": "^0.9.5" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject", - "predeploy": "npm run build", - "deploy": "now build" + "start": "NODE_PATH=../ react-scripts start", + "build": "NODE_PATH=../ react-scripts build", + "test": "NODE_PATH=../ react-scripts test --env=jsdom" } } diff --git a/api/index.js b/api/index.js index 6d833d9732..bbbbd9ec8d 100644 --- a/api/index.js +++ b/api/index.js @@ -11,6 +11,7 @@ import express from 'express'; import Raven from 'shared/raven'; import { ApolloEngine } from 'apollo-engine'; import toobusy from 'shared/middlewares/toobusy'; +import addSecurityMiddleware from 'shared/middlewares/security'; import { init as initPassport } from './authentication.js'; import type { DBUser } from 'shared/types'; @@ -28,6 +29,9 @@ app.set('trust proxy', true); // Return the request if the server is too busy app.use(toobusy); +// Security middleware. +addSecurityMiddleware(app); + // Send all responses as gzip app.use(compression()); diff --git a/api/models/community.js b/api/models/community.js index 6597de3557..be068c0ede 100644 --- a/api/models/community.js +++ b/api/models/community.js @@ -1,7 +1,7 @@ // @flow const { db } = require('./db'); import { parseRange } from './utils'; -import { uploadImage } from '../utils/s3'; +import { uploadImage } from '../utils/file-storage'; import getRandomDefaultPhoto from '../utils/get-random-default-photo'; import { sendNewCommunityWelcomeEmailQueue, diff --git a/api/models/user.js b/api/models/user.js index 4465135606..6373fd9ef5 100644 --- a/api/models/user.js +++ b/api/models/user.js @@ -1,6 +1,6 @@ // @flow const { db } = require('./db'); -import { uploadImage } from '../utils/s3'; +import { uploadImage } from '../utils/file-storage'; import { createNewUsersSettings } from './usersSettings'; import { sendNewUserWelcomeEmailQueue } from 'shared/bull/queues'; import type { PaginationOptions } from '../utils/paginate-arrays'; diff --git a/api/mutations/channel/disableChannelTokenJoin.js b/api/mutations/channel/disableChannelTokenJoin.js index f5b15d4af4..6347f18b1a 100644 --- a/api/mutations/channel/disableChannelTokenJoin.js +++ b/api/mutations/channel/disableChannelTokenJoin.js @@ -22,12 +22,28 @@ export default async ( return new UserError('You must be signed in to manage this channel.'); } - const [permissions, settings] = await Promise.all([ + const [channelPermissions, channel, settings] = await Promise.all([ loaders.userPermissionsInChannel.load([currentUser.id, channelId]), + loaders.channel.load(channelId), loaders.channelSettings.load(channelId), ]); - if (!permissions.isOwner) { + const communityPermissions = await loaders.userPermissionsInCommunity.load([ + currentUser.id, + channel.communityId, + ]); + + if (!channelPermissions || !communityPermissions) { + return new UserError("You don't have permission to do this."); + } + + const canEdit = + channelPermissions.isOwner || + channelPermissions.isModerator || + communityPermissions.isOwner || + communityPermissions.isModerator; + + if (!canEdit) { return new UserError("You don't have permission to do this."); } diff --git a/api/mutations/channel/enableChannelTokenJoin.js b/api/mutations/channel/enableChannelTokenJoin.js index 877a4d1efd..b187f81460 100644 --- a/api/mutations/channel/enableChannelTokenJoin.js +++ b/api/mutations/channel/enableChannelTokenJoin.js @@ -22,12 +22,28 @@ export default async ( return new UserError('You must be signed in to manage this channel.'); } - const [permissions, settings] = await Promise.all([ + const [channelPermissions, channel, settings] = await Promise.all([ loaders.userPermissionsInChannel.load([currentUser.id, channelId]), + loaders.channel.load(channelId), loaders.channelSettings.load(channelId), ]); - if (!permissions.isOwner) { + const communityPermissions = await loaders.userPermissionsInCommunity.load([ + currentUser.id, + channel.communityId, + ]); + + if (!channelPermissions || !communityPermissions) { + return new UserError("You don't have permission to do this."); + } + + const canEdit = + channelPermissions.isOwner || + channelPermissions.isModerator || + communityPermissions.isOwner || + communityPermissions.isModerator; + + if (!canEdit) { return new UserError("You don't have permission to do this."); } diff --git a/api/mutations/channel/resetChannelJoinToken.js b/api/mutations/channel/resetChannelJoinToken.js index 86aa45b63b..658d660edb 100644 --- a/api/mutations/channel/resetChannelJoinToken.js +++ b/api/mutations/channel/resetChannelJoinToken.js @@ -23,12 +23,28 @@ export default async ( return new UserError('You must be signed in to manage this channel.'); } - const [permissions, settings] = await Promise.all([ + const [channelPermissions, channel, settings] = await Promise.all([ loaders.userPermissionsInChannel.load([currentUser.id, channelId]), + loaders.channel.load(channelId), loaders.channelSettings.load(channelId), ]); - if (!permissions.isOwner) { + const communityPermissions = await loaders.userPermissionsInCommunity.load([ + currentUser.id, + channel.communityId, + ]); + + if (!channelPermissions || !communityPermissions) { + return new UserError("You don't have permission to do this."); + } + + const canEdit = + channelPermissions.isOwner || + channelPermissions.isModerator || + communityPermissions.isOwner || + communityPermissions.isModerator; + + if (!canEdit) { return new UserError("You don't have permission to do this."); } diff --git a/api/mutations/channel/togglePendingUser.js b/api/mutations/channel/togglePendingUser.js index 64314abe4b..e2f855a134 100644 --- a/api/mutations/channel/togglePendingUser.js +++ b/api/mutations/channel/togglePendingUser.js @@ -12,6 +12,7 @@ import { getUserPermissionsInCommunity, createMemberInCommunity, } from '../../models/usersCommunities'; +import { sendPrivateChannelRequestApprovedQueue } from 'shared/bull/queues'; type TogglePendingUserInput = { input: { @@ -74,7 +75,9 @@ export default async ( // user is neither a community or channel owner, they don't have permission if ( currentUserChannelPermissions.isOwner || - currentUserCommunityPermissions.isOwner + currentUserCommunityPermissions.isOwner || + currentUserChannelPermissions.isModerator || + currentUserCommunityPermissions.isModerator ) { // all checks passed // determine whether to approve or block them @@ -91,6 +94,13 @@ export default async ( input.userId ); + sendPrivateChannelRequestApprovedQueue.add({ + userId: input.userId, + channelId: input.channelId, + communityId: channelToEvaluate.communityId, + moderatorId: currentUser.id, + }); + // if the user is a member of the parent community, we can return if (evaluatedUserCommunityPermissions.isMember) { return Promise.all([channelToEvaluate, approveUser]).then( @@ -113,6 +123,6 @@ export default async ( } return new UserError( - "You don't have permission to make changes to this channel." + "You don't have permission to manage users in this channel." ); }; diff --git a/api/mutations/channel/unblockUser.js b/api/mutations/channel/unblockUser.js index 98dcbedf2b..cdfa58df3b 100644 --- a/api/mutations/channel/unblockUser.js +++ b/api/mutations/channel/unblockUser.js @@ -59,7 +59,9 @@ export default async ( // if a user owns the community or owns the channel, they can make this change if ( currentUserChannelPermissions.isOwner || - currentUserCommunityPermissions.isOwner + currentUserCommunityPermissions.isOwner || + currentUserChannelPermissions.isModerator || + currentUserCommunityPermissions.isModerator ) { return unblockMemberInChannel(input.channelId, input.userId).then( () => channelToEvaluate diff --git a/api/mutations/community/disableBrandedLogin.js b/api/mutations/community/disableBrandedLogin.js index 7efda1fd77..21ae6d77de 100644 --- a/api/mutations/community/disableBrandedLogin.js +++ b/api/mutations/community/disableBrandedLogin.js @@ -27,7 +27,13 @@ export default async ( loaders.communitySettings.load(communityId), ]); - if (!permissions.isOwner) { + if (!permissions) { + return new UserError("You don't have permission to do this."); + } + + const { isOwner, isModerator } = permissions; + + if (!isOwner && !isModerator) { return new UserError("You don't have permission to do this."); } diff --git a/api/mutations/community/enableBrandedLogin.js b/api/mutations/community/enableBrandedLogin.js index cb8134ff9d..b06c02d06d 100644 --- a/api/mutations/community/enableBrandedLogin.js +++ b/api/mutations/community/enableBrandedLogin.js @@ -27,7 +27,13 @@ export default async ( loaders.communitySettings.load(communityId), ]); - if (!permissions.isOwner) { + if (!permissions) { + return new UserError("You don't have permission to do this."); + } + + const { isOwner, isModerator } = permissions; + + if (!isOwner && !isModerator) { return new UserError("You don't have permission to do this."); } diff --git a/api/mutations/community/saveBrandedLoginSettings.js b/api/mutations/community/saveBrandedLoginSettings.js index 41f60611bd..a290b0ee8d 100644 --- a/api/mutations/community/saveBrandedLoginSettings.js +++ b/api/mutations/community/saveBrandedLoginSettings.js @@ -34,7 +34,13 @@ export default async ( loaders.communitySettings.load(communityId), ]); - if (!permissions.isOwner) { + if (!permissions) { + return new UserError("You don't have permission to do this."); + } + + const { isOwner, isModerator } = permissions; + + if (!isOwner && !isModerator) { return new UserError("You don't have permission to do this."); } diff --git a/api/mutations/directMessageThread/createDirectMessageThread.js b/api/mutations/directMessageThread/createDirectMessageThread.js index 0a62b79407..014eca9c8b 100644 --- a/api/mutations/directMessageThread/createDirectMessageThread.js +++ b/api/mutations/directMessageThread/createDirectMessageThread.js @@ -6,7 +6,7 @@ import { getDirectMessageThread, createDirectMessageThread, } from '../../models/directMessageThread'; -import { uploadImage } from '../../utils/s3'; +import { uploadImage } from '../../utils/file-storage'; import { storeMessage } from '../../models/message'; import { setUserLastSeenInDirectMessageThread, diff --git a/api/mutations/message/addMessage.js b/api/mutations/message/addMessage.js index 34740ef711..baf7c0fb6e 100644 --- a/api/mutations/message/addMessage.js +++ b/api/mutations/message/addMessage.js @@ -3,7 +3,7 @@ import { stateFromMarkdown } from 'draft-js-import-markdown'; import { EditorState } from 'draft-js'; import type { GraphQLContext } from '../../'; import UserError from '../../utils/UserError'; -import { uploadImage } from '../../utils/s3'; +import { uploadImage } from '../../utils/file-storage'; import { storeMessage } from '../../models/message'; import { setDirectMessageThreadLastActive } from '../../models/directMessageThread'; import { setUserLastSeenInDirectMessageThread } from '../../models/usersDirectMessageThreads'; diff --git a/api/mutations/thread/editThread.js b/api/mutations/thread/editThread.js index 773b7a4027..58c95e75c6 100644 --- a/api/mutations/thread/editThread.js +++ b/api/mutations/thread/editThread.js @@ -2,7 +2,7 @@ import type { GraphQLContext } from '../../'; import type { EditThreadInput } from '../../models/thread'; import UserError from '../../utils/UserError'; -import { uploadImage } from '../../utils/s3'; +import { uploadImage } from '../../utils/file-storage'; import { getThreads, editThread } from '../../models/thread'; import { getUserPermissionsInCommunity } from '../../models/usersCommunities'; import { getUserPermissionsInChannel } from '../../models/usersChannels'; diff --git a/api/mutations/thread/publishThread.js b/api/mutations/thread/publishThread.js index 852982a787..67f3dbc323 100644 --- a/api/mutations/thread/publishThread.js +++ b/api/mutations/thread/publishThread.js @@ -3,7 +3,7 @@ const debug = require('debug')('api:mutations:thread:publish-thread'); import stringSimilarity from 'string-similarity'; import type { GraphQLContext } from '../../'; import UserError from '../../utils/UserError'; -import { uploadImage } from '../../utils/s3'; +import { uploadImage } from '../../utils/file-storage'; import { publishThread, editThread, diff --git a/api/package.json b/api/package.json index 36d3dfe5f2..d6ecd76d21 100644 --- a/api/package.json +++ b/api/package.json @@ -49,9 +49,11 @@ "graphql-server-express": "1.3.0", "graphql-subscriptions": "0.4.x", "graphql-tools": "1.2.3", + "helmet": "^3.12.0", "highlight.js": "^9.10.0", "history": "^4.6.1", "hoist-non-react-statics": "^2.3.1", + "hpp": "^0.2.2", "imgix-core-js": "^1.0.6", "immutability-helper": "^2.2.0", "isomorphic-fetch": "^2.2.1", diff --git a/api/queries/community/billingSettings.js b/api/queries/community/billingSettings.js index 03bc93b5f4..f8b89ddcdc 100644 --- a/api/queries/community/billingSettings.js +++ b/api/queries/community/billingSettings.js @@ -29,6 +29,8 @@ export default async ( loaders.stripeCustomers.load(stripeCustomerId), ]); + if (!permissions) return defaultResult; + const { isOwner, isModerator } = permissions; const customer = stripeCustomer && stripeCustomer.reduction.length > 0 @@ -49,8 +51,9 @@ export default async ( : subscriptions; return { - pendingAdministratorEmail: isOwner ? pendingAdministratorEmail : null, - administratorEmail: isOwner ? administratorEmail : null, + pendingAdministratorEmail: + isOwner || isModerator ? pendingAdministratorEmail : null, + administratorEmail: isOwner || isModerator ? administratorEmail : null, sources: sources, invoices: cleanInvoices, subscriptions: subscriptions, diff --git a/api/queries/community/hasChargeableSource.js b/api/queries/community/hasChargeableSource.js index c89639e856..2a10990e61 100644 --- a/api/queries/community/hasChargeableSource.js +++ b/api/queries/community/hasChargeableSource.js @@ -9,10 +9,14 @@ export default async ( ) => { if (!stripeCustomerId || !user) return false; - const { - isOwner, - isModerator, - } = await loaders.userPermissionsInCommunity.load([user.id, id]); + const permissions = await loaders.userPermissionsInCommunity.load([ + user.id, + id, + ]); + + if (!permissions) return null; + + const { isOwner, isModerator } = permissions; if (!isOwner && !isModerator) return null; return loaders.stripeCustomers.load(stripeCustomerId).then(results => { diff --git a/api/utils/file-storage.js b/api/utils/file-storage.js new file mode 100644 index 0000000000..5c27f0f6db --- /dev/null +++ b/api/utils/file-storage.js @@ -0,0 +1,27 @@ +// @flow +require('now-env'); + +import type { FileUpload, EntityTypes } from 'shared/types'; + +const { FILE_STORAGE } = process.env; + +const getUploadImageFn = () => { + switch (FILE_STORAGE) { + case 'local': + return require('./file-system').uploadImage; + case 's3': + default: + return require('./s3').uploadImage; + } +}; + +const uploadImageFn = getUploadImageFn(); + +export const uploadImage = ( + file: FileUpload, + entity: EntityTypes, + id: string +): Promise => + uploadImageFn(file, entity, id).catch(err => { + throw new Error(err); + }); diff --git a/api/utils/file-system.js b/api/utils/file-system.js new file mode 100644 index 0000000000..2e835ce70a --- /dev/null +++ b/api/utils/file-system.js @@ -0,0 +1,40 @@ +// @flow +import shortid from 'shortid'; +import fs from 'fs'; + +import type { FileUpload, EntityTypes } from 'shared/types'; + +const STORAGE_DIR = 'public/uploads'; +const READ_WRITE_MODE = 0o777; + +const dirExists = (path: string): Promise => + new Promise(res => fs.access(path, fs.constants.F_OK, err => res(!!!err))); + +const createUploadsDir = (path: string): Promise => + new Promise(res => + fs.mkdir(path, READ_WRITE_MODE, err => { + if (err) throw new Error(err); + res(); + }) + ); + +export const uploadImage = async ( + file: FileUpload, + entity: EntityTypes, + id: string +): Promise => { + const result = await file; + + if (!await dirExists(STORAGE_DIR)) { + await createUploadsDir(STORAGE_DIR); + } + + return new Promise(res => { + const filePath = `${shortid.generate()}-${entity}-${id}`; + const { stream } = result; + stream.pipe(fs.createWriteStream(`${STORAGE_DIR}/${filePath}`)); + stream.on('end', () => { + res(encodeURI(`/uploads/${filePath}`)); + }); + }); +}; diff --git a/api/utils/s3.js b/api/utils/s3.js index 64cd13932f..01d658c547 100644 --- a/api/utils/s3.js +++ b/api/utils/s3.js @@ -4,8 +4,7 @@ import AWS from 'aws-sdk'; import shortid from 'shortid'; const IS_PROD = process.env.NODE_ENV === 'production'; -import type { FileUpload } from 'shared/types'; -type EntityTypes = 'communities' | 'channels' | 'users' | 'threads'; +import type { FileUpload, EntityTypes } from 'shared/types'; let S3_TOKEN = process.env.S3_TOKEN; let S3_SECRET = process.env.S3_SECRET; @@ -36,7 +35,7 @@ const generateImageUrl = path => { return imgixBase + '/' + newPath; }; -const upload = async ( +export const uploadImage = async ( file: FileUpload, entity: EntityTypes, id: string @@ -62,13 +61,3 @@ const upload = async ( ); }); }; - -export const uploadImage = async ( - file: FileUpload, - entity: EntityTypes, - id: string -): Promise => { - return await upload(file, entity, id).catch(err => { - throw new Error(err); - }); -}; diff --git a/api/yarn.lock b/api/yarn.lock index 53a37057da..a2176bf24f 100644 --- a/api/yarn.lock +++ b/api/yarn.lock @@ -1414,6 +1414,10 @@ camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" +camelize@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + caniuse-lite@^1.0.30000792: version "1.0.30000792" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000792.tgz#d0cea981f8118f3961471afbb43c9a1e5bbf0332" @@ -1705,6 +1709,10 @@ content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" +content-security-policy-builder@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-2.0.0.tgz#8749a1d542fcbe82237281ea9f716ce68b394dd2" + content-type-parser@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" @@ -1926,6 +1934,10 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +dasherize@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" + dataloader@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.3.0.tgz#6fec5be4b30a712e4afd30b86b4334566b97673b" @@ -2103,6 +2115,10 @@ direction@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/direction/-/direction-0.1.5.tgz#ce5d797f97e26f8be7beff53f7dc40e1c1a9ec4c" +dns-prefetch-control@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" + dom-helpers@^3.2.0: version "3.3.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" @@ -2156,6 +2172,10 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" +dont-sniff-mimetype@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" + dot-prop@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" @@ -2639,6 +2659,10 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +expect-ct@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.1.0.tgz#52735678de18530890d8d7b95f0ac63640958094" + expect@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/expect/-/expect-21.2.1.tgz#003ac2ac7005c3c29e73b38a272d4afadd6d1d7b" @@ -2933,6 +2957,10 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +frameguard@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9" + fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -3382,6 +3410,37 @@ hawk@~6.0.2: hoek "4.x.x" sntp "2.x.x" +helmet-csp@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.7.0.tgz#7934094617d1feb7bb2dc43bb7d9e8830f774716" + dependencies: + camelize "1.0.0" + content-security-policy-builder "2.0.0" + dasherize "2.0.0" + lodash.reduce "4.6.0" + platform "1.3.5" + +helmet@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.12.0.tgz#2098e35cf4e51c64c2f1d38670b7d382a377d92c" + dependencies: + dns-prefetch-control "0.1.0" + dont-sniff-mimetype "1.0.0" + expect-ct "0.1.0" + frameguard "3.0.0" + helmet-csp "2.7.0" + hide-powered-by "1.0.0" + hpkp "2.0.0" + hsts "2.1.0" + ienoopen "1.0.0" + nocache "2.0.0" + referrer-policy "1.1.0" + x-xss-protection "1.1.0" + +hide-powered-by@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" + highlight.js@^9.10.0: version "9.12.0" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" @@ -3431,6 +3490,21 @@ hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" +hpkp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672" + +hpp@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/hpp/-/hpp-0.2.2.tgz#0ec5f77472049a74361d85ba2b88e2470a4356f8" + dependencies: + lodash "^4.7.0" + type-is "^1.6.12" + +hsts@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.1.0.tgz#cbd6c918a2385fee1dd5680bfb2b3a194c0121cc" + html-encoding-sniffer@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" @@ -3491,6 +3565,10 @@ ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" +ienoopen@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b" + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -4581,7 +4659,7 @@ lodash.pick@^4.2.1, lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" -lodash.reduce@^4.4.0: +lodash.reduce@4.6.0, lodash.reduce@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" @@ -4618,7 +4696,7 @@ lodash.values@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" -lodash@^4.0.0, lodash@^4.13.1: +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.7.0: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" @@ -4819,12 +4897,22 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.7: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: mime-db "~1.30.0" +mime-types@~2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" @@ -4936,6 +5024,10 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +nocache@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" + node-env-file@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/node-env-file/-/node-env-file-0.1.8.tgz#fccb7b050f735b5a33da9eb937cf6f1ab457fb69" @@ -5482,6 +5574,10 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" +platform@1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -5998,6 +6094,10 @@ redux@^3.6.0: loose-envify "^1.1.0" symbol-observable "^1.0.3" +referrer-policy@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79" + regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" @@ -7014,6 +7114,13 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-is@^1.6.12: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" @@ -7480,6 +7587,10 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" +x-xss-protection@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.1.0.tgz#4f1898c332deb1e7f2be1280efb3e2c53d69c1a7" + xdg-basedir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" diff --git a/athena/models/usersChannels.js b/athena/models/usersChannels.js index 9aaebafcb6..b9cf9b8c95 100644 --- a/athena/models/usersChannels.js +++ b/athena/models/usersChannels.js @@ -48,3 +48,14 @@ export const getOwnersInChannel = ( .map(user => user('userId')) .run(); }; + +export const getModeratorsInChannel = ( + channelId: string +): Promise> => { + return db + .table('usersChannels') + .getAll(channelId, { index: 'channelId' }) + .filter({ isModerator: true }) + .map(user => user('userId')) + .run(); +}; diff --git a/athena/models/usersCommunities.js b/athena/models/usersCommunities.js index c5a0939703..8c0903b75d 100644 --- a/athena/models/usersCommunities.js +++ b/athena/models/usersCommunities.js @@ -23,6 +23,17 @@ export const getOwnersInCommunity = ( .then(users => users.map(user => user.userId)); }; +export const getModeratorsInCommunity = ( + communityId: string +): Promise> => { + return db + .table('usersCommunities') + .getAll(communityId, { index: 'communityId' }) + .filter({ isModerator: true }) + .run() + .then(users => users.map(user => user.userId)); +}; + export const getUserPermissionsInCommunity = ( communityId: string, userId: string diff --git a/athena/package.json b/athena/package.json index 779e50e007..1abfea402b 100644 --- a/athena/package.json +++ b/athena/package.json @@ -15,6 +15,7 @@ "raven": "^2.1.1", "rethinkdbdash": "^2.3.29", "source-map-support": "^0.4.15", + "toobusy-js": "^0.5.1", "validator": "^9.2.0", "web-push": "^3.2.2" } diff --git a/athena/queues/private-channel-request-approved.js b/athena/queues/private-channel-request-approved.js index 3c81ac7035..e9867428b3 100644 --- a/athena/queues/private-channel-request-approved.js +++ b/athena/queues/private-channel-request-approved.js @@ -10,16 +10,12 @@ import { getUsers } from '../models/user'; import { fetchPayload } from '../utils/payloads'; import isEmail from 'validator/lib/isEmail'; import { sendPrivateChannelRequestApprovedEmailQueue } from 'shared/bull/queues'; +import type { + Job, + PrivateChannelRequestApprovedJobData, +} from 'shared/bull/types'; -type JobData = { - data: { - userId: string, - channelId: string, - communityId: string, - moderatorId: string, - }, -}; -export default async (job: JobData) => { +export default async (job: Job) => { const { userId, channelId, communityId, moderatorId } = job.data; debug(`user request to join channel ${channelId} approved`); diff --git a/athena/queues/private-channel-request-sent.js b/athena/queues/private-channel-request-sent.js index 131b49f749..bdf51bb4f7 100644 --- a/athena/queues/private-channel-request-sent.js +++ b/athena/queues/private-channel-request-sent.js @@ -6,12 +6,18 @@ import Raven from 'shared/raven'; import { getCommunityById } from '../models/community'; import { storeNotification } from '../models/notification'; import { storeUsersNotifications } from '../models/usersNotifications'; -import { getOwnersInChannel } from '../models/usersChannels'; +import { + getOwnersInChannel, + getModeratorsInChannel, +} from '../models/usersChannels'; +import { + getOwnersInCommunity, + getModeratorsInCommunity, +} from '../models/usersCommunities'; import { getUsers } from '../models/user'; import { fetchPayload, createPayload } from '../utils/payloads'; import isEmail from 'validator/lib/isEmail'; import { sendPrivateChannelRequestEmailQueue } from 'shared/bull/queues'; -import type { DBChannel } from 'shared/types'; import type { Job, PrivateChannelRequestJobData } from 'shared/bull/types'; export default async (job: Job) => { @@ -45,12 +51,29 @@ export default async (job: Job) => { const updatedNotification = await storeNotification(nextNotificationRecord); // get the owners of the channel - const recipients = await getOwnersInChannel(channel.id); + const [ + ownersInCommunity, + moderatorsInCommunity, + ownersInChannel, + moderatorsInChannel, + ] = await Promise.all([ + getOwnersInCommunity(channel.communityId), + getModeratorsInCommunity(channel.communityId), + getOwnersInChannel(channel.id), + getModeratorsInChannel(channel.id), + ]); + + const uniqueRecipientIds = [ + ...ownersInCommunity, + ...moderatorsInCommunity, + ...ownersInChannel, + ...moderatorsInChannel, + ].filter((item, i, ar) => ar.indexOf(item) === i); // get all the user data for the owners - const recipientsWithUserData = await getUsers([...recipients]); + const recipientsWithUserData = await getUsers([...uniqueRecipientIds]); - // only get owners with emails + // only get owners + moderators with emails const filteredRecipients = recipientsWithUserData.filter( owner => owner.email && isEmail(owner.email) ); diff --git a/athena/queues/track-user-thread-last-seen.js b/athena/queues/track-user-thread-last-seen.js index 36ef640e9c..4f19f85d62 100644 --- a/athena/queues/track-user-thread-last-seen.js +++ b/athena/queues/track-user-thread-last-seen.js @@ -20,7 +20,13 @@ export default async (job: Job) => { ); return; } - const date = new Date(parseInt(timestamp, 10)); + // Timestamp will be serialized to Redis, so it's either a string date "Thu 20 Nov 2017" or a + // string timestamp. "1835463856" We gotta make sure to handle both those cases, so we try and + // parse to int first, and if that fails (i.e. returns NaN) we assume it's a string date. + let parsedTimestamp = + typeof timestamp === 'string' ? parseInt(timestamp, 10) : timestamp; + if (isNaN(parsedTimestamp)) parsedTimestamp = timestamp; + const date = new Date(parsedTimestamp); debug( `new job\nthreadId: ${threadId}\nuserId: ${userId}\ntimestamp: ${new Date( timestamp diff --git a/athena/yarn.lock b/athena/yarn.lock index 23c95c23f6..a52f095aaa 100644 --- a/athena/yarn.lock +++ b/athena/yarn.lock @@ -709,6 +709,10 @@ timed-out@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" +toobusy-js@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/toobusy-js/-/toobusy-js-0.5.1.tgz#5511f78f6a87a6a512d44fdb0efa13672217f659" + ua-parser-js@^0.7.9: version "0.7.14" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.14.tgz#110d53fa4c3f326c121292bbeac904d2e03387ca" diff --git a/chronos/package.json b/chronos/package.json index 069b619803..6956e1e2d7 100644 --- a/chronos/package.json +++ b/chronos/package.json @@ -8,10 +8,12 @@ "draft-js": "^0.10.3", "lodash": "^4.17.4", "lodash.intersection": "^4.4.0", + "now-env": "^3.0.4", "postmark": "^1.3.1", "raven": "^2.1.1", "rethinkdbdash": "^2.3.29", - "source-map-support": "^0.4.15" + "source-map-support": "^0.4.15", + "toobusy-js": "^0.5.1" }, "devDependencies": { "json-stringify-pretty-compact": "^1.0.4" diff --git a/chronos/yarn.lock b/chronos/yarn.lock index ee3931fe9e..32e8c80251 100644 --- a/chronos/yarn.lock +++ b/chronos/yarn.lock @@ -470,6 +470,10 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +now-env@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/now-env/-/now-env-3.0.4.tgz#f9ed88884bff8d208ad3eaf39cc3437dd1a591ad" + nth-check@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" @@ -611,6 +615,10 @@ timed-out@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" +toobusy-js@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/toobusy-js/-/toobusy-js-0.5.1.tgz#5511f78f6a87a6a512d44fdb0efa13672217f659" + ua-parser-js@^0.7.9: version "0.7.14" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.14.tgz#110d53fa4c3f326c121292bbeac904d2e03387ca" diff --git a/cypress.json b/cypress.json index fccc6d3890..77ee091c6c 100644 --- a/cypress.json +++ b/cypress.json @@ -2,9 +2,11 @@ "baseUrl": "http://localhost:3000", "viewportWidth": 1300, "defaultCommandTimeout": 20000, - "blacklistHosts": ["*.google-analytics.com"], - "videoRecording": false, + "blacklistHosts": [ + "*.google-analytics.com" + ], "env": { "DEBUG": "src*,testing*,build*" - } + }, + "projectId": "6a92uk" } diff --git a/cypress/integration/community_settings_overview_spec.js b/cypress/integration/community_settings_overview_spec.js index b4b73b0c80..a962a060d0 100644 --- a/cypress/integration/community_settings_overview_spec.js +++ b/cypress/integration/community_settings_overview_spec.js @@ -48,6 +48,7 @@ describe('Community settings overview tab', () => { .type(website); // Submit changes cy.get('button[type="submit"]').click(); + cy.visit(`/${community.slug}`); cy.location('pathname').should('eq', `/${community.slug}`); // Make sure changes were applied cy.contains(description); @@ -68,13 +69,13 @@ describe('Community settings overview tab', () => { .clear() .type(community.website); cy.get('button[type="submit"]').click(); + cy.visit(`/${community.slug}`); cy.location('pathname').should('eq', `/${community.slug}`); cy.contains(community.name); cy.contains(community.description); cy.contains(community.website); }); - // TODO: FIXME it.skip('should allow managing branded login settings', () => { const brandedLoginString = 'Testing branded login custom message'; diff --git a/cypress/integration/thread_spec.js b/cypress/integration/thread_spec.js index 38e6d68694..adab0ed6e9 100644 --- a/cypress/integration/thread_spec.js +++ b/cypress/integration/thread_spec.js @@ -1,6 +1,11 @@ import { toPlainText, toState } from '../../shared/draft-utils'; import data from '../../shared/testing/data'; +import { + SPECTRUM_PRIVATE_CHANNEL_ID, + QUIET_USER_ID, +} from '../../api/migrations/seed/default/constants'; +// Public const thread = data.threads[0]; const community = data.communities.find( community => community.id === thread.communityId @@ -10,46 +15,55 @@ const messages = data.messages.filter( message => message.threadId === thread.id ); +// Private +const privateThread = data.threads.find( + thread => thread.channelId === SPECTRUM_PRIVATE_CHANNEL_ID +); +const privateAuthor = data.users.find( + user => user.id === privateThread.creatorId +); + describe('Thread View', () => { - // Before every test suite set up a new browser and page - beforeEach(() => { - cy.visit(`/thread/${thread.id}`); - }); + describe('Public', () => { + beforeEach(() => { + cy.visit(`/thread/${thread.id}`); + }); - it('should render', () => { - cy.get('[data-cy="thread-view"]').should('be.visible'); - cy.contains(thread.content.title); - cy.contains( - toPlainText(toState(JSON.parse(thread.content.body))).split(' ')[0] - ); - cy.contains(author.name); - cy.contains(author.username); - cy.get(`[href*="/users/${author.username}"]`).should('be.visible'); - cy.get(`[href*="/${community.slug}"]`).should('be.visible'); + it('should render', () => { + cy.get('[data-cy="thread-view"]').should('be.visible'); + cy.contains(thread.content.title); + cy.contains( + toPlainText(toState(JSON.parse(thread.content.body))).split(' ')[0] + ); + cy.contains(author.name); + cy.contains(author.username); + cy.get(`[href*="/users/${author.username}"]`).should('be.visible'); + cy.get(`[href*="/${community.slug}"]`).should('be.visible'); - cy.get('[data-cy="message-group"]').should('be.visible'); - messages.forEach(message => { - cy.contains(toPlainText(toState(JSON.parse(message.content.body)))); + cy.get('[data-cy="message-group"]').should('be.visible'); + messages.forEach(message => { + cy.contains(toPlainText(toState(JSON.parse(message.content.body)))); + }); }); - }); - it('should prompt logged-out users to log in', () => { - const newMessage = 'A new message!'; - cy.get('[data-cy="thread-view"]').should('be.visible'); - cy.get('[contenteditable="true"]').type(newMessage); - // Wait for the messages to be loaded before sending new message - cy.get('[data-cy="message-group"]').should('be.visible'); - cy.get('[data-cy="chat-input-send-button"]').click(); - cy.contains('Sign in'); + it('should prompt logged-out users to log in', () => { + const newMessage = 'A new message!'; + cy.get('[data-cy="thread-view"]').should('be.visible'); + cy.get('[contenteditable="true"]').type(newMessage); + // Wait for the messages to be loaded before sending new message + cy.get('[data-cy="message-group"]').should('be.visible'); + cy.get('[data-cy="chat-input-send-button"]').click(); + cy.contains('Sign in'); + }); }); - describe('authenticated', () => { + describe('Public (authenticated)', () => { beforeEach(() => { cy.auth(author.id); + cy.visit(`/thread/${thread.id}`); }); - it('should allow logged-in users to send messages', () => { - cy.auth(author.id); + it('should allow logged-in users to send public messages', () => { const newMessage = 'A new message!'; cy.get('[data-cy="thread-view"]').should('be.visible'); cy.get('[contenteditable="true"]').type(newMessage); @@ -61,6 +75,34 @@ describe('Thread View', () => { cy.contains(newMessage); }); }); + + describe('Private', () => { + beforeEach(() => { + cy.auth(QUIET_USER_ID); + cy.visit(`/thread/${privateThread.id}`); + }); + + it("should not allow logged-in users to send private messages if they don't have permission", () => { + cy.get('[data-cy="null-thread-view"]').should('be.visible'); + }); + }); + + describe('Private (with permissions)', () => { + beforeEach(() => { + cy.auth(privateAuthor.id); + cy.visit(`/thread/${privateThread.id}`); + }); + + it('should allow logged-in users to send private messages if they have permission', () => { + const newMessage = 'A new private message!'; + cy.get('[data-cy="thread-view"]').should('be.visible'); + cy.get('[contenteditable="true"]').type(newMessage); + cy.get('[data-cy="chat-input-send-button"]').click(); + // Clear the chat input and make sure the message was sent by matching the text + cy.get('[contenteditable="true"]').type(''); + cy.contains(newMessage); + }); + }); }); describe('/new/thread', () => { diff --git a/cypress/integration/user/delete_user_spec.js b/cypress/integration/user/delete_user_spec.js index f8e1b2aa89..c42ebb252b 100644 --- a/cypress/integration/user/delete_user_spec.js +++ b/cypress/integration/user/delete_user_spec.js @@ -1,7 +1,7 @@ import data from '../../../shared/testing/data'; const user = data.users[0]; -describe('can view delete controls in settings', () => { +describe.skip('can view delete controls in settings', () => { beforeEach(() => { cy.auth(user.id); cy.visit(`/users/${user.username}/settings`); diff --git a/docs/operations/banning-users.md b/docs/operations/banning-users.md index d01b7e6296..461d29a998 100644 --- a/docs/operations/banning-users.md +++ b/docs/operations/banning-users.md @@ -10,7 +10,7 @@ Follow these steps to safely ban a user from Spectrum: 1. Find the user in the database 2. Update the user with the following fields: -``` +```js r.db('spectrum') .table('users') .get(ID) @@ -20,8 +20,8 @@ r.db('spectrum') bannedReason: "Reason for ban here" }) ``` -4. Remove that user as a member from all communities and channels: -``` +3. Remove that user as a member from all communities and channels: +```js // usersCommunities .table('usersCommunities') .getAll(ID, { index: 'userId' }) @@ -42,8 +42,8 @@ r.db('spectrum') receiveNotifications: false, }) ``` -5. Remove all notifications from threads to save worker processing: -``` +4. Remove all notifications from threads to save worker processing: +```js // usersThreads .table('usersThreads') .getAll(ID, { index: 'userId' }) @@ -51,4 +51,34 @@ r.db('spectrum') receiveNotifications: false, }) ``` +5. Reset the person's notification settings so they will not get any future emails about DMs, daily digests, etc +```js +// usersSettings +.table('usersSettings') +.getAll(ID, { index: 'userId' }) +.update({ + notifications: { + types: { + dailyDigest: { + email: false + }, + newDirectMessage: { + email: false + }, + newMention: { + email: false + }, + newMessageInThreads: { + email: false + }, + newThreadCreated: { + email: false + }, + weeklyDigest: { + email: false + } + } + } +}) +``` 6. Done! The user now can't be messaged, searched for, or re-logged into. The banned user no longer affects community or channel member counts, and will not ever get pulled into Athena for notifications processing. \ No newline at end of file diff --git a/hermes/package.json b/hermes/package.json index 9d80f41bb7..78ed2df881 100644 --- a/hermes/package.json +++ b/hermes/package.json @@ -5,13 +5,15 @@ "dependencies": { "bull": "3.3.10", "debug": "^2.6.8", + "draft-js": "^0.10.5", "jsonwebtoken": "^8.0.1", "node-env-file": "^0.1.8", "now-env": "^3.0.2", "postmark": "^1.3.1", "raven": "^2.1.1", "rethinkdbdash": "^2.3.29", - "source-map-support": "^0.4.15" + "source-map-support": "^0.4.15", + "toobusy-js": "^0.5.1" }, "devDependencies": { "json-stringify-pretty-compact": "^1.0.4" diff --git a/hermes/queues/send-community-invite-email.js b/hermes/queues/send-community-invite-email.js index 3ac6afcbc1..e43cc4766c 100644 --- a/hermes/queues/send-community-invite-email.js +++ b/hermes/queues/send-community-invite-email.js @@ -1,5 +1,5 @@ // @flow -const debug = require('debug')('hermes:queue:send-new-message-email'); +const debug = require('debug')('hermes:queue:send-community-invite-email'); import Raven from 'shared/raven'; import sendEmail from '../send-email'; import { diff --git a/hermes/queues/send-mention-message-email.js b/hermes/queues/send-mention-message-email.js index 538f675ad1..cf3935b0d5 100644 --- a/hermes/queues/send-mention-message-email.js +++ b/hermes/queues/send-mention-message-email.js @@ -1,5 +1,5 @@ // @flow -const debug = require('debug')('hermes:queue:send-new-direct-message-email'); +const debug = require('debug')('hermes:queue:send-mention-message-email'); import Raven from 'shared/raven'; import sendEmail from '../send-email'; import { generateUnsubscribeToken } from '../utils/generate-jwt'; diff --git a/hermes/yarn.lock b/hermes/yarn.lock index 8a40cd66ac..5c5dc86e9f 100644 --- a/hermes/yarn.lock +++ b/hermes/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + base64url@2.0.0, base64url@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" @@ -34,6 +38,10 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + cron-parser@^2.4.1: version "2.4.3" resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.4.3.tgz#cae844c20117fc72c678f63ac83c7884be199e78" @@ -68,6 +76,14 @@ denque@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/denque/-/denque-1.1.1.tgz#10229c2b88eec1bd15ff82c5fde356e7beb6db9e" +draft-js@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/draft-js/-/draft-js-0.10.5.tgz#bfa9beb018fe0533dbb08d6675c371a6b08fa742" + dependencies: + fbjs "^0.8.15" + immutable "~3.7.4" + object-assign "^4.1.0" + ecdsa-sig-formatter@1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1" @@ -75,6 +91,24 @@ ecdsa-sig-formatter@1.0.9: base64url "^2.0.0" safe-buffer "^5.0.1" +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +fbjs@^0.8.15: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + flexbuffer@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/flexbuffer/-/flexbuffer-0.0.6.tgz#039fdf23f8823e440c38f3277e6fef1174215b30" @@ -87,6 +121,16 @@ git-rev@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/git-rev/-/git-rev-0.2.1.tgz#8ccbd2092b345bc2c9149548396df549646ca63f" +iconv-lite@~0.4.13: + version "0.4.21" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" + dependencies: + safer-buffer "^2.1.0" + +immutable@~3.7.4: + version "3.7.6" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" + ioredis@^3.1.4: version "3.2.2" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-3.2.2.tgz#b7d5ff3afd77bb9718bb2821329b894b9a44c00b" @@ -121,6 +165,21 @@ is-nan@^1.2.1: dependencies: define-properties "^1.1.1" +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +js-tokens@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + json-stringify-pretty-compact@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-1.0.4.tgz#d5161131be27fd9748391360597fcca250c6c5ce" @@ -257,6 +316,12 @@ lodash@^4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + lsmod@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lsmod/-/lsmod-1.0.0.tgz#9a00f76dca36eb23fa05350afe1b585d4299e64b" @@ -283,10 +348,21 @@ node-env-file@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/node-env-file/-/node-env-file-0.1.8.tgz#fccb7b050f735b5a33da9eb937cf6f1ab457fb69" +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + now-env@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/now-env/-/now-env-3.0.2.tgz#b0725023a799240c5c7e4a43515eb0a65c2c3663" +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" @@ -298,6 +374,12 @@ postmark@^1.3.1: git-rev "0.2.1" merge "1.2.0" +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + dependencies: + asap "~2.0.3" + raven@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/raven/-/raven-2.1.1.tgz#b3a974c6c29315c677c079e168435ead196525cd" @@ -327,10 +409,18 @@ safe-buffer@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" +safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + semver@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + source-map-support@^0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" @@ -349,6 +439,14 @@ timed-out@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" +toobusy-js@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/toobusy-js/-/toobusy-js-0.5.1.tgz#5511f78f6a87a6a512d44fdb0efa13672217f659" + +ua-parser-js@^0.7.9: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + uuid@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" @@ -357,6 +455,10 @@ uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" +whatwg-fetch@>=0.10.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" diff --git a/hyperion/index.js b/hyperion/index.js index 286a0b515b..7099f30f4f 100644 --- a/hyperion/index.js +++ b/hyperion/index.js @@ -1,6 +1,6 @@ // @flow -console.log('Hyperion starting...'); const debug = require('debug')('hyperion'); +debug('Hyperion starting...'); debug('logging with debug enabled'); // $FlowFixMe require('isomorphic-fetch'); @@ -10,6 +10,7 @@ import path from 'path'; import { getUser } from 'api/models/user'; import Raven from 'shared/raven'; import toobusy from 'shared/middlewares/toobusy'; +import addSecurityMiddleware from 'shared/middlewares/security'; const PORT = process.env.PORT || 3006; @@ -20,6 +21,9 @@ app.set('trust proxy', true); app.use(toobusy); +// Security middleware. +addSecurityMiddleware(app); + if (process.env.NODE_ENV === 'development') { const logging = require('shared/middlewares/logging'); app.use(logging); @@ -144,7 +148,7 @@ process.on('uncaughtException', async err => { Loadable.preloadAll().then(() => { app.listen(PORT); - console.log( + debug( `Hyperion, the server-side renderer, running at http://localhost:${PORT}` ); }); diff --git a/mercury/package.json b/mercury/package.json index be4b1aadf3..e9e40bf718 100644 --- a/mercury/package.json +++ b/mercury/package.json @@ -5,9 +5,11 @@ "dependencies": { "bull": "^3.3.10", "debug": "^2.6.8", + "now-env": "^3.0.4", "raven": "^2.1.1", "rethinkdbdash": "^2.3.29", - "source-map-support": "^0.4.15" + "source-map-support": "^0.4.15", + "toobusy-js": "^0.5.1" }, "devDependencies": { "json-stringify-pretty-compact": "^1.0.4" diff --git a/mercury/yarn.lock b/mercury/yarn.lock index 8f1d08a7e9..c077fce3ad 100644 --- a/mercury/yarn.lock +++ b/mercury/yarn.lock @@ -202,6 +202,10 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +now-env@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/now-env/-/now-env-3.0.4.tgz#f9ed88884bff8d208ad3eaf39cc3437dd1a591ad" + object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" @@ -252,6 +256,10 @@ timed-out@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" +toobusy-js@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/toobusy-js/-/toobusy-js-0.5.1.tgz#5511f78f6a87a6a512d44fdb0efa13672217f659" + uuid@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" diff --git a/mobile/app.json b/mobile/app.json index bf7d986677..c0935c18d4 100644 --- a/mobile/app.json +++ b/mobile/app.json @@ -3,7 +3,7 @@ "name": "spectrum", "slug": "spectrum", "privacy": "unlisted", - "sdkVersion": "25.0.0", + "sdkVersion": "26.0.0", "platforms": ["ios", "android"], "version": "1.0.0", "orientation": "portrait", diff --git a/mobile/components/Avatar/image.js b/mobile/components/Avatar/image.js deleted file mode 100644 index 0b3ecc3dbb..0000000000 --- a/mobile/components/Avatar/image.js +++ /dev/null @@ -1,191 +0,0 @@ -// @flow -import * as React from 'react'; -import { Img, ImgPlaceholder } from './style'; - -type Props = { - loader: any, - unloader: any, - decode: boolean, - src: any, -}; - -type State = { - currentIndex?: number, - isLoading: boolean, - isLoaded: boolean, -}; - -const cache = {}; - -class AvatarImage extends React.Component { - sourceList: any; - i: any; - - static defaultProps = { - loader: false, - unloader: false, - decode: true, - src: [], - }; - - constructor(props: Props) { - super(props); - - this.sourceList = this.srcToArray(this.props.src); - - // check cache to decide at which index to start - for (let i = 0; i < this.sourceList.length; i++) { - // if we've never seen this image before, the cache wont help. - // no need to look further, just start loading - /* istanbul ignore else */ - if (!(this.sourceList[i] in cache)) break; - - // if we have loaded this image before, just load it again - /* istanbul ignore else */ - if (cache[this.sourceList[i]] === true) { - this.state = { currentIndex: i, isLoading: false, isLoaded: true }; - return true; - } - } - - this.state = this.sourceList.length - ? // 'normal' opperation: start at 0 and try to load - { currentIndex: 0, isLoading: true, isLoaded: false } - : // if we dont have any sources, jump directly to unloaded - { isLoading: false, isLoaded: false }; - } - - srcToArray = (src: any) => (Array.isArray(src) ? src : [src]).filter(x => x); - - onLoad = () => { - cache[this.sourceList[this.state.currentIndex]] = true; - /* istanbul ignore else */ - if (this.i) this.setState({ isLoaded: true }); - }; - - onError = () => { - cache[this.sourceList[this.state.currentIndex]] = false; - // if the current image has already been destroyed, we are probably no longer mounted - // no need to do anything then - /* istanbul ignore else */ - if (!this.i) return false; - - // before loading the next image, check to see if it was ever loaded in the past - for ( - var nextIndex = this.state.currentIndex + 1; - nextIndex < this.sourceList.length; - nextIndex++ - ) { - // get next img - let src = this.sourceList[nextIndex]; - - // if we have never seen it, its the one we want to try next - if (!(src in cache)) { - this.setState({ currentIndex: nextIndex }); - break; - } - - // if we know it exists, use it! - if (cache[src] === true) { - this.setState({ - currentIndex: nextIndex, - isLoading: false, - isLoaded: true, - }); - return true; - } - - // if we know it doesn't exist, skip it! - /* istanbul ignore else */ - if (cache[src] === false) continue; - } - - // currentIndex is zero bases, length is 1 based. - // if we have no more sources to try, return - we are done - if (nextIndex === this.sourceList.length) - return this.setState({ isLoading: false }); - - // otherwise, try the next img - this.loadImg(); - }; - - loadImg = () => { - this.i = new Image(); - this.i.src = this.sourceList[this.state.currentIndex]; - - if (this.props.decode && this.i.decode) { - // $FlowFixMe - this.i - .decode() - .then(this.onLoad) - .catch(this.onError); - } else { - this.i.onload = this.onLoad; - } - - this.i.onerror = this.onError; - }; - - unloadImg = () => { - try { - delete this.i.onerror; - delete this.i.onload; - delete this.i.src; - delete this.i; - } catch (err) { - console.log(err); - delete this.i; - } - }; - - componentDidMount() { - // kick off process - /* istanbul ignore else */ - if (this.state.isLoading) this.loadImg(); - } - - componentWillUnmount() { - // ensure that we dont leave any lingering listeners - /* istanbul ignore else */ - if (this.i) this.unloadImg(); - } - - componentWillReceiveProps(nextProps: Props) { - let src = this.srcToArray(nextProps.src); - - let srcAdded = src.filter(s => this.sourceList.indexOf(s) === -1); - let srcRemoved = this.sourceList.filter(s => src.indexOf(s) === -1); - - // if src prop changed, restart the loading process - if (srcAdded.length || srcRemoved.length) { - this.sourceList = src; - - // if we dont have any sources, jump directly to unloader - if (!src.length) - return this.setState({ isLoading: false, isLoaded: false }); - this.setState( - { currentIndex: 0, isLoading: true, isLoaded: false }, - this.loadImg - ); - } - } - - render() { - // if we have loaded, show img - if (this.state.isLoaded) { - // clear non img props - let { src, loader, unloader, decode, ...rest } = this.props; //eslint-disable-line - return ; - } - - // if we are still trying to load, show img and a loader if requested - if (!this.state.isLoaded && this.state.isLoading) return ; - - // if we have given up on loading, show a place holder if requested, or nothing - /* istanbul ignore else */ - if (!this.state.isLoaded && !this.state.isLoading) - return this.props.unloader ? this.props.unloader : null; - } -} - -export default AvatarImage; diff --git a/mobile/components/Avatar/img/default_avatar.svg b/mobile/components/Avatar/img/default_avatar.svg deleted file mode 100644 index 12584728fd..0000000000 --- a/mobile/components/Avatar/img/default_avatar.svg +++ /dev/null @@ -1,73 +0,0 @@ - -default_avatar -Created using Figma - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mobile/components/Avatar/img/default_community.svg b/mobile/components/Avatar/img/default_community.svg deleted file mode 100644 index e7379f2083..0000000000 --- a/mobile/components/Avatar/img/default_community.svg +++ /dev/null @@ -1,34 +0,0 @@ - -default_community -Created using Figma - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mobile/components/Avatar/index.js b/mobile/components/Avatar/index.js index a6a85a91cd..4d7c9aac3a 100644 --- a/mobile/components/Avatar/index.js +++ b/mobile/components/Avatar/index.js @@ -1,44 +1,18 @@ // @flow import React, { Component } from 'react'; -import { optimize } from './utils'; -import AvatarImage from './image'; -import { Status } from './style'; +import { AvatarImage } from './style'; type AvatarProps = { src: string, - community?: any, - user?: any, size: number, - link?: ?string, - noLink?: boolean, + radius: number, }; export default class Avatar extends Component { render() { - const { src, community, user, size } = this.props; + const { src, size, radius } = this.props; + let source = src ? { uri: src } : {}; - // $FlowFixMe - const optimizedAvatar = optimize(src, { - w: size, - dpr: '2', - format: 'png', - }); - - const communityFallback = './img/default_community.svg'; - const userFallback = './img/default_avatar.svg'; - - let source; - - if (community && !user) { - source = [optimizedAvatar, communityFallback]; - } else { - source = [optimizedAvatar, userFallback]; - } - - return ( - - - - ); + return ; } } diff --git a/mobile/components/Avatar/style.js b/mobile/components/Avatar/style.js index 9cd737a489..3361d7cad5 100644 --- a/mobile/components/Avatar/style.js +++ b/mobile/components/Avatar/style.js @@ -1,48 +1,9 @@ import styled from 'styled-components/native'; -export const Status = styled.View` - position: relative; - flex-wrap: 'wrap'; - align-items: 'flex-start'; - flex-direction: 'row'; - width: ${props => (props.size ? `${props.size}px` : '32px')}; - height: ${props => (props.size ? `${props.size}px` : '32px')}; - border-radius: ${props => (props.community ? `25%` : '100%')}; - background-color: ${({ theme }) => theme.bg.default}; - - &:after { - content: ''; - position: absolute; - display: ${props => (props.isOnline ? 'inline-block' : 'none')}; - width: ${props => (props.onlineSize === 'large' ? '8px' : '6px')}; - height: ${props => (props.onlineSize === 'large' ? '8px' : '6px')}; - background: ${props => props.theme.success.alt}; - border-radius: 100%; - border: 2px solid ${props => props.theme.text.reverse}; - bottom: ${props => - props.onlineSize === 'large' - ? '0' - : props.onlineSize === 'small' ? '-1px' : '1px'}; - right: ${props => - props.onlineSize === 'large' - ? '0' - : props.onlineSize === 'small' ? '-6px' : '-3px'}; - } -`; - -export const Img = styled.Image` - display: inline-block; - width: ${props => (props.size ? `${props.size}px` : '32px')}; - height: ${props => (props.size ? `${props.size}px` : '32px')}; - border-radius: ${props => (props.community ? `25%` : '100%')}; - object-fit: cover; -`; - -export const ImgPlaceholder = styled.View` - display: inline-block; +export const AvatarImage = styled.Image` background-color: ${props => props.theme.bg.border}; - width: ${props => (props.size ? `${props.size}px` : '32px')}; - height: ${props => (props.size ? `${props.size}px` : '32px')}; - border-radius: ${props => (props.community ? `25%` : '100%')}; - object-fit: cover; + width: ${props => (props.size ? `${props.size}px` : '30px')}; + height: ${props => (props.size ? `${props.size}px` : '30px')}; + border-radius: ${props => (props.radius ? `${props.radius}px` : '15px')}; + margin-right: 5px; `; diff --git a/mobile/components/Avatar/utils.js b/mobile/components/Avatar/utils.js deleted file mode 100644 index 24c4d9a015..0000000000 --- a/mobile/components/Avatar/utils.js +++ /dev/null @@ -1,24 +0,0 @@ -// @flow -type QueryParams = { - [key: string]: string, -}; - -/** - * Optimize an image - */ -export const optimize = (src: string, params?: QueryParams = {}): string => { - if (src.indexOf('spectrum.imgix.net') < 0) return src; - const queryparams = Object.keys(params).reduce((string, key) => { - return `${string}&${key}=${params[key]}`; - }, ''); - return `${src}?auto=compress${queryparams}`; -}; - -export const FREE_USER_MAX_IMAGE_SIZE_BYTES = 3000000; -export const PRO_USER_MAX_IMAGE_SIZE_BYTES = 25000000; -export const FREE_USER_MAX_IMAGE_SIZE_STRING = `${Math.floor( - FREE_USER_MAX_IMAGE_SIZE_BYTES / 1000000 -)}mb`; -export const PRO_USER_MAX_IMAGE_SIZE_STRING = `${Math.floor( - PRO_USER_MAX_IMAGE_SIZE_BYTES / 1000000 -)}mb`; diff --git a/mobile/components/ThreadFeed/index.js b/mobile/components/ThreadFeed/index.js index 9feb16afd0..5031c4e2b3 100644 --- a/mobile/components/ThreadFeed/index.js +++ b/mobile/components/ThreadFeed/index.js @@ -16,6 +16,8 @@ import type { ThreadConnectionType } from '../../../shared/graphql/fragments/com See 'gql/community/communityThreads.js' for an example of the prop mapping in action */ +import { CenteredView } from './style'; + type State = { subscription: ?Function, }; @@ -109,7 +111,7 @@ class ThreadFeed extends React.Component { if (threadConnection && threadConnection.edges.length > 0) { return ( - + ( @@ -125,24 +127,24 @@ class ThreadFeed extends React.Component { if (isLoading) { return ( - + Loading... - + ); } if (hasError) { return ( - + Error! - + ); } return ( - + Nothing here yet! - + ); } } diff --git a/mobile/components/ThreadFeed/style.js b/mobile/components/ThreadFeed/style.js index e69de29bb2..305c2e82b6 100644 --- a/mobile/components/ThreadFeed/style.js +++ b/mobile/components/ThreadFeed/style.js @@ -0,0 +1,8 @@ +// @flow +import styled from 'styled-components/native'; + +export const CenteredView = styled.View` + flex: 1; + align-items: center; + justify-content: center; +`; diff --git a/mobile/components/ThreadItem/Facepile.js b/mobile/components/ThreadItem/Facepile.js index bdbaabc8b3..80db643e2d 100644 --- a/mobile/components/ThreadItem/Facepile.js +++ b/mobile/components/ThreadItem/Facepile.js @@ -1,11 +1,8 @@ // @flow import * as React from 'react'; import Avatar from '../Avatar'; -import { - FacepileContainer, - ParticipantHead, - EmptyParticipantHead, -} from './style'; +import type { UserInfoType } from '../../../shared/graphql/fragments/user/userInfo'; +import { FacepileContainer, EmptyParticipantHead } from './style'; const NUM_TO_DISPLAY = 5; const messageAvatars = list => { @@ -15,58 +12,20 @@ const messageAvatars = list => { if (!participant) { return null; } - - return ( - - - - ); + return ; }); }; -type UserType = { - profilePhoto: string, - username: string, - name: string, - id: string, -}; type FacepileProps = { - participants: Array, - creator: UserType, + participants: Array, + creator: UserInfoType, }; const Facepile = ({ participants, creator }: FacepileProps) => { if (!participants || participants.length === 0) { return ( - - - + ; ); } @@ -84,25 +43,10 @@ const Facepile = ({ participants, creator }: FacepileProps) => { return ( - - - + {messageAvatars(participantList)} {hasOverflow && ( - + {overflowAmount} )} diff --git a/mobile/components/ThreadItem/index.js b/mobile/components/ThreadItem/index.js index 0ab0bef0b9..1d21547c5f 100644 --- a/mobile/components/ThreadItem/index.js +++ b/mobile/components/ThreadItem/index.js @@ -3,7 +3,7 @@ import * as React from 'react'; import { TouchableHighlight, Image, View } from 'react-native'; import { withNavigation } from 'react-navigation'; import compose from 'recompose/compose'; -// import Facepile from './Facepile' +import Facepile from './Facepile'; import ThreadCommunityInfo from './ThreadCommunityInfo'; import Text from '../Text'; import { @@ -38,14 +38,20 @@ class ThreadItem extends React.Component { > - + @@ -55,10 +61,10 @@ class ThreadItem extends React.Component { {thread.content.title} - {/**/} + creator={thread.author.user} + /> {thread.messageCount > 0 ? ( @@ -67,9 +73,11 @@ class ThreadItem extends React.Component { : `${thread.messageCount} message`} ) : ( - - New thread! - + + + {'New thread!'.toUpperCase()} + + )} diff --git a/mobile/components/ThreadItem/style.js b/mobile/components/ThreadItem/style.js index 814bbf5af4..6d9505eb92 100644 --- a/mobile/components/ThreadItem/style.js +++ b/mobile/components/ThreadItem/style.js @@ -25,64 +25,39 @@ export const ThreadTitle = styled.Text` export const ThreadMeta = styled.View` display: flex; + flex-direction: row; justify-content: space-between; + margin-top: 15px; `; export const MetaText = styled.Text` font-size: 14px; color: ${props => (props.new ? props.theme.warn.alt : props.theme.text.alt)}; font-weight: ${props => (props.new ? 600 : 400)}; - position: relative; `; export const MetaTextPill = styled(MetaText)` color: ${props => props.theme.text.reverse}; - background: ${props => props.theme.warn.alt}; - border-radius: 20px; - padding: 0 12px; - font-size: 11px; - font-weight: 700; - display: flex; - align-items: center; + background: ${props => props.theme.success.alt}; + border-radius: 10px; + font-size: 12px; + padding: 3px 10px 3px 10px; + overflow: hidden; `; export const FacepileContainer = styled.View` display: flex; - margin-right: 8px; - margin-left: 8px; -`; - -export const ParticipantHead = styled.View` - position: relative; - margin-left: -8px; - border-radius: 24px; - max-width: 24px; - max-height: 24px; - shadowColor: ${props => props.theme.bg.default}; - shadowOffset: { width: 0, height: 0 }; - shadowOpacity: 1; - shadowRadius: 2; - transform: translateY(0); + flex-direction: row; `; -export const EmptyParticipantHead = styled.View` +export const EmptyParticipantHead = styled.Text` + color: ${props => props.theme.text.alt}; background: ${props => props.theme.bg.wash}; - display: flex; - align-items: center; - justify-content: center; - font-size: 11px; + border-radius: 15px; + text-align: center; + text-align-vertical: center; + font-size: 12px; font-weight: 600; - color: ${props => props.theme.text.alt}; - shadowColor: ${props => props.theme.bg.default}; - shadowOffset: { width: 0, height: 0 }; - shadowOpacity: 1; - shadowRadius: 2; - width: 24px; - height: 24px; - max-width: 24px; - max-height: 24px; - position: relative; - margin-left: -8px; - border-radius: 24px; - transform: translateY(0); + width: 30px; + overflow: hidden; `; diff --git a/mobile/package.json b/mobile/package.json index 87daff8ef8..eb0a78889e 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -8,15 +8,15 @@ "apollo-link-error": "^1.0.3", "apollo-link-http": "^1.3.2", "apollo-link-retry": "^2.1.2", - "expo": "^25.0.0", + "expo": "^26.0.0", "graphql": "^0.11.0", "graphql-tag": "^2.6.1", "metro-bundler": "^0.22.1", - "react": "16.2.0", + "react": "16.3.0-alpha.1", "react-apollo": "^2.0.4", - "react-native": "https://github.com/expo/react-native/archive/sdk-25.0.0.tar.gz", + "react-native": "https://github.com/expo/react-native/archive/sdk-26.0.0.tar.gz", "react-native-typography": "^1.2.1", - "react-navigation": "^1.0.0-beta.27", + "react-navigation": "^1.5.8", "react-navigation-props-mapper": "^0.1.2", "recompose": "^0.26.0", "redraft": "^0.10.0", @@ -27,9 +27,9 @@ "cross-env": "^5.1.1", "detox": "^6.0.0", "detox-expo-helpers": "^0.2.0", - "exp": "^47.1.2", + "exp": "^52.0.0", "jest": "^22.0.3", - "jest-expo": "^25.1.0", + "jest-expo": "^26.0.0", "react-test-renderer": "^16.2.0" }, "scripts": { diff --git a/mobile/views/Splash/index.js b/mobile/views/Splash/index.js index cf0da65289..9424bdf2da 100644 --- a/mobile/views/Splash/index.js +++ b/mobile/views/Splash/index.js @@ -38,7 +38,7 @@ class Splash extends React.Component { const { authentication } = this.props; return ( - + {!authentication.token ? : } diff --git a/mobile/views/Splash/style.js b/mobile/views/Splash/style.js index 1fe12d833f..f2c3081388 100644 --- a/mobile/views/Splash/style.js +++ b/mobile/views/Splash/style.js @@ -4,6 +4,4 @@ import styled from 'styled-components/native'; export const Wrapper = styled.View` background-color: ${props => props.theme.bg.default}; flex: 1; - align-items: center; - justify-content: center; `; diff --git a/mobile/yarn.lock b/mobile/yarn.lock index 1a8524b238..acfbd8d4e8 100644 --- a/mobile/yarn.lock +++ b/mobile/yarn.lock @@ -2,6 +2,12 @@ # yarn lockfile v1 +"@babel/code-frame@7.0.0-beta.44", "@babel/code-frame@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + "@babel/code-frame@^7.0.0-beta.35": version "7.0.0-beta.38" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.38.tgz#c0af5930617e55e050336838e3a3670983b0b2b2" @@ -10,6 +16,390 @@ esutils "^2.0.2" js-tokens "^3.0.0" +"@babel/core@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.44.tgz#90bb9e897427e7ebec2a1b857f458ff74ca28057" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helpers" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + convert-source-map "^1.1.0" + debug "^3.1.0" + json5 "^0.5.0" + lodash "^4.2.0" + micromatch "^2.3.11" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@7.0.0-beta.44", "@babel/generator@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-annotate-as-pure@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0-beta.44.tgz#8ecf33cc5235295afcc7f160a63cab17ce7776f4" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-builder-react-jsx@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.0.0-beta.44.tgz#52a4fd63ce92df425a4fb550c7a1a3ca30e0f234" + dependencies: + "@babel/types" "7.0.0-beta.44" + esutils "^2.0.0" + +"@babel/helper-call-delegate@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.0.0-beta.44.tgz#e644536f8b3d2eabeecca000037cdced8e453d26" + dependencies: + "@babel/helper-hoist-variables" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-define-map@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.0.0-beta.44.tgz#d63578a67c9654ff9f32e55bbf269c2d5f094c97" + dependencies: + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-hoist-variables@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0-beta.44.tgz#a1bbb2c25f9b4058e041ecc1556f096eacdbd142" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-module-imports@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.44.tgz#60edc68cdf17e13eaca5be813c96127303085133" + dependencies: + "@babel/types" "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/helper-module-transforms@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.0.0-beta.44.tgz#185dc17b37c4b9cc3daee0f0f44e74f000e21bb7" + dependencies: + "@babel/helper-module-imports" "7.0.0-beta.44" + "@babel/helper-simple-access" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/helper-optimise-call-expression@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0-beta.44.tgz#84ceabfb99afc1c185d15668114a697cdad7a5d0" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-plugin-utils@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0-beta.44.tgz#9f590bc3ae6daa8a10b853233baa3e25d263751d" + +"@babel/helper-remap-async-to-generator@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.0.0-beta.44.tgz#8ad8c12a57444042ca281bdb16734841425938ad" + dependencies: + "@babel/helper-annotate-as-pure" "7.0.0-beta.44" + "@babel/helper-wrap-function" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-replace-supers@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.0.0-beta.44.tgz#cf18697951431f533f9d8c201390b158d4a3ee04" + dependencies: + "@babel/helper-optimise-call-expression" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-simple-access@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.0.0-beta.44.tgz#03fb6bfc91eb0a95f6c11499153f8c663654dce5" + dependencies: + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-wrap-function@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.0.0-beta.44.tgz#d128718a543f313264dff7cb386957e3e465c95d" + dependencies: + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helpers@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.44.tgz#b1cc87fdc3b77351c0a4860bcd9d4ef457919bfd" + dependencies: + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/plugin-check-constants@^7.0.0-beta": + version "7.0.0-beta.38" + resolved "https://registry.yarnpkg.com/@babel/plugin-check-constants/-/plugin-check-constants-7.0.0-beta.38.tgz#bbda6306d45a4f097ccb416c0b52d6503f6502cf" + +"@babel/plugin-external-helpers@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.0.0-beta.44.tgz#9ccdea7ec83623b6e580e17b639d4dfe2fd93828" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-proposal-class-properties@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.0.0-beta.44.tgz#aff9192a883b41fdf1c73026b9105c92e931c55e" + dependencies: + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-class-properties" "7.0.0-beta.44" + +"@babel/plugin-proposal-object-rest-spread@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.44.tgz#b7817770cb9cf72f2e73ca6fcb83d61a87305259" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.44" + +"@babel/plugin-syntax-class-properties@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0-beta.44.tgz#1e4e67ef6d7101a3a7d2ae5f60e580cbf4b7750f" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-syntax-dynamic-import@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.0.0-beta.44.tgz#1a7d009f892bc9799dcb22ace4bd24198eef8992" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-syntax-flow@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.0.0-beta.44.tgz#12498c9c6565e185317fcead2cb2ea6b196ce8c1" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-syntax-jsx@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.0.0-beta.44.tgz#b3475f0e6ea797634f0ba823273d76e93727e52f" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-syntax-object-rest-spread@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.44.tgz#c37d271e4edf8a1b5d4623fb2917ba0f5a9da3b3" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-arrow-functions@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.44.tgz#718dae35046eca6938c731d1eae10c5471c17398" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-block-scoping@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0-beta.44.tgz#a7b640e112743634b9226996e58ab92cdebb4ff0" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/plugin-transform-classes@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.0.0-beta.44.tgz#5410fcf6a9eeba3cc8e25bf0f72b43358336b534" + dependencies: + "@babel/helper-annotate-as-pure" "7.0.0-beta.44" + "@babel/helper-define-map" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-optimise-call-expression" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-replace-supers" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0-beta.44.tgz#1421b4e1a18dc3bd276d8648a12a4f8ea088c6a1" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-destructuring@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0-beta.44.tgz#57c8b40d56db45eaa39b44696818b24004306752" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-flow-strip-types@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.0.0-beta.44.tgz#e7f5028f886f6410d9e5488a4f2fde4a28afe9d8" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-flow" "7.0.0-beta.44" + +"@babel/plugin-transform-for-of@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0-beta.44.tgz#b157e38e74c07beacbac01c1946b8ad11dbea32c" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-function-name@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.0.0-beta.44.tgz#8cd5986dac8a0fd0df21b79e9a20de9b2c37b4c4" + dependencies: + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-literals@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0-beta.44.tgz#8c85631ea6fd8a6eecefdb81177ed6ae3d34b195" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-modules-commonjs@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.0.0-beta.44.tgz#864a1fef64091bd5241b0aa7d4b235fb29f60580" + dependencies: + "@babel/helper-module-transforms" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-simple-access" "7.0.0-beta.44" + +"@babel/plugin-transform-object-assign@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.0.0-beta.44.tgz#96881dd11daf77a0fb71137921650b86b8a0e5bb" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-parameters@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.0.0-beta.44.tgz#19eaf0b852d58168097435e33e754a00c3507fb9" + dependencies: + "@babel/helper-call-delegate" "7.0.0-beta.44" + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-react-display-name@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.0.0-beta.44.tgz#e7937554e209d72804808581c334945af238481d" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-react-jsx-source@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.0.0-beta.44.tgz#629101210cf86fe3cfb89a4278fb8d0966bdfc81" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-jsx" "7.0.0-beta.44" + +"@babel/plugin-transform-react-jsx@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.0.0-beta.44.tgz#656a2582002ff1b0eea4cd01b7c8f6cbbf3990bf" + dependencies: + "@babel/helper-builder-react-jsx" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-jsx" "7.0.0-beta.44" + +"@babel/plugin-transform-regenerator@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0-beta.44.tgz#e9a21db8fbedfd99b9e5d04ac405f7440d36b290" + dependencies: + regenerator-transform "^0.12.3" + +"@babel/plugin-transform-shorthand-properties@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0-beta.44.tgz#42e2a31aaa5edf479adaf4c2b677cd3457c99991" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-spread@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0-beta.44.tgz#94cacc3317cb8e2227b543c25b8046d7635d4114" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/plugin-transform-template-literals@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0-beta.44.tgz#88d4605e63a21a4354837af06371e8c51cd76d08" + dependencies: + "@babel/helper-annotate-as-pure" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + +"@babel/template@7.0.0-beta.44", "@babel/template@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/traverse@7.0.0-beta.44", "@babel/traverse@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.44", "@babel/types@^7.0.0-beta": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + "@expo/bunyan@^1.8.10": version "1.8.10" resolved "https://registry.yarnpkg.com/@expo/bunyan/-/bunyan-1.8.10.tgz#7d19354a6bce85aae5fea0e973569d3f0142533e" @@ -18,7 +408,7 @@ mv "~2" safe-json-stringify "~1" -"@expo/json-file@^5.2.0", "@expo/json-file@^5.3.0": +"@expo/json-file@^5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-5.3.0.tgz#9274fd22e68cfdcae1f06aed8d2d1f953a4f7168" dependencies: @@ -26,12 +416,82 @@ lodash "^4.6.1" mz "^2.6.0" -"@expo/ngrok@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@expo/ngrok/-/ngrok-2.3.0.tgz#e6c37c74c2ede6c32f04b13d30383e10255908d3" +"@expo/json-file@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.0.0.tgz#5c3cb84469b1229e6c4aac9a4285fca59e6709fd" dependencies: + "@babel/code-frame" "^7.0.0-beta.44" + json5 "^1.0.1" + lodash "^4.17.4" + util.promisify "^1.0.0" + write-file-atomic "^2.3.0" + +"@expo/ngrok-bin-darwin-ia32@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-darwin-ia32/-/ngrok-bin-darwin-ia32-2.2.8.tgz#46ed6d485a87396acf4af317beeaab7a1f607315" + +"@expo/ngrok-bin-darwin-x64@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-darwin-x64/-/ngrok-bin-darwin-x64-2.2.8.tgz#bf32ece32c3a1c6dcbe518ee88e6c2af3ad8764a" + +"@expo/ngrok-bin-freebsd-ia32@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-freebsd-ia32/-/ngrok-bin-freebsd-ia32-2.2.8.tgz#7b198757f6bb6602a4c2bc5384b4ddb4d272eca5" + +"@expo/ngrok-bin-freebsd-x64@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-freebsd-x64/-/ngrok-bin-freebsd-x64-2.2.8.tgz#3d510c3196087e17747d5e34b765cca1e3279f36" + +"@expo/ngrok-bin-linux-arm64@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-linux-arm64/-/ngrok-bin-linux-arm64-2.2.8.tgz#3829665093c7921c8b73e26c7c262493a93d53b4" + +"@expo/ngrok-bin-linux-arm@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-linux-arm/-/ngrok-bin-linux-arm-2.2.8.tgz#1e64ca1a0856daea5fd752b56d394f083079f195" + +"@expo/ngrok-bin-linux-ia32@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-linux-ia32/-/ngrok-bin-linux-ia32-2.2.8.tgz#dcd8be0a894ba8969548e113a3cd16e7e6fe912b" + +"@expo/ngrok-bin-linux-x64@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-linux-x64/-/ngrok-bin-linux-x64-2.2.8.tgz#517119cb9aa0b74e678d953878910500b6f7f6ec" + +"@expo/ngrok-bin-sunos-x64@2.2.8": + version "2.2.8" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-sunos-x64/-/ngrok-bin-sunos-x64-2.2.8.tgz#66ebd87786b94836ba5636b22e386b81d4e7da32" + +"@expo/ngrok-bin-win32-ia32@2.2.8-beta.1": + version "2.2.8-beta.1" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-win32-ia32/-/ngrok-bin-win32-ia32-2.2.8-beta.1.tgz#c68e530b3c1c96a548d0926fb93e45e2980acd59" + +"@expo/ngrok-bin-win32-x64@2.2.8-beta.1": + version "2.2.8-beta.1" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin-win32-x64/-/ngrok-bin-win32-x64-2.2.8-beta.1.tgz#598d74968ef6d0c15f00df1a41d0df2a40562f23" + +"@expo/ngrok-bin@2.2.8-beta.3": + version "2.2.8-beta.3" + resolved "https://registry.yarnpkg.com/@expo/ngrok-bin/-/ngrok-bin-2.2.8-beta.3.tgz#22b5fadf0a0de91adbcc62a9a3c86402fe74e672" + optionalDependencies: + "@expo/ngrok-bin-darwin-ia32" "2.2.8" + "@expo/ngrok-bin-darwin-x64" "2.2.8" + "@expo/ngrok-bin-freebsd-ia32" "2.2.8" + "@expo/ngrok-bin-freebsd-x64" "2.2.8" + "@expo/ngrok-bin-linux-arm" "2.2.8" + "@expo/ngrok-bin-linux-arm64" "2.2.8" + "@expo/ngrok-bin-linux-ia32" "2.2.8" + "@expo/ngrok-bin-linux-x64" "2.2.8" + "@expo/ngrok-bin-sunos-x64" "2.2.8" + "@expo/ngrok-bin-win32-ia32" "2.2.8-beta.1" + "@expo/ngrok-bin-win32-x64" "2.2.8-beta.1" + +"@expo/ngrok@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@expo/ngrok/-/ngrok-2.4.2.tgz#cb304ca49913b8bc23550407fb4f8b25f3e76a9a" + dependencies: + "@expo/ngrok-bin" "2.2.8-beta.3" async "^0.9.0" - decompress-zip "^0.3.0" lock "^0.1.2" logfmt "^1.2.0" request "^2.81.0" @@ -77,26 +537,26 @@ version "1.0.2" resolved "https://registry.yarnpkg.com/@expo/simple-spinner/-/simple-spinner-1.0.2.tgz#b31447de60e5102837a4edf702839fcc8f7f31f3" -"@expo/spawn-async@^1.2.8": +"@expo/spawn-async@^1.2.8", "@expo/spawn-async@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.3.0.tgz#01b8a4f6bba10b792663f9272df66c7e90166dad" dependencies: cross-spawn "^5.1.0" -"@expo/traveling-fastlane-darwin@1.2.5": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@expo/traveling-fastlane-darwin/-/traveling-fastlane-darwin-1.2.5.tgz#45c7d71bfb2227599856cb319b7ac50b6cd7e4d0" +"@expo/traveling-fastlane-darwin@1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@expo/traveling-fastlane-darwin/-/traveling-fastlane-darwin-1.4.7.tgz#f18fce83159ee6f554cd0dcb4cda2fb324887478" -"@expo/traveling-fastlane-linux@1.2.5": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@expo/traveling-fastlane-linux/-/traveling-fastlane-linux-1.2.5.tgz#32f4c3636c84faef53989a052cab32f783d9129b" +"@expo/traveling-fastlane-linux@1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@expo/traveling-fastlane-linux/-/traveling-fastlane-linux-1.4.7.tgz#c5ea23ff36789e8b3c72e9eb381235a703dc1717" -"@expo/vector-icons@^6.2.0": - version "6.2.2" - resolved "https://registry.yarnpkg.com/@expo/vector-icons/-/vector-icons-6.2.2.tgz#441edb58a52c0f4e5b4aba1e6f8da1e87cea7e11" +"@expo/vector-icons@^6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@expo/vector-icons/-/vector-icons-6.3.1.tgz#ffb97cc2343e4a330b44ce3063ee7c8571a6a50d" dependencies: lodash "^4.17.4" - react-native-vector-icons "4.4.2" + react-native-vector-icons "4.5.0" "@segment/loosely-validate-event@^1.1.2": version "1.1.2" @@ -143,6 +603,13 @@ accepts@~1.3.0, accepts@~1.3.4: mime-types "~2.1.16" negotiator "0.6.1" +accepts@~1.3.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + acorn-globals@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" @@ -208,10 +675,6 @@ analytics-node@^2.1.0: superagent "^3.5.0" superagent-retry "^0.6.0" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - ansi-escapes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" @@ -465,6 +928,17 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" +auth0-js@9.3.3: + version "9.3.3" + resolved "https://registry.yarnpkg.com/auth0-js/-/auth0-js-9.3.3.tgz#c4573ffefba102171982d4a2044eade73baa1b8d" + dependencies: + base64-js "^1.2.0" + idtoken-verifier "^1.1.2" + qs "^6.4.0" + superagent "^3.8.2" + url-join "^1.1.0" + winchan "^0.2.0" + auth0-js@^7.4.0: version "7.6.1" resolved "https://registry.yarnpkg.com/auth0-js/-/auth0-js-7.6.1.tgz#5baea8603133bb143bd2c327b55a57da7afdf97c" @@ -478,7 +952,7 @@ auth0-js@^7.4.0: winchan "0.1.4" xtend "~2.1.1" -auth0@^2.7.0: +auth0@2.9.1, auth0@^2.7.0: version "2.9.1" resolved "https://registry.yarnpkg.com/auth0/-/auth0-2.9.1.tgz#85e088035f29925ed086da94d811288a65f5835c" dependencies: @@ -501,7 +975,7 @@ aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -axios@^0.16.1: +axios@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d" dependencies: @@ -688,7 +1162,7 @@ babel-plugin-check-es2015-constants@^6.5.0, babel-plugin-check-es2015-constants@ dependencies: babel-runtime "^6.22.0" -babel-plugin-external-helpers@^6.18.0: +babel-plugin-external-helpers@^6.18.0, babel-plugin-external-helpers@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz#2285f48b02bd5dede85175caf8c62e86adccefa1" dependencies: @@ -710,7 +1184,7 @@ babel-plugin-jest-hoist@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.3.tgz#7d8bcccadc2667f96a0dcc6afe1891875ee6c14a" -babel-plugin-module-resolver@^2.7.1: +babel-plugin-module-resolver@^2.3.0, babel-plugin-module-resolver@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-2.7.1.tgz#18be3c42ddf59f7a456c9e0512cd91394f6e4be1" dependencies: @@ -718,6 +1192,12 @@ babel-plugin-module-resolver@^2.7.1: glob "^7.1.1" resolve "^1.2.0" +babel-plugin-react-transform@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-react-transform/-/babel-plugin-react-transform-2.0.2.tgz#515bbfa996893981142d90b1f9b1635de2995109" + dependencies: + lodash "^4.6.1" + babel-plugin-react-transform@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-react-transform/-/babel-plugin-react-transform-3.0.0.tgz#402f25137b7bb66e9b54ead75557dfbc7ecaaa74" @@ -789,13 +1269,6 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-runtime "^6.2.0" babel-template "^6.3.0" -babel-plugin-transform-define@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.0.tgz#94c5f9459c810c738cc7c50cbd44a31829d6f319" - dependencies: - lodash "4.17.4" - traverse "0.6.6" - babel-plugin-transform-es2015-arrow-functions@^6.5.0, babel-plugin-transform-es2015-arrow-functions@^6.8.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" @@ -1093,6 +1566,40 @@ babel-preset-jest@^22.4.3: babel-plugin-jest-hoist "^22.4.3" babel-plugin-syntax-object-rest-spread "^6.13.0" +babel-preset-react-native@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/babel-preset-react-native/-/babel-preset-react-native-1.9.0.tgz#035fc06c65f4f2a02d0336a100b2da142f36dab1" + dependencies: + babel-plugin-check-es2015-constants "^6.5.0" + babel-plugin-react-transform "2.0.2" + babel-plugin-syntax-async-functions "^6.5.0" + babel-plugin-syntax-class-properties "^6.5.0" + babel-plugin-syntax-flow "^6.5.0" + babel-plugin-syntax-jsx "^6.5.0" + babel-plugin-syntax-trailing-function-commas "^6.5.0" + babel-plugin-transform-class-properties "^6.5.0" + babel-plugin-transform-es2015-arrow-functions "^6.5.0" + babel-plugin-transform-es2015-block-scoping "^6.5.0" + babel-plugin-transform-es2015-classes "^6.5.0" + babel-plugin-transform-es2015-computed-properties "^6.5.0" + babel-plugin-transform-es2015-destructuring "^6.5.0" + babel-plugin-transform-es2015-for-of "^6.5.0" + babel-plugin-transform-es2015-function-name "^6.5.0" + babel-plugin-transform-es2015-literals "^6.5.0" + babel-plugin-transform-es2015-modules-commonjs "^6.5.0" + babel-plugin-transform-es2015-parameters "^6.5.0" + babel-plugin-transform-es2015-shorthand-properties "^6.5.0" + babel-plugin-transform-es2015-spread "^6.5.0" + babel-plugin-transform-es2015-template-literals "^6.5.0" + babel-plugin-transform-flow-strip-types "^6.5.0" + babel-plugin-transform-object-assign "^6.5.0" + babel-plugin-transform-object-rest-spread "^6.5.0" + babel-plugin-transform-react-display-name "^6.5.0" + babel-plugin-transform-react-jsx "^6.5.0" + babel-plugin-transform-react-jsx-source "^6.5.0" + babel-plugin-transform-regenerator "^6.5.0" + react-transform-hmr "^1.0.4" + babel-preset-react-native@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/babel-preset-react-native/-/babel-preset-react-native-4.0.0.tgz#3df80dd33a453888cdd33bdb87224d17a5d73959" @@ -1181,6 +1688,10 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26 lodash "^4.17.4" to-fast-properties "^1.0.3" +babylon@7.0.0-beta.44, babylon@^7.0.0-beta: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1205,6 +1716,10 @@ base64-js@^1.0.2, base64-js@^1.1.2: version "1.2.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" +base64-js@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" + base64-url@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/base64-url/-/base64-url-1.2.1.tgz#199fd661702a0e7b7dcae6e0698bb089c52f6d78" @@ -1221,6 +1736,12 @@ basic-auth@~1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" +basic-auth@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + dependencies: + safe-buffer "5.1.1" + batch@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" @@ -1239,13 +1760,6 @@ big-integer@^1.6.7: version "1.6.26" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.26.tgz#3af1672fa62daf2d5ecafacf6e5aa0d25e02c1c8" -binary@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" - dependencies: - buffers "~0.1.1" - chainsaw "~0.1.0" - block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -1377,10 +1891,6 @@ buffer@^5.0.3: base64-js "^1.0.2" ieee754 "^1.1.4" -buffers@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" - builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1435,12 +1945,6 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chainsaw@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" - dependencies: - traverse ">=0.3.0 <0.4" - chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -1508,12 +2012,6 @@ clamp@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/clamp/-/clamp-1.0.1.tgz#66a0e64011816e37196828fdc8c8c147312c8634" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -1635,12 +2133,30 @@ component-type@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" +compressible@~2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" + dependencies: + mime-db ">= 1.33.0 < 2" + compressible@~2.0.5: version "2.0.12" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66" dependencies: mime-db ">= 1.30.0 < 2" +compression@^1.7.1: + version "1.7.2" + resolved "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" + dependencies: + accepts "~1.3.4" + bytes "3.0.0" + compressible "~2.0.13" + debug "2.6.9" + on-headers "~1.0.1" + safe-buffer "5.1.1" + vary "~1.1.2" + compression@~1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/compression/-/compression-1.5.2.tgz#b03b8d86e6f8ad29683cba8df91ddc6ffc77b395" @@ -1656,7 +2172,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.7, concat-stream@^1.6.0: +concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1741,7 +2257,7 @@ content-type@~1.0.1, content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" -convert-source-map@^1.4.0, convert-source-map@^1.5.0: +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" @@ -1790,9 +2306,9 @@ create-error-class@^3.0.0: dependencies: capture-stack-trace "^1.0.0" -create-react-class@^15.5.2: - version "15.6.2" - resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.2.tgz#cf1ed15f12aad7f14ef5f2dfe05e6c42f91ef02a" +create-react-class@^15.6.3: + version "15.6.3" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036" dependencies: fbjs "^0.8.9" loose-envify "^1.3.1" @@ -1832,6 +2348,10 @@ cryptiles@3.x.x: dependencies: boom "5.x.x" +crypto-js@^3.1.9-1: + version "3.1.9-1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.9-1.tgz#fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8" + crypto-token@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/crypto-token/-/crypto-token-1.0.1.tgz#27c6482faf3b63c2f5da11577f8304346fe797a5" @@ -1917,18 +2437,6 @@ decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -decompress-zip@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/decompress-zip/-/decompress-zip-0.3.0.tgz#ae3bcb7e34c65879adfe77e19c30f86602b4bdb0" - dependencies: - binary "^0.3.0" - graceful-fs "^4.1.3" - mkpath "^0.1.0" - nopt "^3.0.1" - q "^1.1.2" - readable-stream "^1.1.8" - touch "0.0.3" - dedent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.6.0.tgz#0e6da8f0ce52838ef5cec5c8f9396b0c1b64a3cb" @@ -1994,7 +2502,7 @@ depd@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.0.1.tgz#80aec64c9d6d97e65cc2a9caa93c0aa6abf73aaa" -depd@~1.1.0, depd@~1.1.1: +depd@~1.1.0, depd@~1.1.1, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -2094,7 +2602,7 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -encodeurl@~1.0.1: +encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -2114,12 +2622,29 @@ envinfo@^3.0.0: os-name "^2.0.1" which "^1.2.14" +envinfo@^3.11.1: + version "3.11.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-3.11.1.tgz#45968faf5079aa797b7dcdc3b123f340d4529e1c" + dependencies: + clipboardy "^1.2.2" + glob "^7.1.2" + minimist "^1.2.0" + os-name "^2.0.1" + which "^1.2.14" + error-ex@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" +errorhandler@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.5.0.tgz#eaba64ca5d542a311ac945f582defc336165d9f4" + dependencies: + accepts "~1.3.3" + escape-html "~1.0.3" + errorhandler@~1.4.2: version "1.4.3" resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.4.3.tgz#b7b70ed8f359e9db88092f2d20c0f831420ad83f" @@ -2198,7 +2723,7 @@ estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -esutils@^2.0.2: +esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2256,34 +2781,33 @@ exists-async@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/exists-async/-/exists-async-2.0.0.tgz#7e0b1652b34b0fe18b9f9640987bd56d59e51e5e" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" -exp@^47.1.2: - version "47.4.4" - resolved "https://registry.yarnpkg.com/exp/-/exp-47.4.4.tgz#2862b827e181f938f6ef6a2fadb742d7c5aa201a" +exp@^52.0.0: + version "52.0.3" + resolved "https://registry.yarnpkg.com/exp/-/exp-52.0.3.tgz#2974521050263de31d233e303367e8c4afb8dde5" dependencies: + "@babel/code-frame" "^7.0.0-beta.44" "@expo/bunyan" "^1.8.10" - "@expo/json-file" "^5.2.0" - "@expo/ngrok" "2.3.0" + "@expo/json-file" "^8.0.0" "@expo/simple-spinner" "^1.0.2" + "@expo/spawn-async" "^1.3.0" babel-runtime "^6.9.2" chalk "^2.0.1" cli-table "^0.3.1" commander "^2.9.0" delay-async "^1.0.0" + envinfo "^3.11.1" es6-error "^3.0.0" fs-extra "^4.0.2" glob "^7.0.3" indent-string "^3.1.0" - inquirer "^2.0.0" + inquirer "^5.0.1" lodash "^4.17.4" - mz "^2.6.0" + match-require "^2.1.0" + mkdirp "^0.5.1" ora "^1.3.0" progress "^2.0.0" qrcode-terminal "^0.11.0" @@ -2291,10 +2815,11 @@ exp@^47.1.2: slash "^1.0.0" source-map-support "^0.4.1" untildify "^3.0.2" - xdl "47.1.4" + wordwrap "^1.0.0" + xdl "49.0.2" optionalDependencies: - "@expo/traveling-fastlane-darwin" "1.2.5" - "@expo/traveling-fastlane-linux" "1.2.5" + "@expo/traveling-fastlane-darwin" "1.4.7" + "@expo/traveling-fastlane-linux" "1.4.7" expand-brackets@^0.1.4: version "0.1.5" @@ -2330,11 +2855,11 @@ expect@^22.4.3: jest-message-util "^22.4.3" jest-regex-util "^22.4.3" -expo@^25.0.0: - version "25.0.0" - resolved "https://registry.yarnpkg.com/expo/-/expo-25.0.0.tgz#791d0052e159d56854a84d90540bf11c33abfe4d" +expo@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/expo/-/expo-26.0.0.tgz#19636fbcf760d284313d6e8cd891ae186baa48be" dependencies: - "@expo/vector-icons" "^6.2.0" + "@expo/vector-icons" "^6.3.1" babel-preset-expo "^4.0.0" fbemitter "^2.1.1" invariant "^2.2.2" @@ -2347,9 +2872,9 @@ expo@^25.0.0: prop-types "^15.6.0" qs "^6.5.0" react-native-branch "2.0.0-beta.3" - react-native-gesture-handler "1.0.0-alpha.39" - react-native-maps "0.19.0" - react-native-svg "https://github.com/expo/react-native-svg/archive/5.5.1-exp.1.tar.gz" + react-native-gesture-handler "1.0.0-alpha.41" + react-native-maps "https://github.com/expo/react-native-maps/archive/0.20.1-exp.0.tar.gz" + react-native-svg "6.2.2" uuid-js "^0.7.5" websql "https://github.com/expo/node-websql/archive/18.0.0.tar.gz" @@ -2406,14 +2931,6 @@ extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -external-editor@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" - dependencies: - extend "^3.0.0" - spawn-sync "^1.0.15" - tmp "^0.0.29" - external-editor@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" @@ -2422,6 +2939,14 @@ external-editor@^2.0.4: iconv-lite "^0.4.17" tmp "^0.0.33" +external-editor@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -2819,6 +3344,10 @@ global@^4.3.0: min-document "^2.19.0" process "~0.5.1" +globals@^11.1.0: + version "11.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.4.0.tgz#b85c793349561c16076a3c13549238a27945f1bc" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -3095,6 +3624,16 @@ iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +idtoken-verifier@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/idtoken-verifier/-/idtoken-verifier-1.2.0.tgz#4654f1f07ab7a803fc9b1b8b36057e2a87ad8b09" + dependencies: + base64-js "^1.2.0" + crypto-js "^3.1.9-1" + jsbn "^0.1.0" + superagent "^3.8.2" + url-join "^1.1.0" + idx@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/idx/-/idx-2.2.0.tgz#8544749f9faba6409822b5d9488ba5bc77b8fbfe" @@ -3141,40 +3680,39 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" -inquirer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" +inquirer@^3.0.6, inquirer@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^1.1.0" + external-editor "^2.0.4" figures "^2.0.0" lodash "^4.3.0" - mute-stream "0.0.6" - pinkie-promise "^2.0.0" + mute-stream "0.0.7" run-async "^2.2.0" - rx "^4.1.0" - string-width "^2.0.0" - strip-ansi "^3.0.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" through "^2.3.6" -inquirer@^3.0.6, inquirer@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" +inquirer@^5.0.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^2.0.4" + external-editor "^2.1.0" figures "^2.0.0" lodash "^4.3.0" mute-stream "0.0.7" run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" + rxjs "^5.5.2" string-width "^2.1.0" strip-ansi "^4.0.0" through "^2.3.6" @@ -3193,6 +3731,12 @@ invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2: dependencies: loose-envify "^1.0.0" +invariant@^2.2.0, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -3614,13 +4158,19 @@ jest-docblock@21.3.0-beta.8: dependencies: detect-newline "^2.1.0" -jest-docblock@22.1.0, jest-docblock@^22.1.0: +jest-docblock@22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.4.0.tgz#dbf1877e2550070cfc4d9b07a55775a0483159b8" + dependencies: + detect-newline "^2.1.0" + +jest-docblock@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.1.0.tgz#3fe5986d5444cbcb149746eb4b07c57c5a464dfd" dependencies: detect-newline "^2.1.0" -jest-docblock@^22.4.3: +jest-docblock@^22.4.0, jest-docblock@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.4.3.tgz#50886f132b42b280c903c592373bb6e93bb68b19" dependencies: @@ -3656,14 +4206,14 @@ jest-environment-node@^22.4.3: jest-mock "^22.4.3" jest-util "^22.4.3" -jest-expo@^25.1.0: - version "25.1.0" - resolved "https://registry.yarnpkg.com/jest-expo/-/jest-expo-25.1.0.tgz#7f91d0c93f3dadaa8f45dab065d06bccd0519a8c" +jest-expo@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-expo/-/jest-expo-26.0.0.tgz#a20f0e2d1ccb445814982e5fdc9bfcddb5c13ee3" dependencies: babel-jest "^22.1.0" - jest "^22.1.1" + jest "^22.2.1" json5 "^0.5.1" - react-test-renderer "16.2.0" + react-test-renderer "^16.3.0-alpha.2" jest-get-type@^22.1.0: version "22.1.0" @@ -3684,7 +4234,19 @@ jest-haste-map@21.3.0-beta.8: micromatch "^2.3.11" sane "^2.0.0" -jest-haste-map@22.1.0, jest-haste-map@^22.1.0: +jest-haste-map@22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.4.2.tgz#a90178e66146d4378bb076345a949071f3b015b4" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + jest-docblock "^22.4.0" + jest-serializer "^22.4.0" + jest-worker "^22.2.2" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-haste-map@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.1.0.tgz#1174c6ff393f9818ebf1163710d8868b5370da2a" dependencies: @@ -3910,7 +4472,7 @@ jest-runtime@^22.4.3: write-file-atomic "^2.1.0" yargs "^10.0.3" -jest-serializer@^22.4.3: +jest-serializer@^22.4.0, jest-serializer@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-22.4.3.tgz#a679b81a7f111e4766235f4f0c46d230ee0f7436" @@ -3985,13 +4547,19 @@ jest-worker@21.3.0-beta.8: dependencies: merge-stream "^1.0.1" -jest-worker@22.1.0, jest-worker@^22.1.0: +jest-worker@22.2.2: + version "22.2.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.2.2.tgz#c1f5dc39976884b81f68ec50cb8532b2cbab3390" + dependencies: + merge-stream "^1.0.1" + +jest-worker@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.1.0.tgz#0987832fe58fbdc205357f4c19b992446368cafb" dependencies: merge-stream "^1.0.1" -jest-worker@^22.4.3: +jest-worker@^22.2.2, jest-worker@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.4.3.tgz#5c421417cba1c0abf64bf56bd5fb7968d79dd40b" dependencies: @@ -4003,7 +4571,7 @@ jest@^22.0.3: dependencies: jest-cli "^22.1.4" -jest@^22.1.1: +jest@^22.2.1: version "22.4.3" resolved "https://registry.yarnpkg.com/jest/-/jest-22.4.3.tgz#2261f4b117dc46d9a4a1a673d2150958dee92f16" dependencies: @@ -4043,7 +4611,7 @@ js-yaml@^3.7.0: argparse "^1.0.7" esprima "^4.0.0" -jsbn@~0.1.0: +jsbn@^0.1.0, jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -4082,6 +4650,10 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -4116,6 +4688,12 @@ json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + dependencies: + minimist "^1.2.0" + jsonfile@^2.1.0, jsonfile@^2.3.1: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -4374,11 +4952,15 @@ lodash.templatesettings@^3.0.0: lodash._reinterpolate "^3.0.0" lodash.escape "^3.0.0" +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + lodash.zipobject@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz#b399f5aba8ff62a746f6979bf20b214f964dbef8" -lodash@4.17.4, lodash@4.x.x, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.14.1, lodash@^4.16.6, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: +lodash@4.x.x, lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.14.1, lodash@^4.16.6, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4386,6 +4968,10 @@ lodash@^3.5.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" +lodash@^4.17.5: + version "4.17.5" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + lodash@~2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e" @@ -4486,6 +5072,12 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" +match-require@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/match-require/-/match-require-2.1.0.tgz#f67d62c4cb1d703f408fb63b55b9ae83fb25e2cc" + dependencies: + uuid "^3.0.0" + md5-file@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-3.2.3.tgz#f9bceb941eca2214a4c0727f5e700314e770f06f" @@ -4533,6 +5125,12 @@ methods@^1.1.1, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" +metro-babylon7@0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/metro-babylon7/-/metro-babylon7-0.28.0.tgz#cf9701ffdc1992d1562b4cb667d9692164950df4" + dependencies: + babylon "^7.0.0-beta" + metro-bundler@^0.22.1: version "0.22.1" resolved "https://registry.yarnpkg.com/metro-bundler/-/metro-bundler-0.22.1.tgz#e91d5e6f78f6d1549e6863ec4b4bba2713b1df19" @@ -4578,27 +5176,76 @@ metro-bundler@^0.22.1: xpipe "^1.0.5" yargs "^9.0.0" -metro-core@0.24.6, metro-core@^0.24.4: - version "0.24.6" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.24.6.tgz#fe75f06bbb21d594f8eed75880fb5cc9e0ccddf7" +metro-cache@0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.28.0.tgz#c5164a361985fc0294059fccdf4ea824e3173c1d" dependencies: - lodash "^4.16.6" + jest-serializer "^22.4.0" + mkdirp "^0.5.1" -metro-source-map@0.24.6: - version "0.24.6" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.24.6.tgz#6c64b958b47696e365aacf508e726ae5820959a4" +metro-core@0.28.0, metro-core@^0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.28.0.tgz#e1ced4cf07ca8fb5196a6e5ca853b5d893f06038" dependencies: - source-map "^0.5.6" + lodash.throttle "^4.1.1" -metro@^0.24.4: - version "0.24.6" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.24.6.tgz#a7b01c3c7d1d1868f232d2d92a8bc4ecc251e909" +metro-minify-uglify@0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.28.0.tgz#c9aecb8e893430d2fd58e00cf799c00b99dc0f79" + dependencies: + uglify-es "^3.1.9" + +metro-resolver@0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.28.0.tgz#813802d60fc762772927c81d02e01c7eec84bad8" dependencies: absolute-path "^0.0.0" + +metro-source-map@0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.28.0.tgz#ec8c3161d8516ad3c4e7149f2c3d4802f4fd6fa2" + dependencies: + source-map "^0.5.6" + +metro@^0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.28.0.tgz#22999c96c3129682a76acd4e1f2adc17f7d77cac" + dependencies: + "@babel/core" "^7.0.0-beta" + "@babel/generator" "^7.0.0-beta" + "@babel/helper-remap-async-to-generator" "^7.0.0-beta" + "@babel/plugin-check-constants" "^7.0.0-beta" + "@babel/plugin-external-helpers" "^7.0.0-beta" + "@babel/plugin-proposal-class-properties" "^7.0.0-beta" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0-beta" + "@babel/plugin-syntax-dynamic-import" "^7.0.0-beta" + "@babel/plugin-transform-arrow-functions" "^7.0.0-beta" + "@babel/plugin-transform-block-scoping" "^7.0.0-beta" + "@babel/plugin-transform-classes" "^7.0.0-beta" + "@babel/plugin-transform-computed-properties" "^7.0.0-beta" + "@babel/plugin-transform-destructuring" "^7.0.0-beta" + "@babel/plugin-transform-flow-strip-types" "^7.0.0-beta" + "@babel/plugin-transform-for-of" "^7.0.0-beta" + "@babel/plugin-transform-function-name" "^7.0.0-beta" + "@babel/plugin-transform-literals" "^7.0.0-beta" + "@babel/plugin-transform-modules-commonjs" "^7.0.0-beta" + "@babel/plugin-transform-object-assign" "^7.0.0-beta" + "@babel/plugin-transform-parameters" "^7.0.0-beta" + "@babel/plugin-transform-react-display-name" "^7.0.0-beta" + "@babel/plugin-transform-react-jsx" "^7.0.0-beta" + "@babel/plugin-transform-react-jsx-source" "^7.0.0-beta" + "@babel/plugin-transform-regenerator" "^7.0.0-beta" + "@babel/plugin-transform-shorthand-properties" "^7.0.0-beta" + "@babel/plugin-transform-spread" "^7.0.0-beta" + "@babel/plugin-transform-template-literals" "^7.0.0-beta" + "@babel/template" "^7.0.0-beta" + "@babel/traverse" "^7.0.0-beta" + "@babel/types" "^7.0.0-beta" + absolute-path "^0.0.0" async "^2.4.0" babel-core "^6.24.1" babel-generator "^6.26.0" - babel-plugin-external-helpers "^6.18.0" + babel-plugin-external-helpers "^6.22.0" babel-preset-es2015-node "^6.1.1" babel-preset-fbjs "^2.1.4" babel-preset-react-native "^4.0.0" @@ -4615,16 +5262,20 @@ metro@^0.24.4: fs-extra "^1.0.0" graceful-fs "^4.1.3" image-size "^0.6.0" - jest-docblock "22.1.0" - jest-haste-map "22.1.0" - jest-worker "22.1.0" + jest-docblock "22.4.0" + jest-haste-map "22.4.2" + jest-worker "22.2.2" json-stable-stringify "^1.0.1" json5 "^0.4.0" left-pad "^1.1.3" - lodash "^4.16.6" + lodash.throttle "^4.1.1" merge-stream "^1.0.1" - metro-core "0.24.6" - metro-source-map "0.24.6" + metro-babylon7 "0.28.0" + metro-cache "0.28.0" + metro-core "0.28.0" + metro-minify-uglify "0.28.0" + metro-resolver "0.28.0" + metro-source-map "0.28.0" mime-types "2.1.11" mkdirp "^0.5.1" request "^2.79.0" @@ -4633,7 +5284,6 @@ metro@^0.24.4: source-map "^0.5.6" temp "0.8.3" throat "^4.1.0" - uglify-es "^3.1.9" wordwrap "^1.0.0" write-file-atomic "^1.2.0" ws "^1.1.0" @@ -4662,6 +5312,10 @@ micromatch@^2.1.5, micromatch@^2.3.11: version "1.32.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414" +"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + mime-db@~1.23.0: version "1.23.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.23.0.tgz#a31b4070adaea27d732ea333740a64d0ec9a6659" @@ -4682,6 +5336,12 @@ mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, dependencies: mime-db "~1.30.0" +mime-types@~2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -4746,14 +5406,20 @@ mkdirp@*, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" -mkpath@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-0.1.0.tgz#7554a6f8d871834cc97b5462b122c4c124d6de91" - moment@2.x.x, moment@^2.10.6: version "2.20.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" +morgan@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" + dependencies: + basic-auth "~2.0.0" + debug "2.6.9" + depd "~1.1.1" + on-finished "~2.3.0" + on-headers "~1.0.1" + morgan@~1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.6.1.tgz#5fd818398c6819cba28a7cd6664f292fe1c0bbf2" @@ -4797,10 +5463,6 @@ multipipe@^0.1.2: dependencies: duplexer2 "0.0.2" -mute-stream@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" - mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -4893,12 +5555,6 @@ noop-fn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/noop-fn/-/noop-fn-1.0.0.tgz#5f33d47f13d2150df93e0cb036699e982f78ffbf" -nopt@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -4906,12 +5562,6 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - dependencies: - abbrev "1" - normalize-package-data@^2.3.2: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" @@ -5017,10 +5667,6 @@ once@^1.3.0, once@^1.3.3, once@^1.4.0: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -5090,11 +5736,7 @@ os-name@^2.0.1: macos-release "^1.0.0" win-release "^1.0.0" -os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -5430,10 +6072,6 @@ punycode@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - qrcode-terminal@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz#ffc6c28a2fc0bfb47052b47e23f4f446a5fbdb9e" @@ -5442,7 +6080,7 @@ qs@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" -qs@6.5.1, qs@^6.2.1, qs@^6.5.0, qs@^6.5.1, qs@~6.5.1: +qs@6.5.1, qs@^6.2.1, qs@^6.4.0, qs@^6.5.0, qs@^6.5.1, qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -5532,13 +6170,21 @@ react-deep-force-update@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.1.1.tgz#bcd31478027b64b3339f108921ab520b4313dc2c" -react-devtools-core@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-3.0.0.tgz#f683e19f0311108f97dbb5b29d948323a1bf7c03" +react-devtools-core@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-3.1.0.tgz#eec2e9e0e6edb77772e2bfc7d286a296f55a261a" dependencies: shell-quote "^1.6.1" ws "^2.0.3" +react-is@^16.3.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22" + +react-lifecycles-compat@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-1.1.4.tgz#fc005c72849b7ed364de20a0f64ff58ebdc2009a" + react-native-branch@2.0.0-beta.3: version "2.0.0-beta.3" resolved "https://registry.yarnpkg.com/react-native-branch/-/react-native-branch-2.0.0-beta.3.tgz#2167af86bbc9f964bd45bd5f37684e5b54965e32" @@ -5559,17 +6205,26 @@ react-native-drawer-layout@1.3.2: dependencies: react-native-dismiss-keyboard "1.0.0" -react-native-gesture-handler@1.0.0-alpha.39: - version "1.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.0.0-alpha.39.tgz#e87851d5efc49d2d91ebf76ad59b7b5d1fd356f5" +react-native-gesture-handler@1.0.0-alpha.41: + version "1.0.0-alpha.41" + resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.0.0-alpha.41.tgz#5667a1977ab148339ec2e7b0a94ad4b959cf09e5" dependencies: hoist-non-react-statics "^2.3.1" invariant "^2.2.2" prop-types "^15.5.10" -react-native-maps@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-0.19.0.tgz#ce94fad1cf360e335cb4338a68c95f791e869074" +"react-native-maps@https://github.com/expo/react-native-maps/archive/0.20.1-exp.0.tar.gz": + version "0.20.1" + resolved "https://github.com/expo/react-native-maps/archive/0.20.1-exp.0.tar.gz#81d607e2d77481c0441aecfdbc303389a34084c0" + dependencies: + babel-plugin-module-resolver "^2.3.0" + babel-preset-react-native "1.9.0" + +react-native-safe-area-view@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.7.0.tgz#38f5ab9368d6ef9e5d18ab64212938af3ec39421" + dependencies: + hoist-non-react-statics "^2.3.1" react-native-safe-module@^1.1.0: version "1.2.0" @@ -5588,16 +6243,17 @@ react-native-sentry@^0.30.0: sentry-cli-binary "^1.21.0" xcode "^1.0.0" -"react-native-svg@https://github.com/expo/react-native-svg/archive/5.5.1-exp.1.tar.gz": - version "5.5.1" - resolved "https://github.com/expo/react-native-svg/archive/5.5.1-exp.1.tar.gz#0c6e373dbe63cfcbdd465f5b2965ebe011c8962f" +react-native-svg@6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-6.2.2.tgz#5803cddce374a542b4468c38a2474fca32080685" dependencies: color "^2.0.1" lodash "^4.16.6" + pegjs "^0.10.0" -react-native-tab-view@^0.0.74: +"react-native-tab-view@github:react-navigation/react-native-tab-view": version "0.0.74" - resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.74.tgz#62c0c882d9232b461ce181d440d683b4f99d1bd8" + resolved "https://codeload.github.com/react-navigation/react-native-tab-view/tar.gz/36ebd834d78b841fc19778c966465d02fd1213bb" dependencies: prop-types "^15.6.0" @@ -5605,17 +6261,17 @@ react-native-typography@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/react-native-typography/-/react-native-typography-1.2.1.tgz#380c71a71e4a4774bd2ca81971aabc6ecf3cb195" -react-native-vector-icons@4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-4.4.2.tgz#090f42ee0396c4cc4eae0ddaa518028ba8df40c7" +react-native-vector-icons@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-4.5.0.tgz#6b95619e64f62f05f579f74a01fe5640df95158b" dependencies: lodash "^4.0.0" prop-types "^15.5.10" yargs "^8.0.2" -"react-native@https://github.com/expo/react-native/archive/sdk-25.0.0.tar.gz": - version "0.52.0" - resolved "https://github.com/expo/react-native/archive/sdk-25.0.0.tar.gz#e46ac1a9ff6d48db801c1937c5c2ea9353415818" +"react-native@https://github.com/expo/react-native/archive/sdk-26.0.0.tar.gz": + version "0.54.2" + resolved "https://github.com/expo/react-native/archive/sdk-26.0.0.tar.gz#0e55599929c08c1d2100fdd2b90926ad9f567b42" dependencies: absolute-path "^0.0.0" art "^0.10.0" @@ -5631,11 +6287,13 @@ react-native-vector-icons@4.4.2: base64-js "^1.1.2" chalk "^1.1.1" commander "^2.9.0" - connect "^2.8.3" - create-react-class "^15.5.2" + compression "^1.7.1" + connect "^3.6.5" + create-react-class "^15.6.3" debug "^2.2.0" denodeify "^1.2.1" envinfo "^3.0.0" + errorhandler "^1.5.0" event-target-shim "^1.0.5" fbjs "^0.8.14" fbjs-scripts "^0.8.1" @@ -5643,12 +6301,13 @@ react-native-vector-icons@4.4.2: glob "^7.1.1" graceful-fs "^4.1.3" inquirer "^3.0.6" - lodash "^4.16.6" - metro "^0.24.4" - metro-core "^0.24.4" + lodash "^4.17.5" + metro "^0.28.0" + metro-core "^0.28.0" mime "^1.3.4" minimist "^1.2.0" mkdirp "^0.5.1" + morgan "^1.9.0" node-fetch "^1.3.3" node-notifier "^5.1.2" npmlog "^2.0.4" @@ -5659,11 +6318,12 @@ react-native-vector-icons@4.4.2: promise "^7.1.1" prop-types "^15.5.8" react-clone-referenced-element "^1.0.1" - react-devtools-core "3.0.0" + react-devtools-core "3.1.0" react-timer-mixin "^0.13.2" regenerator-runtime "^0.11.0" rimraf "^2.5.4" semver "^5.0.3" + serve-static "^1.13.1" shell-quote "1.6.1" stacktrace-parser "^0.1.3" whatwg-fetch "^1.0.0" @@ -5678,17 +6338,18 @@ react-navigation-props-mapper@^0.1.2: dependencies: hoist-non-react-statics "^2.2.1" -react-navigation@^1.0.0-beta.27: - version "1.0.0-beta.27" - resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-1.0.0-beta.27.tgz#e6263b01975cd790e32b3711c2eb6cead96c102c" +react-navigation@^1.5.8: + version "1.5.11" + resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-1.5.11.tgz#fba6ab45d7b9987c1763a5aaac53b4f6d62b7f5c" dependencies: - babel-plugin-transform-define "^1.3.0" clamp "^1.0.1" hoist-non-react-statics "^2.2.0" path-to-regexp "^1.7.0" prop-types "^15.5.10" + react-lifecycles-compat "^1.0.2" react-native-drawer-layout-polyfill "^1.3.2" - react-native-tab-view "^0.0.74" + react-native-safe-area-view "^0.7.0" + react-native-tab-view "github:react-navigation/react-native-tab-view" react-proxy@^1.1.7: version "1.1.8" @@ -5708,7 +6369,7 @@ react-redux@^5.0.2: loose-envify "^1.1.0" prop-types "^15.5.10" -react-test-renderer@16.2.0, react-test-renderer@^16.2.0: +react-test-renderer@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.2.0.tgz#bddf259a6b8fcd8555f012afc8eacc238872a211" dependencies: @@ -5716,6 +6377,15 @@ react-test-renderer@16.2.0, react-test-renderer@^16.2.0: object-assign "^4.1.1" prop-types "^15.6.0" +react-test-renderer@^16.3.0-alpha.2: + version "16.3.2" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.2.tgz#3d1ed74fda8db42521fdf03328e933312214749a" + dependencies: + fbjs "^0.8.16" + object-assign "^4.1.1" + prop-types "^15.6.0" + react-is "^16.3.2" + react-timer-mixin@^0.13.2: version "0.13.3" resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.3.tgz#0da8b9f807ec07dc3e854d082c737c65605b3d22" @@ -5727,7 +6397,16 @@ react-transform-hmr@^1.0.4: global "^4.3.0" react-proxy "^1.1.7" -react@16.2.0, react@^16.0.0: +react@16.3.0-alpha.1: + version "16.3.0-alpha.1" + resolved "https://registry.yarnpkg.com/react/-/react-16.3.0-alpha.1.tgz#de20f646e31e8b3c004e6bcbd3c54d51b48e1120" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + +react@^16.0.0: version "16.2.0" resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" dependencies: @@ -5773,7 +6452,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@1.1.x, readable-stream@^1.1.8, readable-stream@~1.1.8, readable-stream@~1.1.9: +readable-stream@1.1.x, readable-stream@~1.1.8, readable-stream@~1.1.9: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" dependencies: @@ -5850,6 +6529,12 @@ regenerator-transform@^0.10.0: babel-types "^6.19.0" private "^0.1.6" +regenerator-transform@^0.12.3: + version "0.12.3" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.12.3.tgz#459adfb64f6a27164ab991b7873f45ab969eca8b" + dependencies: + private "^0.1.6" + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -6010,6 +6695,12 @@ resolve@^1.2.0: dependencies: path-parse "^1.0.5" +resolve@^1.3.2: + version "1.7.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" + dependencies: + path-parse "^1.0.5" + response-time@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/response-time/-/response-time-2.3.2.tgz#ffa71bab952d62f7c1d49b7434355fbc68dffc5a" @@ -6027,13 +6718,6 @@ rest-facade@^1.10.0: superagent "^3.8.0" superagent-proxy "^1.0.2" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -6087,9 +6771,11 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" +rxjs@^5.5.2: + version "5.5.10" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.10.tgz#fde02d7a614f6c8683d0d1957827f492e09db045" + dependencies: + symbol-observable "1.0.1" safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" @@ -6168,6 +6854,24 @@ send@0.16.1: range-parser "~1.2.0" statuses "~1.3.1" +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + sentence-case@^1.1.1, sentence-case@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-1.1.3.tgz#8034aafc2145772d3abe1509aa42c9e1042dc139" @@ -6223,6 +6927,15 @@ serve-static@1.13.1: parseurl "~1.3.2" send "0.16.1" +serve-static@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + serve-static@~1.10.0: version "1.10.3" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.10.3.tgz#ce5a6ecd3101fed5ec09827dac22a9c29bfb0535" @@ -6366,7 +7079,7 @@ source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.6: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -6378,13 +7091,6 @@ sparkles@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" -spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" - spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -6441,7 +7147,7 @@ stacktrace-parser@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.4.tgz#01397922e5f62ecf30845522c95c4fe1d25e7d4e" -statuses@1, "statuses@>= 1.3.1 < 2": +statuses@1, "statuses@>= 1.3.1 < 2", statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" @@ -6567,7 +7273,7 @@ superagent-retry@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/superagent-retry/-/superagent-retry-0.6.0.tgz#e49b35ca96c0e3b1d0e3f49605136df0e0a028b7" -superagent@^3.5.0, superagent@^3.8.0: +superagent@^3.5.0, superagent@^3.8.0, superagent@^3.8.2: version "3.8.2" resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.2.tgz#e4a11b9d047f7d3efeb3bbe536d9ec0021d16403" dependencies: @@ -6605,6 +7311,10 @@ swap-case@^1.1.0: lower-case "^1.1.1" upper-case "^1.1.1" +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + symbol-observable@^1.0.2, symbol-observable@^1.0.3, symbol-observable@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32" @@ -6736,12 +7446,6 @@ title-case@^1.1.0: sentence-case "^1.1.1" upper-case "^1.0.3" -tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - dependencies: - os-tmpdir "~1.0.1" - tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6756,6 +7460,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + topo@1.x.x: version "1.1.0" resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" @@ -6768,12 +7476,6 @@ topo@2.x.x: dependencies: hoek "4.x.x" -touch@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/touch/-/touch-0.0.3.tgz#51aef3d449571d4f287a5d87c9c8b49181a0db1d" - dependencies: - nopt "~1.0.10" - tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" @@ -6786,14 +7488,6 @@ tr46@^1.0.0: dependencies: punycode "^2.1.0" -traverse@0.6.6: - version "0.6.6" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" - -"traverse@>=0.3.0 <0.4": - version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - tree-kill@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" @@ -6911,6 +7605,10 @@ upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" +url-join@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" + url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" @@ -7083,6 +7781,10 @@ winchan@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/winchan/-/winchan-0.1.4.tgz#88fa12411cd542eb626018c38a196bcbb17993bb" +winchan@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/winchan/-/winchan-0.2.0.tgz#3863028e7f974b0da1412f28417ba424972abd94" + window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" @@ -7118,7 +7820,7 @@ write-file-atomic@^1.2.0: imurmurhash "^0.1.4" slide "^1.1.5" -write-file-atomic@^2.1.0: +write-file-atomic@^2.1.0, write-file-atomic@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" dependencies: @@ -7164,29 +7866,29 @@ xcode@^1.0.0: simple-plist "^0.2.1" uuid "3.0.1" -xdl@47.1.4: - version "47.1.4" - resolved "https://registry.yarnpkg.com/xdl/-/xdl-47.1.4.tgz#dabe4ca6f9c61520a69c95d502d1a3544d305cfb" +xdl@49.0.2: + version "49.0.2" + resolved "https://registry.yarnpkg.com/xdl/-/xdl-49.0.2.tgz#5245749cd8e9346b4032da6c0e80f95491c16334" dependencies: "@expo/bunyan" "^1.8.10" - "@expo/json-file" "^5.3.0" - "@expo/ngrok" "2.3.0" + "@expo/json-file" "^8.0.0" + "@expo/ngrok" "2.4.2" "@expo/osascript" "^1.8.0" "@expo/schemer" "1.1.0" "@expo/spawn-async" "^1.2.8" analytics-node "^2.1.0" - auth0 "^2.7.0" - auth0-js "^7.4.0" - axios "^0.16.1" - bluebird "^3.4.7" + auth0 "2.9.1" + auth0-js "9.3.3" + axios "0.16.2" body-parser "^1.15.2" concat-stream "^1.6.0" decache "^4.1.0" delay-async "^1.0.0" es6-error "^4.0.2" - exists-async "^2.0.0" + escape-string-regexp "^1.0.5" express "^4.13.4" file-type "^4.0.0" + follow-redirects "^1.2.3" form-data "^2.1.4" freeport-async "^1.1.1" fs-extra "^4.0.2" @@ -7198,17 +7900,15 @@ xdl@47.1.4: home-dir "^1.0.0" idx "^2.1.0" indent-string "^3.1.0" + inquirer "^5.0.1" + invariant "^2.2.4" joi "^10.0.2" jsonfile "^2.3.1" - jsonschema "^1.1.0" jsonwebtoken "^7.2.1" lodash "^4.14.1" md5hex "^1.0.0" minimatch "^3.0.4" mkdirp "^0.5.1" - mkdirp-promise "^5.0.0" - mv "^2.1.1" - mz "^2.6.0" ncp "^2.0.0" opn "^4.0.2" plist "2.1.0" @@ -7223,7 +7923,6 @@ xdl@47.1.4: redux-logger "^2.7.4" replace-string "^1.1.0" request "^2.83.0" - request-progress "^3.0.0" request-promise-native "^1.0.5" semver "^5.3.0" slugid "^1.1.0" @@ -7236,7 +7935,6 @@ xdl@47.1.4: util.promisify "^1.0.0" uuid "^3.0.1" xmldom "^0.1.27" - yesno "^0.0.1" xdl@^44.0.2: version "44.0.2" diff --git a/package.json b/package.json index 3b6c995d5c..2699a9075f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Spectrum", - "version": "2.2.6", + "version": "2.2.7", "license": "BSD-3-Clause", "devDependencies": { "babel-cli": "^6.24.1", @@ -106,9 +106,11 @@ "graphql-subscriptions": "0.5.6", "graphql-tag": "^2.6.1", "graphql-tools": "1.2.3", + "helmet": "^3.12.0", "highlight.js": "^9.10.0", "history": "^4.6.1", "hoist-non-react-statics": "^2.3.1", + "hpp": "^0.2.2", "imgix-core-js": "^1.0.6", "ioredis": "3.1.4", "isomorphic-fetch": "^2.2.1", @@ -199,7 +201,7 @@ "start:pluto": "cross-env NODE_ENV=production node build-pluto/main.js", "start:api": "cross-env NODE_ENV=production node build-api/main.js", "dev:web": "cross-env NODE_PATH=./ react-app-rewired start", - "dev:api": "cross-env NODE_PATH=./ cross-env NODE_ENV=development cross-env DEBUG=build*,api*,shared:middlewares*,-api:resolvers cross-env DIR=api backpack", + "dev:api": "cross-env FILE_STORAGE=local cross-env NODE_PATH=./ cross-env NODE_ENV=development cross-env DEBUG=build*,api*,shared:middlewares*,-api:resolvers cross-env DIR=api backpack", "dev:athena": "cross-env NODE_PATH=./ cross-env NODE_ENV=development cross-env DEBUG=build*,athena*,shared:middlewares*,-athena:resolvers cross-env DIR=athena backpack", "dev:hermes": "cross-env NODE_PATH=./ cross-env NODE_ENV=development cross-env DEBUG=build*,hermes*,shared:middlewares*,-hermes:resolvers cross-env DIR=hermes backpack", "dev:chronos": "cross-env NODE_PATH=./ cross-env NODE_ENV=development cross-env DEBUG=build*,chronos*,shared:middlewares*,-chronos:resolvers cross-env DIR=chronos backpack", @@ -255,7 +257,7 @@ }, "lint-staged": { "*.js": [ - "prettier --write --single-quote --trailing-comma es5", + "prettier --write", "eslint --fix", "git add" ] diff --git a/pluto/package.json b/pluto/package.json index 6e7ef567b4..f4681bf2d3 100644 --- a/pluto/package.json +++ b/pluto/package.json @@ -17,7 +17,8 @@ "rethinkdbdash": "^2.3.31", "shortid": "^2.2.8", "source-map-support": "^0.5.4", - "stripe": "^5.4.0" + "stripe": "^5.4.0", + "toobusy-js": "^0.5.1" }, "scripts": { "start": "NODE_ENV=production node main.js" diff --git a/pluto/yarn.lock b/pluto/yarn.lock index 94b7f151ce..6ea3d508a6 100644 --- a/pluto/yarn.lock +++ b/pluto/yarn.lock @@ -631,6 +631,10 @@ timed-out@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" +toobusy-js@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/toobusy-js/-/toobusy-js-0.5.1.tgz#5511f78f6a87a6a512d44fdb0efa13672217f659" + type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" diff --git a/shared/bull/queues.js b/shared/bull/queues.js index 88d1946a4b..398ea20e08 100644 --- a/shared/bull/queues.js +++ b/shared/bull/queues.js @@ -63,6 +63,7 @@ import { COMMUNITY_INVOICE_PAID_NOTIFICATION, REACTION_NOTIFICATION, PRIVATE_CHANNEL_REQUEST_SENT, + PRIVATE_CHANNEL_REQUEST_APPROVED, COMMUNITY_INVITE_NOTIFICATION, CHANNEL_NOTIFICATION, DIRECT_MESSAGE_NOTIFICATION, @@ -83,6 +84,7 @@ exports.QUEUE_NAMES = { sendCommunityInvoicePaidNotificationQueue: COMMUNITY_INVOICE_PAID_NOTIFICATION, sendReactionNotificationQueue: REACTION_NOTIFICATION, sendPrivateChannelRequestQueue: PRIVATE_CHANNEL_REQUEST_SENT, + sendPrivateChannelRequestApprovedQueue: PRIVATE_CHANNEL_REQUEST_APPROVED, sendPrivateChannelInviteNotificationQueue: 'private channel invite notification', sendCommunityInviteNotificationQueue: COMMUNITY_INVITE_NOTIFICATION, diff --git a/shared/bull/types.js b/shared/bull/types.js index 7f90d69e46..c0003fb310 100644 --- a/shared/bull/types.js +++ b/shared/bull/types.js @@ -220,6 +220,13 @@ export type PrivateChannelRequestJobData = { channel: DBChannel, }; +export type PrivateChannelRequestApprovedJobData = { + userId: string, + channelId: string, + communityId: string, + moderatorId: string, +}; + export type PrivateChannelInviteNotificationJobData = { recipient: { email: string, firstName?: ?string, lastName?: ?string }, channelId: string, @@ -361,6 +368,9 @@ export type Queues = { sendCommunityInvoicePaidNotificationQueue: BullQueue, sendReactionNotificationQueue: BullQueue, sendPrivateChannelRequestQueue: BullQueue, + sendPrivateChannelRequestApprovedQueue: BullQueue< + PrivateChannelRequestApprovedJobData + >, sendPrivateChannelInviteNotificationQueue: BullQueue< PrivateChannelInviteNotificationJobData >, diff --git a/shared/graphql/index.js b/shared/graphql/index.js index 6098f9fe67..e87f972867 100644 --- a/shared/graphql/index.js +++ b/shared/graphql/index.js @@ -16,6 +16,11 @@ const IS_PROD = process.env.NODE_ENV === 'production'; // In production the API is at the same URL, in development it's at a different port const API_URI = IS_PROD ? '/api' : 'http://localhost:3001/api'; +// @see: https://github.com/facebook/react-native/issues/9599 +if (typeof global.self === 'undefined') { + global.self = global; +} + type CreateClientOptions = { token?: ?string, }; @@ -107,6 +112,6 @@ export const clearApolloStore = () => { try { client.resetStore(); } catch (e) { - console.log('error clearing store'); + console.error('error clearing store'); } }; diff --git a/shared/middlewares/security.js b/shared/middlewares/security.js new file mode 100644 index 0000000000..b7915efb63 --- /dev/null +++ b/shared/middlewares/security.js @@ -0,0 +1,34 @@ +// @flow +const hpp = require('hpp'); +const helmet = require('helmet'); + +// $FlowFixMe +function securityMiddleware(server) { + // Don't expose any software information to hackers. + server.disable('x-powered-by'); + + // Prevent HTTP Parameter pollution. + server.use(hpp()); + + // The xssFilter middleware sets the X-XSS-Protection header to prevent + // reflected XSS attacks. + // @see https://helmetjs.github.io/docs/xss-filter/ + server.use(helmet.xssFilter()); + + // Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header. + // @see https://helmetjs.github.io/docs/frameguard/ + server.use(helmet.frameguard('deny')); + + // Sets the X-Download-Options to prevent Internet Explorer from executing + // downloads in your site’s context. + // @see https://helmetjs.github.io/docs/ienoopen/ + server.use(helmet.ieNoOpen()); + + // Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying + // to guess (“sniff”) the MIME type, which can have security implications. It + // does this by setting the X-Content-Type-Options header to nosniff. + // @see https://helmetjs.github.io/docs/dont-sniff-mimetype/ + server.use(helmet.noSniff()); +} + +module.exports = securityMiddleware; diff --git a/shared/stripe/index.js b/shared/stripe/index.js index 4285d34a15..21425043be 100644 --- a/shared/stripe/index.js +++ b/shared/stripe/index.js @@ -1,5 +1,5 @@ require('now-env'); -const IS_PROD = process.env.NODE_ENV === 'production'; +const IS_PROD = process.env.NODE_ENV === 'production' && !process.env.FORCE_DEV; const STRIPE_TOKEN = IS_PROD ? process.env.STRIPE_TOKEN : process.env.STRIPE_TOKEN_DEVELOPMENT; diff --git a/shared/types.js b/shared/types.js index e5f18c8ce8..b4e4fb552f 100644 --- a/shared/types.js +++ b/shared/types.js @@ -387,3 +387,5 @@ export type FileUpload = { encoding: string, stream: any, }; + +export type EntityTypes = 'communities' | 'channels' | 'users' | 'threads'; diff --git a/src/components/chatInput/index.js b/src/components/chatInput/index.js index 678e649b44..828e2fa529 100644 --- a/src/components/chatInput/index.js +++ b/src/components/chatInput/index.js @@ -21,6 +21,7 @@ import { addToastWithTimeout } from '../../actions/toasts'; import { openModal } from '../../actions/modals'; import { Form, + ChatInputContainer, ChatInputWrapper, SendButton, PhotoSizeError, @@ -113,6 +114,7 @@ class ChatInput extends React.Component { if (currState.isSendingMediaMessage !== nextState.isSendingMediaMessage) return true; if (currState.mediaPreview !== nextState.mediaPreview) return true; + if (currState.photoSizeError !== nextState.photoSizeError) return true; return false; } @@ -144,6 +146,7 @@ class ChatInput extends React.Component { }; toggleMarkdownHint = state => { + // eslint-disable-next-line let hasText = false; // NOTE(@mxstbr): This throws an error on focus, so we just ignore that try { @@ -529,7 +532,7 @@ class ChatInput extends React.Component { return ( - + {photoSizeError && (

{ /> )} - {currentUser && ( - - )} -

- (this.editor = editor)} - editorKey="chat-input" - decorators={[mentionsDecorator, linksDecorator]} - networkDisabled={networkDisabled} - /> - - -
+ + {currentUser && ( + + )} +
+ (this.editor = editor)} + editorKey="chat-input" + decorators={[mentionsDecorator, linksDecorator]} + networkDisabled={networkDisabled} + /> + + +
+ **bold** *italics* diff --git a/src/components/chatInput/input.js b/src/components/chatInput/input.js index 6c672dcee6..7732e8f48b 100644 --- a/src/components/chatInput/input.js +++ b/src/components/chatInput/input.js @@ -5,7 +5,6 @@ import createLinkifyPlugin from 'draft-js-linkify-plugin'; import createCodeEditorPlugin from 'draft-js-code-editor-plugin'; import createMarkdownPlugin from 'draft-js-markdown-plugin'; import Prism from 'prismjs'; -import debounce from 'debounce'; import 'prismjs/components/prism-java'; import 'prismjs/components/prism-scala'; import 'prismjs/components/prism-go'; @@ -18,7 +17,6 @@ import 'prismjs/components/prism-perl'; import 'prismjs/components/prism-ruby'; import 'prismjs/components/prism-swift'; import createPrismPlugin from 'draft-js-prism-plugin'; -import { isAndroid } from 'shared/draft-utils'; import { customStyleMap } from 'src/components/rich-text-editor/style'; import type { DraftEditorState } from 'draft-js/lib/EditorState'; @@ -61,7 +59,7 @@ class Input extends React.Component { createMarkdownPlugin({ features: { inline: ['BOLD', 'ITALIC', 'CODE'], - block: ['CODE', 'ordered-list-item', 'unordered-list-item'], + block: ['CODE'], }, renderLanguageSelect: () => null, }), diff --git a/src/components/chatInput/style.js b/src/components/chatInput/style.js index dc2f5adb8c..9c3b8c4f40 100644 --- a/src/components/chatInput/style.js +++ b/src/components/chatInput/style.js @@ -10,13 +10,25 @@ import { } from 'src/components/globals'; import { Wrapper as EditorWrapper } from '../rich-text-editor/style'; -export const ChatInputWrapper = styled(FlexRow)` - flex: none; - align-items: center; +export const ChatInputContainer = styled(FlexRow)` + display: flex; + flex-direction: column; z-index: inherit; position: relative; width: 100%; margin: 0; + + a { + text-decoration: underline; + } +`; + +export const ChatInputWrapper = styled.div` + display: flex; + flex-direction: row; + align-items: center; + width: 100%; + margin: 0; padding: 16px 16px 0px; background-color: ${props => props.theme.bg.default}; border-top: 1px solid ${({ theme }) => theme.bg.border}; @@ -29,10 +41,6 @@ export const ChatInputWrapper = styled(FlexRow)` z-index: ${zIndex.mobileInput}; padding: 8px; } - - a { - text-decoration: underline; - } `; export const Form = styled.form` @@ -176,6 +184,7 @@ export const PhotoSizeError = styled.div` align-items: center; align-content: center; padding: 8px 16px; + width: 100%; background: #fff1cc; border-top: 1px solid #ffd566; diff --git a/src/components/infiniteScroll/index.js b/src/components/infiniteScroll/index.js index 89736ad831..4545fa0608 100644 --- a/src/components/infiniteScroll/index.js +++ b/src/components/infiniteScroll/index.js @@ -1,35 +1,247 @@ -import React, { Component } from 'react'; +// @flow +import * as React from 'react'; +import { fetchMoreOnInfiniteScrollLoad } from './tallViewports'; -export const withInfiniteScroll = Comp => { - return class InfiniteScroll extends Component { - componentDidMount() { - // if (!this.scrollBody) return; - // let node = this.scrollBody; - // node.addEventListener('scroll', this.handleScroll) +type Props = { + element: string, + hasMore: boolean, + initialLoad: boolean, + loader: React.Node, + loadMore: Function, + isLoadingMore: boolean, + pageStart: number, + threshold: number, + useWindow: boolean, + isReverse: boolean, + scrollElement: ?Object, + children: Array | ?React.Node, + className: string, +}; + +export default class InfiniteScroll extends React.Component { + static defaultProps = { + element: 'div', + hasMore: false, + initialLoad: true, + pageStart: 0, + threshold: 250, + useWindow: true, + isReverse: false, + scrollElement: null, + scrollComponent: null, + }; + + scrollListener: Function; + scrollComponent: Object; + pageLoaded: number; + _defaultLoader: React.Node; + + constructor(props: Props) { + super(props); + + this._defaultLoader = props.loader; + this.scrollListener = this.scrollListener.bind(this); + } + + componentDidMount() { + this.pageLoaded = this.props.pageStart; + this.attachScrollListener(); + } + + componentDidUpdate(prevProps: Props) { + const curr = this.props; + + /* + if the outer query is fetching more, there's no reason to re-check the scroll + position or re-attach a scroll listener - a refetch is already running! + */ + if (curr.isLoadingMore) { + return; } - componentWillUnmount() { - // if (!this.scrollBody) return; - // let node = this.scrollBody; - // if (node) { - // node.removeEventListener('scroll', this.handleScroll) - // } + /* + if the outer query is fetching more, there's no reason to re-check the scroll + position or re-attach a scroll listener - a refetch is already running! + */ + if ( + Array.isArray(prevProps.children) && + Array.isArray(curr.children) && + prevProps.children.length === curr.children.length + ) { + return; } - handleScroll = () => {}; + /* + There are edge cases where a fetchMore in the parent container can trigger + twice in a row instantly with the same cursor, causing 2 requests to the api + both returning the same results; this causes key errors and duplicates + items in lists. The following React.Children sections check to see if there + are matching children lengths. + + Hwever, in some cases like the dashboard inbox, there is only one child - + the FlipMove component. In this case, we need to make sure that this single + components children lengths match. - fetchMore = () => { - this.props.data.fetchMore(); - }; + Overall this is pretty hacky, but does solve the problem; the real solution + here which I'm unable to tackle right now (@brian) is to entirely make sure + that apollo never runs a fetchMore with the same cursor back to back. + */ + if ( + React.Children.toArray(curr.children).length === 1 && + React.Children.toArray(curr.children)[0].type.name === + 'FlipMovePropConverter' + ) { + const currFlipMoveChildren = React.Children.toArray(curr.children)[0] + .props.children; + const prevFlipMoveChildren = React.Children.toArray(prevProps.children)[0] + .props.children; - render() { - return ( - (this.scrollBody = scrollBody)} - {...this.props} - fetchMore={this.fetchMore} - /> - ); + if ( + Array.isArray(prevFlipMoveChildren) && + Array.isArray(currFlipMoveChildren) && + prevFlipMoveChildren.length === currFlipMoveChildren.length + ) { + return; + } } - }; -}; + + this.attachScrollListener(); + } + + render() { + const { + children, + element, + hasMore, + initialLoad, + loader, + loadMore, + pageStart, + threshold, + useWindow, + isReverse, + scrollElement, + isLoadingMore, + ...props + } = this.props; + + if (scrollElement) { + // $FlowFixMe + props.ref = node => { + this.scrollComponent = scrollElement; + }; + } else { + // $FlowFixMe + props.ref = node => { + this.scrollComponent = node; + }; + } + + return React.createElement( + element, + props, + children, + hasMore && (loader || this._defaultLoader) + ); + } + + calculateTopPosition(el: ?any) { + if (!el) { + return 0; + } + return el.offsetTop + this.calculateTopPosition(el.offsetParent); + } + + scrollListener() { + const el = this.scrollComponent; + const scrollEl = window; + + let offset; + if (this.props.scrollElement) { + if (this.props.isReverse) { + offset = el.scrollTop; + } else offset = el.scrollHeight - el.scrollTop - el.clientHeight; + } else if (this.props.useWindow) { + let scrollTop = + scrollEl.pageYOffset !== undefined + ? scrollEl.pageYOffset + : //$FlowFixMe + ( + document.documentElement || + //$FlowFixMe + document.body.parentNode || + document.body + ).scrollTop; + if (this.props.isReverse) offset = scrollTop; + else + offset = + this.calculateTopPosition(el) + + el.offsetHeight - + scrollTop - + window.innerHeight; + } else { + if (this.props.isReverse) offset = el.parentNode.scrollTop; + else + offset = + el.scrollHeight - + el.parentNode.scrollTop - + el.parentNode.clientHeight; + } + + if ( + offset < Number(this.props.threshold) || + fetchMoreOnInfiniteScrollLoad(el, this.props.className) + ) { + this.detachScrollListener(); + // Call loadMore after detachScrollListener to allow for non-async loadMore functions + if (typeof this.props.loadMore === 'function') { + this.props.loadMore((this.pageLoaded += 1)); + } + } + } + + attachScrollListener() { + if (!this.props.hasMore) { + return; + } + + let scrollEl = window; + if (this.props.scrollElement) { + scrollEl = this.scrollComponent; + } else if (this.props.useWindow === false) { + scrollEl = this.scrollComponent.parentNode; + } + + scrollEl.addEventListener('scroll', this.scrollListener); + scrollEl.addEventListener('resize', this.scrollListener); + + if (fetchMoreOnInfiniteScrollLoad(scrollEl, this.props.className)) { + this.props.loadMore((this.pageLoaded += 1)); + } + + if (this.props.initialLoad) { + this.scrollListener(); + } + } + + detachScrollListener() { + let scrollEl = window; + if (this.props.scrollElement) { + scrollEl = this.scrollComponent; + } else if (this.props.useWindow === false) { + scrollEl = this.scrollComponent.parentNode; + } + + scrollEl.removeEventListener('scroll', this.scrollListener); + scrollEl.removeEventListener('resize', this.scrollListener); + } + + componentWillUnmount() { + this.detachScrollListener(); + } + + // Set a defaut loader for all your `InfiniteScroll` components + setDefaultLoader(loader: React.Node) { + this._defaultLoader = loader; + } +} diff --git a/src/components/infiniteScroll/tallViewports.js b/src/components/infiniteScroll/tallViewports.js new file mode 100644 index 0000000000..77f2780c94 --- /dev/null +++ b/src/components/infiniteScroll/tallViewports.js @@ -0,0 +1,33 @@ +// @flow +export const fetchMoreOnInfiniteScrollLoad = ( + scrollElement: any, + infiniteScrollerClass: string +): boolean => { + if (!scrollElement) return false; + if (!window) return false; + if (!infiniteScrollerClass) return false; + + let infiniteScroller = null; + const nodes = document.getElementsByClassName(infiniteScrollerClass); + if (!nodes || nodes.length === 0) return false; + infiniteScroller = nodes[0]; + + const windowHeight = window.innerHeight; + + const scrollContainerHeight = scrollElement.clientHeight; + + const infiniteScrollHeight = infiniteScroller.clientHeight; + + if ( + infiniteScrollHeight > windowHeight || + infiniteScrollHeight > scrollContainerHeight + ) { + return false; + } + + if (scrollContainerHeight > infiniteScrollHeight) { + return true; + } + + return false; +}; diff --git a/src/components/loading/style.js b/src/components/loading/style.js index 6b2e48a7eb..dfb10c153f 100644 --- a/src/components/loading/style.js +++ b/src/components/loading/style.js @@ -7,15 +7,15 @@ import { hexa, FlexCol, zIndex } from '../globals'; import Link from 'src/components/link'; const containerFadeIn = keyframes` - 0%{ - opacity: 0; - } + 0%{ + opacity: 0; + } 99% { opacity: 0; } - 100%{ - opacity: 1 - } + 100%{ + opacity: 1 + } `; export const LoadingScreenContainer = styled.div` @@ -246,16 +246,16 @@ export const ShimmerSelect = styled.div` `; const placeHolderShimmer = keyframes` - 0%{ - transform: translateX(-100%) translateY(0%); - background-size: 100%; - opacity: 1; - } - 100%{ - transform: translateX(200%) translateY(0%); - background-size: 500%; - opacity: 0; - } + 0%{ + transform: translateX(-100%) translateY(0%); + background-size: 100%; + opacity: 1; + } + 100%{ + transform: translateX(200%) translateY(0%); + background-size: 500%; + opacity: 0; + } `; export const ShimmerBase = styled.section` diff --git a/src/components/message/style.js b/src/components/message/style.js index 2cfd3c45aa..cfc264af0b 100644 --- a/src/components/message/style.js +++ b/src/components/message/style.js @@ -1,6 +1,6 @@ // @flow import styled, { css } from 'styled-components'; -import { zIndex, Transition, monoStack, hexa } from '../globals'; +import { Gradient, zIndex, Transition, monoStack, hexa } from '../globals'; const Bubble = styled.div` display: inline-block; @@ -33,15 +33,16 @@ const Bubble = styled.div` code { border: 1px solid ${props => - props.me ? hexa(props.theme.bg.default, 0.2) : props.theme.bg.border}; + props.me + ? hexa(props.theme.brand.border, 0.5) + : props.theme.bg.default}; border-radius: 4px; - padding: 1px 4px; + padding: 2px 4px; background: ${props => - props.me - ? hexa(props.theme.bg.default, 0.1) - : hexa(props.theme.bg.default, 0.3)}; + props.me ? hexa(props.theme.brand.wash, 0.15) : props.theme.bg.border}; color: ${props => - props.me ? props.theme.text.reverse : props.theme.warn.alt}; + props.me ? props.theme.text.reverse : props.theme.text.default}; + box-shadow: 0 0 8px ${props => hexa(props.theme.bg.reverse, 0.1)}; } pre { @@ -50,13 +51,13 @@ const Bubble = styled.div` width: calc(100% + 32px); border: 1px solid ${props => - props.me ? hexa(props.theme.bg.default, 0.2) : props.theme.bg.border}; + props.me + ? hexa(props.theme.brand.border, 0.5) + : props.theme.bg.default}; border-left: 0; border-right: 0; background: ${props => - props.me - ? hexa(props.theme.bg.default, 0.1) - : hexa(props.theme.bg.default, 0.3)}; + props.me ? hexa(props.theme.brand.wash, 0.15) : props.theme.bg.border}; color: ${props => props.me ? props.theme.text.reverse : props.theme.text.default}; } @@ -244,6 +245,10 @@ export const Text = styled(Bubble)` line-height: 1.4; background-color: ${props => props.me ? props.theme.brand.default : props.theme.generic.default}; + background-image: ${props => + props.me + ? Gradient(props.theme.brand.alt, props.theme.brand.default) + : Gradient(props.theme.generic.alt, props.theme.generic.default)}; color: ${props => props.me ? props.theme.text.reverse : props.theme.text.default}; font-weight: ${props => (props.me ? `500` : `400`)}; diff --git a/src/components/rich-text-editor/toolbar.js b/src/components/rich-text-editor/toolbar.js index bdc47b005b..cb2d80e135 100644 --- a/src/components/rich-text-editor/toolbar.js +++ b/src/components/rich-text-editor/toolbar.js @@ -68,10 +68,19 @@ export default class Toolbar extends React.Component { return; } if (!editor || typeof editor.getBoundingClientRect !== 'function') return; + const topPosition = top + scrollY; + const leftPosition = editor.getBoundingClientRect().left - 48; + // If the position hasn't changed, don't re-render + if ( + this.state.position && + topPosition === this.state.position.top && + leftPosition === this.state.position.left + ) + return; this.setState({ position: { - top: top + scrollY, - left: editor.getBoundingClientRect().left - 48, + top: topPosition, + left: leftPosition, }, }); }, 0); diff --git a/src/components/threadFeed/index.js b/src/components/threadFeed/index.js index 763786b354..2831d9bea1 100644 --- a/src/components/threadFeed/index.js +++ b/src/components/threadFeed/index.js @@ -1,11 +1,10 @@ -import React, { Component } from 'react'; -//$FlowFixMe +// @flow +import * as React from 'react'; import styled from 'styled-components'; -//$FlowFixMe import compose from 'recompose/compose'; // NOTE(@mxstbr): This is a custom fork published of off this (as of this writing) unmerged PR: https://github.com/CassetteRocks/react-infinite-scroller/pull/38 // I literally took it, renamed the package.json and published to add support for scrollElement since our scrollable container is further outside -import InfiniteList from 'react-infinite-scroller-with-scroll-element'; +import InfiniteList from 'src/components/infiniteScroll'; import { connect } from 'react-redux'; import Link from 'src/components/link'; import Icon from 'src/components/icons'; @@ -15,6 +14,7 @@ import { LoadingInboxThread } from '../loading'; import NewActivityIndicator from '../newActivityIndicator'; import ViewError from '../viewError'; import { Upsell, UpsellHeader, UpsellFooter } from './style'; +import type { GetCommunityType } from 'shared/graphql/queries/community/getCommunity'; const NullState = ({ viewContext, search }) => { let hd; @@ -43,14 +43,11 @@ const NullState = ({ viewContext, search }) => { return ; }; -const UpsellState = ({ community, user }) => ( +const UpsellState = ({ community }) => ( -

- Welcome to your new community,{' '} - {user.firstName ? user.firstName : `@${user.username}`}! -

+

Welcome to your new community!

You've already taken a huge step, but there's one problem - there's no one @@ -113,26 +110,41 @@ const Threads = styled.div` } `; -/* - The thread feed always expects a prop of 'threads' - this means that in - the Apollo query contructor, you will need to map a new prop called 'threads' - to return whatever threads we're fetching (community -> threadsConnection) - - See 'views/community/queries.js' for an example of the prop mapping in action -*/ -class ThreadFeedPure extends Component { - state: { - scrollElement: any, - subscription: ?Function, - }; +type Props = { + data: { + subscribeToUpdatedThreads: Function, + fetchMore: Function, + networkStatus: number, + hasNextPage: boolean, + error: ?Object, + community?: any, + channel?: any, + threads?: Array, + }, + community: GetCommunityType, + setThreadsStatus: Function, + hasThreads: Function, + hasNoThreads: Function, + currentUser: ?Object, + viewContext: 'community' | 'channel', + slug: string, + pinnedThreadId: ?string, + isNewAndOwned: ?boolean, + newActivityIndicator: ?boolean, + dispatch: Function, + search?: boolean, +}; - constructor() { - super(); - this.state = { - scrollElement: null, - subscription: null, - }; - } +type State = { + scrollElement: any, + subscription: ?Function, +}; + +class ThreadFeedPure extends React.Component { + state = { + scrollElement: null, + subscription: null, + }; subscribe = () => { this.setState({ @@ -163,31 +175,36 @@ class ThreadFeedPure extends Component { } componentDidMount() { + const scrollElement = document.getElementById('scroller-for-thread-feed'); + this.setState({ // NOTE(@mxstbr): This is super un-reacty but it works. This refers to // the AppViewWrapper which is the scrolling part of the site. - scrollElement: document.getElementById('scroller-for-thread-feed'), + scrollElement, }); + this.subscribe(); } componentDidUpdate(prevProps) { + const curr = this.props; + if ( !prevProps.data.thread && - this.props.data.threads && - this.props.data.threads.length === 0 + curr.data.threads && + curr.data.threads.length === 0 ) { // if there are no threads, tell the parent container so that we can render upsells to community owners in the parent container - if (this.props.setThreadsStatus) { - this.props.setThreadsStatus(); + if (curr.setThreadsStatus) { + curr.setThreadsStatus(); } - if (this.props.hasThreads) { - this.props.hasThreads(); + if (curr.hasThreads) { + curr.hasThreads(); } - if (this.props.hasNoThreads) { - this.props.hasNoThreads(); + if (curr.hasNoThreads) { + curr.hasNoThreads(); } } } @@ -195,7 +212,6 @@ class ThreadFeedPure extends Component { render() { const { data: { threads, networkStatus, error }, - currentUser, viewContext, newActivityIndicator, } = this.props; @@ -203,16 +219,17 @@ class ThreadFeedPure extends Component { const { scrollElement } = this.state; const dataExists = threads && threads.length > 0; - const threadNodes = dataExists - ? threads - .slice() - .map(thread => thread.node) - .filter( - thread => - !thread.channel.channelPermissions.isBlocked && - !thread.community.communityPermissions.isBlocked - ) - : []; + const threadNodes = + threads && threads.length > 0 + ? threads + .slice() + .map(thread => thread.node) + .filter( + thread => + !thread.channel.channelPermissions.isBlocked && + !thread.community.communityPermissions.isBlocked + ) + : []; let filteredThreads = threadNodes; if ( @@ -221,6 +238,7 @@ class ThreadFeedPure extends Component { this.props.data.community.watercooler.id ) { filteredThreads = filteredThreads.filter( + // $FlowIssue t => t.id !== this.props.data.community.watercooler.id ); } @@ -230,6 +248,7 @@ class ThreadFeedPure extends Component { this.props.data.community.pinnedThread.id ) { filteredThreads = filteredThreads.filter( + // $FlowIssue t => t.id !== this.props.data.community.pinnedThread.id ); } @@ -273,12 +292,14 @@ class ThreadFeedPure extends Component { } useWindow={false} initialLoad={false} scrollElement={scrollElement} threshold={750} + className={'threadfeed-infinite-scroll-div'} > {uniqueThreads.map(thread => { return ( @@ -330,9 +351,7 @@ class ThreadFeedPure extends Component { } if (this.props.isNewAndOwned) { - return ( - - ); + return ; } else { return ; } @@ -343,6 +362,9 @@ const map = state => ({ currentUser: state.users.currentUser, newActivityIndicator: state.newActivityIndicator.hasNew, }); -const ThreadFeed = compose(connect(map))(ThreadFeedPure); +const ThreadFeed = compose( + // $FlowIssue + connect(map) +)(ThreadFeedPure); export default ThreadFeed; diff --git a/src/components/toasts/index.js b/src/components/toasts/index.js index 9a70bb3b99..75c6cc0207 100644 --- a/src/components/toasts/index.js +++ b/src/components/toasts/index.js @@ -14,9 +14,13 @@ const ToastsPure = ({ toasts }): React$Element => { const { kind, timeout, message, id } = toast; switch (kind) { case 'error': { + let cleanedMessage = message; + if (message.indexOf('GraphQL error: ') >= 0) { + cleanedMessage = message.replace('GraphQL error: ', ''); + } return ( - {message} + {cleanedMessage} ); } diff --git a/src/components/toggleCommunityMembership/index.js b/src/components/toggleCommunityMembership/index.js index dadae4c541..9a24d7f631 100644 --- a/src/components/toggleCommunityMembership/index.js +++ b/src/components/toggleCommunityMembership/index.js @@ -95,7 +95,7 @@ class ToggleCommunityMembership extends React.Component { render() { return ( -

+
{this.props.render(this.state)}
); diff --git a/src/components/upsell/newUserUpsell.js b/src/components/upsell/newUserUpsell.js index ef8e12865e..ebdaba0030 100644 --- a/src/components/upsell/newUserUpsell.js +++ b/src/components/upsell/newUserUpsell.js @@ -168,7 +168,7 @@ class UpsellNewUser extends Component { icon="facebook" gradientTheme={'none'} color={'social.facebook.default'} - onClick={() => this.clickShareLink('twitter')} + onClick={() => this.clickShareLink('facebook')} > Share on Facebook diff --git a/src/views/channel/index.js b/src/views/channel/index.js index cd26f756ec..4b16f70cc1 100644 --- a/src/views/channel/index.js +++ b/src/views/channel/index.js @@ -99,8 +99,12 @@ class ChannelView extends React.Component { isMember: isChannelMember, } = channel.channelPermissions; const { communityPermissions } = channel.community; - const { isOwner: isCommunityOwner } = communityPermissions; + const { + isOwner: isCommunityOwner, + isModerator: isCommunityModerator, + } = communityPermissions; const isGlobalOwner = isChannelOwner || isCommunityOwner; + const isGlobalModerator = isCommunityModerator; const loginUrl = channel.community.brandedLogin.isEnabled ? `/${channel.community.slug}/login?r=${CLIENT_URL}/${ @@ -137,6 +141,36 @@ class ChannelView extends React.Component { ); } + if (isGlobalModerator) { + return ( + + ( + + {isChannelMember ? 'Joined' : `Join ${channel.name}`} + + )} + /> + + + + Settings + + + + ); + } + // otherwise prompt a join return ( { @@ -79,6 +80,7 @@ class CommunityMemberGrid extends React.Component { initialLoad={false} scrollElement={scrollElement} threshold={750} + className={'scroller-for-community-members-list'} > {nodes.map(node => { if (!node) return null; diff --git a/src/views/community/style.js b/src/views/community/style.js index e448b4158a..0ced8db779 100644 --- a/src/views/community/style.js +++ b/src/views/community/style.js @@ -232,6 +232,11 @@ export const ColumnHeading = styled.div` export const ChannelListItemRow = styled.div` display: flex; + + a { + display: flex; + flex: auto; + } `; export const ToggleNotificationsContainer = styled.div` diff --git a/src/views/communitySettings/components/brandedLogin.js b/src/views/communitySettings/components/brandedLogin.js index 7200be9a74..d84b7619d7 100644 --- a/src/views/communitySettings/components/brandedLogin.js +++ b/src/views/communitySettings/components/brandedLogin.js @@ -86,7 +86,7 @@ class BrandedLogin extends React.Component { }) .catch(err => { this.setState({ messageLengthError: false, isLoading: false }); - return this.props.dispatch(addToastWithTimeout('error', err)); + return this.props.dispatch(addToastWithTimeout('error', err.message)); }); }; @@ -130,7 +130,7 @@ class BrandedLogin extends React.Component { }} > diff --git a/src/views/communitySettings/components/editForm.js b/src/views/communitySettings/components/editForm.js index 4d550708ba..8faad23eb4 100644 --- a/src/views/communitySettings/components/editForm.js +++ b/src/views/communitySettings/components/editForm.js @@ -231,7 +231,6 @@ class EditForm extends React.Component { this.props.dispatch( addToastWithTimeout('success', 'Community saved!') ); - window.location.href = `/${this.props.community.slug}`; } return; }) @@ -240,7 +239,7 @@ class EditForm extends React.Component { isLoading: false, }); - this.props.dispatch(addToastWithTimeout('error', err)); + this.props.dispatch(addToastWithTimeout('error', err.message)); }); }; diff --git a/src/views/dashboard/components/threadFeed.js b/src/views/dashboard/components/threadFeed.js index fa7283a187..450d0b685f 100644 --- a/src/views/dashboard/components/threadFeed.js +++ b/src/views/dashboard/components/threadFeed.js @@ -5,7 +5,7 @@ import { withRouter } from 'react-router'; import { connect } from 'react-redux'; // NOTE(@mxstbr): This is a custom fork published of off this (as of this writing) unmerged PR: https://github.com/CassetteRocks/react-infinite-scroller/pull/38 // I literally took it, renamed the package.json and published to add support for scrollElement since our scrollable container is further outside -import InfiniteList from 'react-infinite-scroller-with-scroll-element'; +import InfiniteList from 'src/components/infiniteScroll'; import FlipMove from 'react-flip-move'; import { sortByDate } from '../../../helpers/utils'; import { LoadingInboxThread } from '../../../components/loading'; @@ -93,7 +93,7 @@ class ThreadFeed extends React.Component { componentDidUpdate(prevProps) { const isDesktop = window.innerWidth > 768; const { scrollElement } = this.state; - const { mountedWithActiveThread, isFetchingMore, queryString } = this.props; + const { mountedWithActiveThread, queryString } = this.props; // user is searching, don't select anything if (queryString) { @@ -109,23 +109,6 @@ class ThreadFeed extends React.Component { return; } - if ( - // a thread has been selected - ((!prevProps.selectedId && this.props.selectedId) || - prevProps.selectedId !== this.props.selectedId || - prevProps.activeCommunity !== this.props.activeCommunity) && - // elems exist - this.innerScrollElement && - scrollElement && - // the threads height is less than the container scroll area - this.innerScrollElement.offsetHeight < scrollElement.offsetHeight && - // the component isn't currently fetching more - !isFetchingMore - ) { - this.props.data.hasNextPage && this.props.data.fetchMore(); - return; - } - // don't select a thread if the composer is open if (prevProps.selectedId === 'new') return; @@ -202,11 +185,14 @@ class ThreadFeed extends React.Component { } componentDidMount() { + const scrollElement = document.getElementById('scroller-for-inbox'); + this.setState({ // NOTE(@mxstbr): This is super un-reacty but it works. This refers to // the AppViewWrapper which is the scrolling part of the site. - scrollElement: document.getElementById('scroller-for-inbox'), + scrollElement, }); + this.subscribe(); } @@ -305,12 +291,14 @@ class ThreadFeed extends React.Component { } useWindow={false} initialLoad={false} scrollElement={scrollElement} threshold={750} + className={'scroller-for-dashboard-threads'} > {uniqueThreads.map(thread => { diff --git a/src/views/directMessages/components/threadsList.js b/src/views/directMessages/components/threadsList.js index 6d6935b112..0a42a3e864 100644 --- a/src/views/directMessages/components/threadsList.js +++ b/src/views/directMessages/components/threadsList.js @@ -1,16 +1,18 @@ // @flow import * as React from 'react'; import ListCardItemDirectMessageThread from './messageThreadListItem'; -import InfiniteList from 'react-infinite-scroller-with-scroll-element'; -import { LoadingDM } from '../../../components/loading'; +import InfiniteList from 'src/components/infiniteScroll'; +import { LoadingDM } from 'src/components/loading'; import { ThreadsListScrollContainer } from './style'; type Props = { - threads: ?Array, + threads: Array, currentUser: ?Object, active: string, fetchMore: Function, hasNextPage: boolean, + isFetchingMore: boolean, + isLoading: boolean, }; type State = { @@ -23,17 +25,44 @@ class ThreadsList extends React.Component { }; componentDidMount() { + const scrollElement = document.getElementById('scroller-for-dm-threads'); this.setState({ // NOTE(@mxstbr): This is super un-reacty but it works. This refers to // the AppViewWrapper which is the scrolling part of the site. - scrollElement: document.getElementById('scroller-for-dm-threads'), + scrollElement, }); } render() { - const { threads, currentUser, active, fetchMore, hasNextPage } = this.props; + const { + threads, + currentUser, + active, + fetchMore, + hasNextPage, + isLoading, + isFetchingMore, + } = this.props; const { scrollElement } = this.state; + if (isLoading) { + return ( +
+ + + + + + + + + + + +
+ ); + } + if (!threads || threads.length === 0) { return null; } @@ -43,12 +72,14 @@ class ThreadsList extends React.Component { } useWindow={false} initialLoad={false} scrollElement={scrollElement} threshold={30} + className={'scroller-for-community-dm-threads-list'} > {threads.map(thread => { if (!thread) return null; diff --git a/src/views/directMessages/containers/existingThread.js b/src/views/directMessages/containers/existingThread.js index 729dd898a4..98780ceefc 100644 --- a/src/views/directMessages/containers/existingThread.js +++ b/src/views/directMessages/containers/existingThread.js @@ -53,6 +53,14 @@ class ExistingThread extends React.Component { ) { this.chatInput.triggerFocus(); } + // as soon as the direct message thread is loaded, refocus the chat input + if ( + this.props.data.directMessageThread && + !prevProps.data.directMessageThread && + this.chatInput + ) { + this.chatInput.triggerFocus(); + } if (prevProps.match.params.threadId !== this.props.match.params.threadId) { const threadId = this.props.match.params.threadId; this.props.setActiveThread(threadId); diff --git a/src/views/directMessages/index.js b/src/views/directMessages/index.js index 890dff64ac..9dfccc01fe 100644 --- a/src/views/directMessages/index.js +++ b/src/views/directMessages/index.js @@ -12,7 +12,6 @@ import NewThread from './containers/newThread'; import ExistingThread from './containers/existingThread'; import viewNetworkHandler from '../../components/viewNetworkHandler'; import ViewError from '../../components/viewError'; -import { LoadingDM } from '../../components/loading'; import Titlebar from '../titlebar'; import { View, MessagesList, ComposeHeader } from './style'; @@ -23,6 +22,8 @@ type Props = { match: Object, currentUser?: Object, hasError: boolean, + isFetchingMore: boolean, + isLoading: boolean, fetchMore: Function, data: { user: GetCurrentUserDMThreadConnectionType, @@ -57,14 +58,6 @@ class DirectMessages extends React.Component { } }; - shouldComponentUpdate(nextProps) { - const curr = this.props; - // fetching more - if (curr.data.networkStatus === 7 && nextProps.data.networkStatus === 3) - return false; - return true; - } - componentDidMount() { this.props.markDirectMessageNotificationsSeen(); this.subscribe(); @@ -81,7 +74,15 @@ class DirectMessages extends React.Component { }; render() { - const { match, currentUser, data, hasError, fetchMore } = this.props; + const { + match, + currentUser, + data, + hasError, + fetchMore, + isFetchingMore, + isLoading, + } = this.props; // Only logged-in users can view DM threads if (!currentUser) return null; @@ -109,7 +110,7 @@ class DirectMessages extends React.Component { const val = parseInt(y, 10) - parseInt(x, 10); return val; }) - : null; + : []; if (hasError) return ; @@ -135,29 +136,15 @@ class DirectMessages extends React.Component { - {dataExists ? ( - - ) : ( -
- - - - - - - - - - - -
- )} + {dataExists && ( diff --git a/src/views/login/style.js b/src/views/login/style.js index d5fdc978cc..78f990df2a 100644 --- a/src/views/login/style.js +++ b/src/views/login/style.js @@ -161,14 +161,6 @@ export const Profile = styled.div` } `; -export const LargeEmoji = styled.div` - display: flex; - text-align: center; - flex 1; - padding: 16px 0 32px; - font-size: 48px; -`; - export const UpsellIconContainer = styled.div` display: flex; align-items: center; diff --git a/src/views/notifications/index.js b/src/views/notifications/index.js index 7d48d8b934..6dca10bd8f 100644 --- a/src/views/notifications/index.js +++ b/src/views/notifications/index.js @@ -4,8 +4,7 @@ import compose from 'recompose/compose'; import { connect } from 'react-redux'; // NOTE(@mxstbr): This is a custom fork published of off this (as of this writing) unmerged PR: https://github.com/CassetteRocks/react-infinite-scroller/pull/38 // I literally took it, renamed the package.json and published to add support for scrollElement since our scrollable container is further outside -import InfiniteList from 'react-infinite-scroller-with-scroll-element'; -import { withInfiniteScroll } from '../../components/infiniteScroll'; +import InfiniteList from 'src/components/infiniteScroll'; import { parseNotification, getDistinctNotifications } from './utils'; import { NewMessageNotification } from './components/newMessageNotification'; import { NewReactionNotification } from './components/newReactionNotification'; @@ -37,12 +36,14 @@ import { UpsellSignIn, UpsellNullNotifications } from '../../components/upsell'; import ViewError from '../../components/viewError'; import BrowserNotificationRequest from './components/browserNotificationRequest'; import generateMetaInfo from 'shared/generate-meta-info'; +import viewNetworkHandler from '../../components/viewNetworkHandler'; type Props = { markAllNotificationsSeen?: Function, subscribeToWebPush: Function, dispatch: Function, currentUser: Object, + isFetchingMore: boolean, data: { networkStatus: number, fetchMore: Function, @@ -77,11 +78,12 @@ class NotificationsPure extends React.Component { }; componentDidMount() { + const scrollElement = document.getElementById('scroller-for-thread-feed'); this.markAllNotificationsSeen(); this.setState({ // NOTE(@mxstbr): This is super un-reacty but it works. This refers to // the AppViewWrapper which is the scrolling part of the site. - scrollElement: document.getElementById('scroller-for-thread-feed'), + scrollElement, }); WebPushManager.getPermissionState() @@ -220,12 +222,14 @@ class NotificationsPure extends React.Component { } useWindow={false} initialLoad={false} scrollElement={scrollElement} threshold={750} + className={'scroller-for-notifications'} > {notifications.map(notification => { switch (notification.event) { @@ -343,5 +347,5 @@ export default compose( markNotificationsSeenMutation, // $FlowIssue connect(mapStateToProps), - withInfiniteScroll + viewNetworkHandler )(NotificationsPure); diff --git a/src/views/thread/components/messages.js b/src/views/thread/components/messages.js index 53afbb2314..2abaa762fa 100644 --- a/src/views/thread/components/messages.js +++ b/src/views/thread/components/messages.js @@ -2,7 +2,7 @@ import * as React from 'react'; import compose from 'recompose/compose'; import { withRouter } from 'react-router'; -import InfiniteList from 'react-infinite-scroller-with-scroll-element'; +import InfiniteList from 'src/components/infiniteScroll'; import { sortAndGroupMessages } from 'shared/clients/group-messages'; import ChatMessages from '../../../components/messageGroup'; import { LoadingChat } from '../../../components/loading'; @@ -215,12 +215,14 @@ class MessagesWithData extends React.Component { } useWindow={false} initialLoad={false} scrollElement={scrollContainer} threshold={750} + className={'scroller-for-messages'} > { ]; const subheading = { - to: `/users/${user.name}`, + to: `/users/${user.username}`, label: `Return to profile`, }; diff --git a/vulcan/package.json b/vulcan/package.json index 2148be0952..a206084174 100644 --- a/vulcan/package.json +++ b/vulcan/package.json @@ -5,14 +5,16 @@ "dependencies": { "algoliasearch": "^3.24.7", "debug": "^2.6.8", + "draft-js": "^0.10.3", "emoji-regex": "^6.1.1", "node-env-file": "^0.1.8", - "draft-js": "^0.10.3", + "now-env": "^3.0.1", "raven": "^2.1.1", + "rethinkdb-changefeed-reconnect": "^0.3.2", "rethinkdbdash": "^2.3.29", - "now-env": "^3.0.1", "source-map-support": "^0.4.15", - "stopword": "^0.1.9" + "stopword": "^0.1.9", + "toobusy-js": "^0.5.1" }, "devDependencies": { "json-stringify-pretty-compact": "^1.0.4" diff --git a/vulcan/yarn.lock b/vulcan/yarn.lock index 6105a76db6..61005214f3 100644 --- a/vulcan/yarn.lock +++ b/vulcan/yarn.lock @@ -30,6 +30,13 @@ asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" +babel-runtime@^6.18.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + "bluebird@>= 3.0.1": version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -42,6 +49,10 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" +core-js@^2.4.0: + version "2.5.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b" + debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -224,6 +235,16 @@ reduce@^1.0.1: dependencies: object-keys "~1.0.0" +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +rethinkdb-changefeed-reconnect@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/rethinkdb-changefeed-reconnect/-/rethinkdb-changefeed-reconnect-0.3.2.tgz#2999f5313205ab35d9ac2d1b0533765ee3376923" + dependencies: + babel-runtime "^6.18.0" + rethinkdbdash@^2.3.29: version "2.3.31" resolved "https://registry.yarnpkg.com/rethinkdbdash/-/rethinkdbdash-2.3.31.tgz#fe2f73d1fa6e6f5d96d8e881292013cf6dca914d" @@ -268,6 +289,10 @@ timed-out@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" +toobusy-js@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/toobusy-js/-/toobusy-js-0.5.1.tgz#5511f78f6a87a6a512d44fdb0efa13672217f659" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" diff --git a/yarn.lock b/yarn.lock index a3da97f298..6746b0f0f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2301,6 +2301,10 @@ camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" +camelize@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" @@ -2811,6 +2815,10 @@ content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" +content-security-policy-builder@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-2.0.0.tgz#8749a1d542fcbe82237281ea9f716ce68b394dd2" + content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -3290,6 +3298,10 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +dasherize@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" + data-urls@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.0.0.tgz#24802de4e81c298ea8a9388bb0d8e461c774684f" @@ -3556,6 +3568,10 @@ dns-packet@^1.3.1: ip "^1.1.0" safe-buffer "^5.0.1" +dns-prefetch-control@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" + dns-txt@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" @@ -3658,6 +3674,10 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" +dont-sniff-mimetype@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" + dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" @@ -4457,6 +4477,10 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" +expect-ct@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.1.0.tgz#52735678de18530890d8d7b95f0ac63640958094" + expect@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/expect/-/expect-22.4.3.tgz#d5a29d0a0e1fb2153557caef2674d4547e914674" @@ -4909,6 +4933,10 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +frameguard@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9" + fresh@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" @@ -5486,6 +5514,37 @@ he@1.1.x: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" +helmet-csp@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.7.0.tgz#7934094617d1feb7bb2dc43bb7d9e8830f774716" + dependencies: + camelize "1.0.0" + content-security-policy-builder "2.0.0" + dasherize "2.0.0" + lodash.reduce "4.6.0" + platform "1.3.5" + +helmet@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.12.0.tgz#2098e35cf4e51c64c2f1d38670b7d382a377d92c" + dependencies: + dns-prefetch-control "0.1.0" + dont-sniff-mimetype "1.0.0" + expect-ct "0.1.0" + frameguard "3.0.0" + helmet-csp "2.7.0" + hide-powered-by "1.0.0" + hpkp "2.0.0" + hsts "2.1.0" + ienoopen "1.0.0" + nocache "2.0.0" + referrer-policy "1.1.0" + x-xss-protection "1.1.0" + +hide-powered-by@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" + highlight.js@^9.10.0: version "9.12.0" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" @@ -5554,6 +5613,21 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" +hpkp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672" + +hpp@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/hpp/-/hpp-0.2.2.tgz#0ec5f77472049a74361d85ba2b88e2470a4356f8" + dependencies: + lodash "^4.7.0" + type-is "^1.6.12" + +hsts@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.1.0.tgz#cbd6c918a2385fee1dd5680bfb2b3a194c0121cc" + html-comment-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" @@ -5736,6 +5810,10 @@ ieee754@^1.1.4: version "1.1.11" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" +ienoopen@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b" + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -7217,7 +7295,7 @@ lodash.pick@^4.2.1, lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" -lodash.reduce@^4.4.0: +lodash.reduce@4.6.0, lodash.reduce@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" @@ -7266,7 +7344,7 @@ lodash@4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -lodash@4.17.5, "lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.1.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1: +lodash@4.17.5, "lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.1.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.7.0: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" @@ -7693,6 +7771,10 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" +nocache@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" + node-cleanup@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c" @@ -8437,6 +8519,10 @@ pkginfo@0.x.x: version "0.4.1" resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" +platform@1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444" + pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" @@ -9501,6 +9587,10 @@ redux@^3.6.0: loose-envify "^1.1.0" symbol-observable "^1.0.3" +referrer-policy@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79" + regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" @@ -10976,7 +11066,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@~1.6.15, type-is@~1.6.16: +type-is@^1.6.12, type-is@~1.6.15, type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: @@ -11739,6 +11829,10 @@ ws@^4.0.0: async-limiter "~1.0.0" safe-buffer "~5.1.0" +x-xss-protection@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.1.0.tgz#4f1898c332deb1e7f2be1280efb3e2c53d69c1a7" + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"